├── .mdlrc ├── tests ├── data │ ├── issue_fluent_bit_9267.txt │ ├── remote_write_dump_originally_from_node_exporter.bin │ ├── statsd_payload.txt │ ├── histogram_different_label_count.txt │ ├── issue_71.txt │ ├── issue_fluent_bit_5541.txt │ └── pr_168.txt ├── cmt_tests_config.h.in ├── encode_output.h ├── cmt_tests.h ├── CMakeLists.txt ├── util.c ├── encode_output.c ├── atomic_operations.c ├── untyped.c ├── issues.c ├── basic.c ├── gauge.c ├── summary.c ├── null_label.c ├── prometheus_lexer.c ├── histogram.c └── counter.c ├── cpack ├── description └── macos │ └── welcome.txt.cmakein ├── .gitignore ├── cmake ├── libraries.cmake ├── headers.cmake └── macros.cmake ├── scripts └── win_build.bat ├── .gitmodules ├── CODEOWNERS ├── include ├── cmetrics │ ├── cmt_atomic.h │ ├── cmt_time.h │ ├── cmt_info.h.in │ ├── cmt_encode_text.h │ ├── cmt_encode_influx.h │ ├── cmt_encode_prometheus.h │ ├── cmt_encode_msgpack.h │ ├── cmt_compat.h │ ├── cmt_label.h │ ├── cmt_version.h.in │ ├── cmt_opts.h │ ├── cmt_encode_splunk_hec.h │ ├── cmt_encode_cloudwatch_emf.h │ ├── cmt_mpack_utils_defs.h │ ├── cmt_cat.h │ ├── cmt_untyped.h │ ├── cmt_math.h │ ├── cmt_filter.h │ ├── cmt_encode_opentelemetry.h │ ├── cmt_decode_prometheus_remote_write.h │ ├── cmt_decode_opentelemetry.h │ ├── cmt_mpack_utils.h │ ├── cmt_counter.h │ ├── cmt_decode_statsd.h │ ├── cmt_gauge.h │ ├── cmt_encode_prometheus_remote_write.h │ ├── cmetrics.h │ ├── cmt_map.h │ ├── cmt_summary.h │ ├── cmt_log.h │ ├── cmt_decode_msgpack.h │ ├── cmt_histogram.h │ ├── cmt_metric.h │ └── cmt_decode_prometheus.h └── CMakeLists.txt ├── markdownlint.rb ├── .github ├── dependabot.yml ├── actionlint-matcher.json └── workflows │ ├── lint.yaml │ └── packages.yaml ├── create-submoduled-tarball.sh ├── README.md ├── lib └── mpack │ └── CMakeLists.txt ├── appveyor.yml └── src ├── cmt_time.c ├── cmt_atomic_clang.c ├── cmt_atomic_gcc.c ├── external ├── LICENSE └── opentelemetry_resource.pb-c.c ├── cmt_log.c ├── cmt_label.c ├── CMakeLists.txt ├── cmt_decode_prometheus.y ├── cmt_opts.c ├── cmt_atomic_generic.c ├── cmt_atomic_msvc.c ├── cmt_metric.c ├── cmetrics.c ├── cmt_untyped.c ├── cmt_decode_prometheus.l ├── cmt_metric_histogram.c ├── cmt_counter.c └── cmt_gauge.c /.mdlrc: -------------------------------------------------------------------------------- 1 | style "#{File.dirname(__FILE__)}/markdownlint.rb" -------------------------------------------------------------------------------- /tests/data/issue_fluent_bit_9267.txt: -------------------------------------------------------------------------------- 1 | _bu_nn 0 171798732 -------------------------------------------------------------------------------- /cpack/description: -------------------------------------------------------------------------------- 1 | A standalone library to create and manipulate metrics in C. 2 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *~ 2 | build/* 3 | include/cmetrics/cmt_info.h 4 | include/cmetrics/cmt_version.h 5 | LICENSE.txt 6 | README.html 7 | welcome.txt -------------------------------------------------------------------------------- /cmake/libraries.cmake: -------------------------------------------------------------------------------- 1 | # List of bundled libraries 2 | set(CMT_PATH_LIB_CFL "lib/cfl") 3 | set(CMT_PATH_LIB_FLUENT_OTEL_PROTO "lib/fluent-otel-proto") 4 | -------------------------------------------------------------------------------- /scripts/win_build.bat: -------------------------------------------------------------------------------- 1 | setlocal 2 | git submodule update --init --recursive 3 | cd build 4 | cmake -G "NMake Makefiles" -DCMT_TESTS=On ..\ 5 | cmake --build . 6 | endlocal 7 | -------------------------------------------------------------------------------- /tests/data/remote_write_dump_originally_from_node_exporter.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fluent/cmetrics/HEAD/tests/data/remote_write_dump_originally_from_node_exporter.bin -------------------------------------------------------------------------------- /cmake/headers.cmake: -------------------------------------------------------------------------------- 1 | include_directories(${PROJECT_SOURCE_DIR}/lib/fluent-otel-proto/include 2 | ${PROJECT_SOURCE_DIR}/lib/fluent-otel-proto/proto_c 3 | ${PROJECT_SOURCE_DIR}/lib/cfl/include 4 | ) 5 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "lib/cfl"] 2 | path = lib/cfl 3 | url = https://github.com/fluent/cfl 4 | [submodule "lib/fluent-otel-proto"] 5 | path = lib/fluent-otel-proto 6 | url = https://github.com/fluent/fluent-otel-proto 7 | -------------------------------------------------------------------------------- /CODEOWNERS: -------------------------------------------------------------------------------- 1 | # Global Owners 2 | # ------------- 3 | * @edsiper @leonardo-albertovich 4 | 5 | # CI 6 | # ------------------------- 7 | /.github/ @niedbalski @patrick-stephens @celalettin1286 8 | -------------------------------------------------------------------------------- /cpack/macos/welcome.txt.cmakein: -------------------------------------------------------------------------------- 1 | This will install @CPACK_PACKAGE_NAME@ on your Mac. 2 | 3 | -------------------------------------------------- 4 | 5 | Thank you for trying @CPACK_PACKAGE_NAME@! Have a fantastic day! 6 | 7 | You can use @CPACK_PACKAGE_NAME@ as metrics library on your system. 8 | -------------------------------------------------------------------------------- /cmake/macros.cmake: -------------------------------------------------------------------------------- 1 | # Macro to set definitions 2 | macro(CMT_DEFINITION var) 3 | add_definitions(-D${var}) 4 | set(CMT_BUILD_FLAGS "${CMT_BUILD_FLAGS}#ifndef ${var}\n#define ${var}\n#endif\n") 5 | set(CMT_INFO_FLAGS "${CMT_INFO_FLAGS} ${var}") 6 | endmacro() 7 | 8 | macro(CMT_OPTION option value) 9 | set(${option} ${value} CACHE INTERNAL "" FORCE) 10 | endmacro() 11 | -------------------------------------------------------------------------------- /include/cmetrics/cmt_atomic.h: -------------------------------------------------------------------------------- 1 | #ifndef CMT_ATOMIC_H 2 | #define CMT_ATOMIC_H 3 | 4 | #include 5 | 6 | int cmt_atomic_initialize(); 7 | int cmt_atomic_compare_exchange(uint64_t *storage, uint64_t old_value, uint64_t new_value); 8 | void cmt_atomic_store(uint64_t *storage, uint64_t new_value); 9 | uint64_t cmt_atomic_load(uint64_t *storage); 10 | 11 | #endif 12 | -------------------------------------------------------------------------------- /markdownlint.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/ruby 2 | 3 | # Enable all rules by default 4 | all 5 | 6 | # Extend line length, since each sentence should be on a separate line. 7 | rule 'MD013', :line_length => 99999, :ignore_code_blocks => true 8 | 9 | # Allow in-line HTML 10 | exclude_rule 'MD033' 11 | 12 | # Nested lists should be indented with two spaces. 13 | rule 'MD007', :indent => 2 14 | 15 | # Bash defaulting confuses this and now way to ignore code blocks 16 | exclude_rule 'MD029' 17 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | # To get started with Dependabot version updates, you'll need to specify which 2 | # package ecosystems to update and where the package manifests are located. 3 | # Please see the documentation for all configuration options: 4 | # https://help.github.com/github/administering-a-repository/configuration-options-for-dependency-updates 5 | 6 | version: 2 7 | updates: 8 | # Maintain dependencies for GitHub Actions 9 | - package-ecosystem: "github-actions" 10 | directory: "/" 11 | schedule: 12 | interval: "weekly" -------------------------------------------------------------------------------- /.github/actionlint-matcher.json: -------------------------------------------------------------------------------- 1 | { 2 | "problemMatcher": [ 3 | { 4 | "owner": "actionlint", 5 | "pattern": [ 6 | { 7 | "regexp": "^(?:\\x1b\\[\\d+m)?(.+?)(?:\\x1b\\[\\d+m)*:(?:\\x1b\\[\\d+m)*(\\d+)(?:\\x1b\\[\\d+m)*:(?:\\x1b\\[\\d+m)*(\\d+)(?:\\x1b\\[\\d+m)*: (?:\\x1b\\[\\d+m)*(.+?)(?:\\x1b\\[\\d+m)* \\[(.+?)\\]$", 8 | "file": 1, 9 | "line": 2, 10 | "column": 3, 11 | "message": 4, 12 | "code": 5 13 | } 14 | ] 15 | } 16 | ] 17 | } -------------------------------------------------------------------------------- /tests/data/statsd_payload.txt: -------------------------------------------------------------------------------- 1 | statsdTestMetric011:5000|g|#mykey:myvalue,mykey2:othervalue 2 | statsdTestMetric012:400|s|@0.125|#mykey:myvalue 3 | statsdTestMetric013:+500|g|#mykey:myvalue 4 | statsdTestMetric014:-400|g|#mykey:myvalue 5 | statsdTestMetric015:+2|g|#mykey:myvalue 6 | statsdTestMetric016:-1|g|@0.1|#mykey:myvalue 7 | statsdTestMetric021:365|g|#mykey:myvalue 8 | statsdTestMetric022:+300|c|#mykey:myvalue 9 | statsdTestMetric023:-200|s|#mykey:myvalue 10 | statsdTestMetric024:200|g|#mykey:myvalue 11 | expohisto:1|ms|#mykey:myvalue 12 | expohisto:0|ms|#mykey:myvalue 13 | expohisto:-1|ms|#mykey:myvalue 14 | -------------------------------------------------------------------------------- /create-submoduled-tarball.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | if [ -z "$1" ]; then 4 | echo "Specify archive name" 5 | exit 1 6 | fi 7 | 8 | OS=$(uname -s) 9 | 10 | echo "$OS" 11 | if [ "$OS" == "Darwin" ]; then 12 | echo "Using gtar for concatenate option" 13 | TAR=gtar 14 | else 15 | TAR=tar 16 | fi 17 | 18 | ROOT_ARCHIVE_NAME=$1 19 | 20 | git archive --prefix "$ROOT_ARCHIVE_NAME/" -o "$ROOT_ARCHIVE_NAME.tar" HEAD 21 | git submodule foreach --recursive "git archive --prefix=$ROOT_ARCHIVE_NAME/\$path/ --output=\$sha1.tar HEAD && $TAR --concatenate --file=$(pwd)/$ROOT_ARCHIVE_NAME.tar \$sha1.tar && rm \$sha1.tar" 22 | 23 | gzip "$ROOT_ARCHIVE_NAME.tar" 24 | -------------------------------------------------------------------------------- /tests/data/histogram_different_label_count.txt: -------------------------------------------------------------------------------- 1 | # HELP k8s_network_load Network load 2 | # TYPE k8s_network_load histogram 3 | k8s_network_load_bucket{le="0.05"} 0 0 4 | k8s_network_load_bucket{le="5.0"} 1 0 5 | k8s_network_load_bucket{le="10.0"} 2 0 6 | k8s_network_load_bucket{le="+Inf"} 3 0 7 | k8s_network_load_sum 1013 0 8 | k8s_network_load_count 3 0 9 | k8s_network_load_bucket{le="0.05",my_label="my_val"} 0 0 10 | k8s_network_load_bucket{le="5.0",my_label="my_val"} 1 0 11 | k8s_network_load_bucket{le="10.0",my_label="my_val"} 2 0 12 | k8s_network_load_bucket{le="+Inf",my_label="my_val"} 3 0 13 | k8s_network_load_sum{my_label="my_val"} 1013 0 14 | k8s_network_load_count{my_label="my_val"} 3 0 15 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # CMetrics 2 | 3 | > DISCLAIMER: THIS LIBRARY IS STILL IN ACTIVE DEVELOPMENT 4 | 5 | The [CMetrics](https://github.com/calyptia/cmetrics) project is a standalone C library to create and maintain a context of different sets of metrics with labels support such as: 6 | 7 | - Counters 8 | - Gauges 9 | - Histograms 10 | - Summaries 11 | 12 | This project is heavily based on Go Prometheus Client API design: 13 | 14 | - https://pkg.go.dev/github.com/prometheus/client_golang/prometheus#section-documentation 15 | 16 | ## License 17 | 18 | This program is under the terms of the [Apache License v2.0](http://www.apache.org/licenses/LICENSE-2.0). 19 | 20 | ## Authors 21 | 22 | [Calyptia Team](https://www.calyptia.com) 23 | -------------------------------------------------------------------------------- /.github/workflows/lint.yaml: -------------------------------------------------------------------------------- 1 | name: Lint PRs 2 | on: 3 | pull_request: 4 | workflow_dispatch: 5 | 6 | jobs: 7 | shellcheck: 8 | runs-on: ubuntu-latest 9 | name: Shellcheck 10 | permissions: 11 | contents: read 12 | steps: 13 | - uses: actions/checkout@v6 14 | - uses: ludeeus/action-shellcheck@master 15 | 16 | actionlint: 17 | runs-on: ubuntu-latest 18 | name: Actionlint 19 | permissions: 20 | contents: read 21 | steps: 22 | - uses: actions/checkout@v6 23 | - run: | 24 | echo "::add-matcher::.github/actionlint-matcher.json" 25 | bash <(curl https://raw.githubusercontent.com/rhysd/actionlint/main/scripts/download-actionlint.bash) 26 | ./actionlint -color -shellcheck= 27 | shell: bash 28 | 29 | -------------------------------------------------------------------------------- /tests/data/issue_71.txt: -------------------------------------------------------------------------------- 1 | # HELP node_power_supply_info info of /sys/class/power_supply/. 2 | # TYPE node_power_supply_info gauge 3 | node_power_supply_info{power_supply="AC",type="Mains"} 1 4 | node_power_supply_info{power_supply="ucsi-source-psy-USBC000:001",type="USB",usb_type="[C] PD PD_PPS"} 1 5 | node_power_supply_info{power_supply="ucsi-source-psy-USBC000:002",type="USB",usb_type="C [PD] PD_PPS"} 1 6 | node_power_supply_info{capacity_level="Normal",manufacturer="SMP",model_name="02DL005",power_supply="BAT0",serial_number="4195",status="Discharging",technology="Li-poly",type="Battery"} 1 7 | # HELP node_power_supply_online online value of /sys/class/power_supply/. 8 | # TYPE node_power_supply_online gauge 9 | node_power_supply_online{power_supply="AC"} 0 10 | node_power_supply_online{power_supply="ucsi-source-psy-USBC000:001"} 0 11 | node_power_supply_online{power_supply="ucsi-source-psy-USBC000:002"} 1 12 | -------------------------------------------------------------------------------- /tests/cmt_tests_config.h.in: -------------------------------------------------------------------------------- 1 | /* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ 2 | 3 | /* CMetrics 4 | * ======== 5 | * Copyright 2021-2022 The CMetrics Authors 6 | * 7 | * Licensed under the Apache License, Version 2.0 (the "License"); 8 | * you may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | */ 19 | 20 | #ifndef CMT_TESTS_CONFIG_H 21 | #define CMT_TESTS_CONFIG_H 22 | 23 | #define CMT_TESTS_DATA_PATH "@CMT_TESTS_DATA_PATH@" 24 | 25 | #endif 26 | -------------------------------------------------------------------------------- /include/cmetrics/cmt_time.h: -------------------------------------------------------------------------------- 1 | /* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ 2 | 3 | /* CMetrics 4 | * ======== 5 | * Copyright 2021-2022 The CMetrics Authors 6 | * 7 | * Licensed under the Apache License, Version 2.0 (the "License"); 8 | * you may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | */ 19 | 20 | #ifndef CMT_TIME_H 21 | #define CMT_TIME_H 22 | 23 | #include 24 | #include 25 | 26 | void cmt_time_from_ns(struct timespec *tm, uint64_t ns); 27 | 28 | #endif 29 | -------------------------------------------------------------------------------- /tests/encode_output.h: -------------------------------------------------------------------------------- 1 | /* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ 2 | 3 | /* CMetrics 4 | * ======== 5 | * Copyright 2021-2022 The CMetrics Authors 6 | * 7 | * Licensed under the Apache License, Version 2.0 (the "License"); 8 | * you may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | */ 19 | 20 | #ifndef CMT_TESTS_ENCODE_OUTPUT_H 21 | #define CMT_TESTS_ENCODE_OUTPUT_H 22 | 23 | #include 24 | 25 | int cmt_test_encode_all(struct cmt *cmt); 26 | 27 | #endif 28 | 29 | -------------------------------------------------------------------------------- /include/cmetrics/cmt_info.h.in: -------------------------------------------------------------------------------- 1 | /* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ 2 | 3 | /* CMetrics 4 | * ======== 5 | * Copyright 2021-2022 The CMetrics Authors 6 | * 7 | * Licensed under the Apache License, Version 2.0 (the "License"); 8 | * you may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | */ 19 | 20 | #ifndef CMT_INFO_H 21 | #define CMT_INFO_H 22 | 23 | #define CMT_SOURCE_DIR "@CMAKE_SOURCE_DIR@" 24 | 25 | /* General flags set by /CMakeLists.txt */ 26 | @CMT_BUILD_FLAGS@ 27 | 28 | #endif 29 | -------------------------------------------------------------------------------- /include/cmetrics/cmt_encode_text.h: -------------------------------------------------------------------------------- 1 | /* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ 2 | 3 | /* CMetrics 4 | * ======== 5 | * Copyright 2021-2022 The CMetrics Authors 6 | * 7 | * Licensed under the Apache License, Version 2.0 (the "License"); 8 | * you may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | */ 19 | 20 | 21 | #ifndef CMT_ENCODE_TEXT_H 22 | #define CMT_ENCODE_TEXT_H 23 | 24 | #include 25 | 26 | cfl_sds_t cmt_encode_text_create(struct cmt *cmt); 27 | void cmt_encode_text_destroy(cfl_sds_t text); 28 | 29 | #endif 30 | -------------------------------------------------------------------------------- /include/cmetrics/cmt_encode_influx.h: -------------------------------------------------------------------------------- 1 | /* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ 2 | 3 | /* CMetrics 4 | * ======== 5 | * Copyright 2021-2022 The CMetrics Authors 6 | * 7 | * Licensed under the Apache License, Version 2.0 (the "License"); 8 | * you may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | */ 19 | 20 | 21 | #ifndef CMT_ENCODE_INFLUX_H 22 | #define CMT_ENCODE_INFLUX_H 23 | 24 | #include 25 | 26 | cfl_sds_t cmt_encode_influx_create(struct cmt *cmt); 27 | void cmt_encode_influx_destroy(cfl_sds_t text); 28 | 29 | #endif 30 | -------------------------------------------------------------------------------- /lib/mpack/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | set(src 2 | src/mpack/mpack.c 3 | ) 4 | 5 | set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=c99") 6 | add_definitions(-DMPACK_EXTENSIONS=1) 7 | add_library(mpack-static STATIC ${src}) 8 | 9 | # Install Library 10 | if(MSVC) 11 | # Rename the output for Windows environment to avoid naming issues 12 | set_target_properties(mpack-static PROPERTIES OUTPUT_NAME libmpack) 13 | else() 14 | set_target_properties(mpack-static PROPERTIES OUTPUT_NAME mpack) 15 | endif(MSVC) 16 | 17 | # Installation Directories 18 | # ======================== 19 | if(${CMAKE_SYSTEM_NAME} MATCHES "Windows") 20 | set(MPACK_INSTALL_LIBDIR "lib") 21 | set(MPACK_INSTALL_INCLUDEDIR "include") 22 | else() 23 | set(MPACK_INSTALL_LIBDIR "${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_LIBDIR}") 24 | set(MPACK_INSTALL_INCLUDEDIR "${CMAKE_INSTALL_PREFIX}/include") 25 | endif() 26 | 27 | install(TARGETS mpack-static 28 | RUNTIME DESTINATION ${MPACK_INSTALL_BINDIR} 29 | LIBRARY DESTINATION ${MPACK_INSTALL_LIBDIR} 30 | ARCHIVE DESTINATION ${MPACK_INSTALL_LIBDIR} 31 | COMPONENT library) 32 | -------------------------------------------------------------------------------- /tests/data/issue_fluent_bit_5541.txt: -------------------------------------------------------------------------------- 1 | # HELP http_request_duration_seconds HTTP request latency (seconds) 2 | # TYPE http_request_duration_seconds histogram 3 | http_request_duration_seconds_bucket{le="0.005"} 2.0 4 | http_request_duration_seconds_bucket{le="0.01"} 2.0 5 | http_request_duration_seconds_bucket{le="0.025"} 2.0 6 | http_request_duration_seconds_bucket{le="0.05"} 2.0 7 | http_request_duration_seconds_bucket{le="0.075"} 2.0 8 | http_request_duration_seconds_bucket{le="0.1"} 2.0 9 | http_request_duration_seconds_bucket{le="0.25"} 2.0 10 | http_request_duration_seconds_bucket{le="0.5"} 2.0 11 | http_request_duration_seconds_bucket{le="0.75"} 2.0 12 | http_request_duration_seconds_bucket{le="1.0"} 2.0 13 | http_request_duration_seconds_bucket{le="2.5"} 2.0 14 | http_request_duration_seconds_bucket{le="5.0"} 2.0 15 | http_request_duration_seconds_bucket{le="7.5"} 2.0 16 | http_request_duration_seconds_bucket{le="10.0"} 2.0 17 | http_request_duration_seconds_bucket{le="+Inf"} 2.0 18 | http_request_duration_seconds_count 2.0 19 | http_request_duration_seconds_sum 0.0006913102697581053 20 | -------------------------------------------------------------------------------- /appveyor.yml: -------------------------------------------------------------------------------- 1 | version: v1-winbuild-{build} 2 | 3 | image: Visual Studio 2019 4 | 5 | platform: 6 | - Win32 7 | - x64 8 | 9 | environment: 10 | vspath: 'C:\Program Files (x86)\Microsoft Visual Studio\2019\Community' 11 | winflexbison: https://github.com/lexxmark/winflexbison/releases/download/v2.5.22/win_flex_bison-2.5.22.zip 12 | PATH: '%PATH%;C:\WinFlexBison' 13 | 14 | configuration: 15 | - Release 16 | 17 | skip_commits: 18 | message: /workflows/ 19 | files: 20 | - '.github/**' 21 | 22 | install: 23 | - ps: Invoke-WebRequest -O winflexbison.zip $env:winflexbison 24 | - ps: Expand-Archive winflexbison.zip -Destination /WinFlexBison 25 | - ps: Copy-Item -Path /WinFlexBison/win_bison.exe /WinFlexBison/bison.exe 26 | - ps: Copy-Item -Path /WinFlexBison/win_flex.exe /WinFlexBison/flex.exe 27 | 28 | before_build: 29 | - if %PLATFORM%==Win32 call "%vspath%\VC\Auxiliary\Build\vcvars32.bat" 30 | - if %PLATFORM%==x64 call "%vspatH%\VC\Auxiliary\Build\vcvars64.bat" 31 | 32 | build_script: 33 | - .\scripts\win_build.bat 34 | - ctest -C Debug --test-dir .\tests\ 35 | -------------------------------------------------------------------------------- /include/cmetrics/cmt_encode_prometheus.h: -------------------------------------------------------------------------------- 1 | /* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ 2 | 3 | /* CMetrics 4 | * ======== 5 | * Copyright 2021-2022 The CMetrics Authors 6 | * 7 | * Licensed under the Apache License, Version 2.0 (the "License"); 8 | * you may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | */ 19 | 20 | 21 | #ifndef CMT_ENCODE_PROMETHEUS_H 22 | #define CMT_ENCODE_PROMETHEUS_H 23 | 24 | #include 25 | 26 | cfl_sds_t cmt_encode_prometheus_create(struct cmt *cmt, int add_timestamp); 27 | void cmt_encode_prometheus_destroy(cfl_sds_t text); 28 | 29 | #endif 30 | -------------------------------------------------------------------------------- /include/cmetrics/cmt_encode_msgpack.h: -------------------------------------------------------------------------------- 1 | /* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ 2 | 3 | /* CMetrics 4 | * ======== 5 | * Copyright 2021-2022 The CMetrics Authors 6 | * 7 | * Licensed under the Apache License, Version 2.0 (the "License"); 8 | * you may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | */ 19 | 20 | 21 | #ifndef CMT_ENCODE_MSGPACK_H 22 | #define CMT_ENCODE_MSGPACK_H 23 | 24 | #include 25 | 26 | #define MSGPACK_ENCODER_VERSION 2 27 | 28 | int cmt_encode_msgpack_create(struct cmt *cmt, char **out_buf, size_t *out_size); 29 | void cmt_encode_msgpack_destroy(char *out_buf); 30 | 31 | #endif 32 | -------------------------------------------------------------------------------- /src/cmt_time.c: -------------------------------------------------------------------------------- 1 | /* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ 2 | 3 | /* CMetrics 4 | * ======== 5 | * Copyright 2021-2022 The CMetrics Authors 6 | * 7 | * Licensed under the Apache License, Version 2.0 (the "License"); 8 | * you may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | */ 19 | 20 | #include 21 | #include 22 | #include 23 | 24 | void cmt_time_from_ns(struct timespec *tm, uint64_t ns) 25 | { 26 | if (ns < 1000000000L) { 27 | tm->tv_sec = 0; 28 | tm->tv_nsec = ns; 29 | } 30 | else { 31 | tm->tv_sec = ns / 1000000000L; 32 | tm->tv_nsec = ns - (tm->tv_sec * 1000000000L); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /tests/cmt_tests.h: -------------------------------------------------------------------------------- 1 | /* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ 2 | 3 | /* CMetrics 4 | * ======== 5 | * Copyright 2021-2022 The CMetrics Authors 6 | * 7 | * Licensed under the Apache License, Version 2.0 (the "License"); 8 | * you may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | */ 19 | 20 | #ifndef CMT_TESTS_H 21 | #define CMT_TESTS_H 22 | 23 | #include "lib/acutest/acutest.h" 24 | 25 | #define MSGPACK_STABILITY_TEST_ITERATION_COUNT 1000 26 | #define MSGPACK_PARTIAL_PROCESSING_ELEMENT_COUNT 20 27 | 28 | #include "tests/cmt_tests_config.h" 29 | #include "encode_output.h" 30 | 31 | #include 32 | 33 | cfl_sds_t read_file(const char *path); 34 | 35 | #endif 36 | -------------------------------------------------------------------------------- /include/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Install headers conditionally based on Prometheus text decoder availability 2 | file(GLOB cmetricsHeaders "cmetrics/*.h") 3 | 4 | if(CMT_BUILD_PROMETHEUS_TEXT_DECODER) 5 | # Install all headers when Prometheus text decoder is enabled 6 | install(FILES ${cmetricsHeaders} 7 | DESTINATION ${CMT_INSTALL_INCLUDEDIR}/cmetrics 8 | COMPONENT headers 9 | PERMISSIONS OWNER_READ OWNER_WRITE GROUP_READ WORLD_READ) 10 | else() 11 | # Install headers except Prometheus text decoder header when disabled 12 | # (remote write decoder header is always installed) 13 | foreach(header ${cmetricsHeaders}) 14 | get_filename_component(header_name ${header} NAME) 15 | if(NOT header_name STREQUAL "cmt_decode_prometheus.h") 16 | install(FILES ${header} 17 | DESTINATION ${CMT_INSTALL_INCLUDEDIR}/cmetrics 18 | COMPONENT headers 19 | PERMISSIONS OWNER_READ OWNER_WRITE GROUP_READ WORLD_READ) 20 | endif() 21 | endforeach() 22 | endif() 23 | 24 | file(GLOB promHeaders "prometheus_remote_write/*.h") 25 | install(FILES ${promHeaders} 26 | DESTINATION ${CMT_INSTALL_INCLUDEDIR}/prometheus_remote_write 27 | COMPONENT headers 28 | PERMISSIONS OWNER_READ OWNER_WRITE GROUP_READ WORLD_READ) 29 | -------------------------------------------------------------------------------- /include/cmetrics/cmt_compat.h: -------------------------------------------------------------------------------- 1 | /* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ 2 | 3 | /* CMetrics 4 | * ======== 5 | * Copyright 2021-2022 The CMetrics Authors 6 | * 7 | * Licensed under the Apache License, Version 2.0 (the "License"); 8 | * you may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | */ 19 | 20 | #ifndef CMT_COMPAT_H 21 | #define CMT_COMPAT_H 22 | 23 | #include 24 | #ifdef _WIN32 25 | #include 26 | #endif 27 | 28 | static inline struct tm *cmt_platform_gmtime_r(const time_t *timep, struct tm *result) 29 | { 30 | #ifdef CMT_HAVE_GMTIME_S 31 | if (gmtime_s(result, timep)) { 32 | return NULL; 33 | } 34 | 35 | return result; 36 | #else 37 | /* FIXME: Need to handle gmtime_r(3) lacking platform? */ 38 | return gmtime_r(timep, result) ; 39 | #endif 40 | } 41 | 42 | #endif 43 | -------------------------------------------------------------------------------- /include/cmetrics/cmt_label.h: -------------------------------------------------------------------------------- 1 | /* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ 2 | 3 | /* CMetrics 4 | * ======== 5 | * Copyright 2021-2022 The CMetrics Authors 6 | * 7 | * Licensed under the Apache License, Version 2.0 (the "License"); 8 | * you may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | */ 19 | 20 | #ifndef CMT_LABEL_H 21 | #define CMT_LABEL_H 22 | 23 | #include 24 | 25 | struct cmt_label { 26 | cfl_sds_t key; /* Label key */ 27 | cfl_sds_t val; /* Label value */ 28 | struct cfl_list _head; /* Link to list cmt_labels->list */ 29 | }; 30 | 31 | struct cmt_labels { 32 | struct cfl_list list; 33 | }; 34 | 35 | struct cmt_labels *cmt_labels_create(); 36 | void cmt_labels_destroy(struct cmt_labels *labels); 37 | int cmt_labels_add_kv(struct cmt_labels *labels, char *key, char *val); 38 | int cmt_labels_count(struct cmt_labels *labels); 39 | 40 | #endif 41 | -------------------------------------------------------------------------------- /include/cmetrics/cmt_version.h.in: -------------------------------------------------------------------------------- 1 | /* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ 2 | 3 | /* Chunk I/O 4 | * ========= 5 | * Copyright 2018 Eduardo Silva 6 | * 7 | * Licensed under the Apache License, Version 2.0 (the "License"); 8 | * you may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | */ 19 | 20 | #ifndef CMT_VERSION_H 21 | #define CMT_VERSION_H 22 | 23 | /* Helpers to convert/format version string */ 24 | #define STR_HELPER(s) #s 25 | #define STR(s) STR_HELPER(s) 26 | 27 | /* Chunk I/O Version */ 28 | #define CMT_VERSION_MAJOR @CMT_VERSION_MAJOR@ 29 | #define CMT_VERSION_MINOR @CMT_VERSION_MINOR@ 30 | #define CMT_VERSION_PATCH @CMT_VERSION_PATCH@ 31 | #define CMT_VERSION (CMT_VERSION_MAJOR * 10000 \ 32 | CMT_VERSION_MINOR * 100 \ 33 | CMT_VERSION_PATCH) 34 | #define CMT_VERSION_STR "@CMT_VERSION_STR@" 35 | 36 | #endif 37 | -------------------------------------------------------------------------------- /tests/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | set(UNIT_TESTS_FILES 2 | basic.c 3 | gauge.c 4 | counter.c 5 | summary.c 6 | histogram.c 7 | untyped.c 8 | atomic_operations.c 9 | encoding.c 10 | decoding.c 11 | cat.c 12 | issues.c 13 | null_label.c 14 | filter.c 15 | ) 16 | 17 | if (CMT_BUILD_PROMETHEUS_TEXT_DECODER) 18 | set(UNIT_TESTS_FILES 19 | ${UNIT_TESTS_FILES} 20 | prometheus_lexer.c 21 | prometheus_parser.c) 22 | endif() 23 | 24 | set(CMT_TESTS_DATA_PATH "${CMAKE_CURRENT_SOURCE_DIR}/data") 25 | configure_file( 26 | "${CMAKE_CURRENT_SOURCE_DIR}/cmt_tests_config.h.in" 27 | "${CMAKE_CURRENT_BINARY_DIR}/cmt_tests_config.h" 28 | ) 29 | 30 | # Prepare list of unit tests 31 | foreach(source_file ${UNIT_TESTS_FILES}) 32 | get_filename_component(source_file_we ${source_file} NAME_WE) 33 | set(source_file_we cmt-test-${source_file_we}) 34 | 35 | add_executable( 36 | ${source_file_we} 37 | ${source_file} 38 | util.c 39 | encode_output.c 40 | ) 41 | 42 | target_link_libraries(${source_file_we} cmetrics-static cfl-static fluent-otel-proto) 43 | 44 | if(NOT CMT_SYSTEM_WINDOWS) 45 | target_link_libraries(${source_file_we} pthread) 46 | endif() 47 | 48 | add_test(NAME ${source_file_we} 49 | COMMAND ${CMAKE_BINARY_DIR}/tests/${source_file_we} 50 | WORKING_DIRECTORY ${CMAKE_HOME_DIRECTORY}/tests) 51 | set_tests_properties(${source_file_we} PROPERTIES LABELS "internal") 52 | endforeach() 53 | -------------------------------------------------------------------------------- /src/cmt_atomic_clang.c: -------------------------------------------------------------------------------- 1 | /* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ 2 | 3 | /* CMetrics 4 | * ======== 5 | * Copyright 2021-2022 The CMetrics Authors 6 | * 7 | * Licensed under the Apache License, Version 2.0 (the "License"); 8 | * you may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | */ 19 | 20 | #include 21 | 22 | inline int cmt_atomic_initialize() 23 | { 24 | return 0; 25 | } 26 | 27 | inline int cmt_atomic_compare_exchange(uint64_t *storage, 28 | uint64_t old_value, uint64_t new_value) 29 | { 30 | return __atomic_compare_exchange(storage, &old_value, &new_value, 0, 31 | __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST); 32 | } 33 | 34 | inline void cmt_atomic_store(uint64_t *storage, uint64_t new_value) 35 | { 36 | __atomic_store_n(storage, new_value, __ATOMIC_SEQ_CST); 37 | } 38 | 39 | inline uint64_t cmt_atomic_load(uint64_t *storage) 40 | { 41 | return __atomic_load_n(storage, __ATOMIC_SEQ_CST); 42 | } 43 | -------------------------------------------------------------------------------- /src/cmt_atomic_gcc.c: -------------------------------------------------------------------------------- 1 | /* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ 2 | 3 | /* CMetrics 4 | * ======== 5 | * Copyright 2021-2022 The CMetrics Authors 6 | * 7 | * Licensed under the Apache License, Version 2.0 (the "License"); 8 | * you may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | */ 19 | 20 | #include 21 | 22 | inline int cmt_atomic_initialize() 23 | { 24 | return 0; 25 | } 26 | 27 | inline int cmt_atomic_compare_exchange(uint64_t *storage, 28 | uint64_t old_value, uint64_t new_value) 29 | { 30 | return __atomic_compare_exchange(storage, &old_value, &new_value, 0, 31 | __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST); 32 | } 33 | 34 | inline void cmt_atomic_store(uint64_t *storage, uint64_t new_value) 35 | { 36 | __atomic_store_n(storage, new_value, __ATOMIC_SEQ_CST); 37 | } 38 | 39 | inline uint64_t cmt_atomic_load(uint64_t *storage) 40 | { 41 | return __atomic_load_n(storage, __ATOMIC_SEQ_CST); 42 | } 43 | -------------------------------------------------------------------------------- /include/cmetrics/cmt_opts.h: -------------------------------------------------------------------------------- 1 | /* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ 2 | 3 | /* CMetrics 4 | * ======== 5 | * Copyright 2021-2022 The CMetrics Authors 6 | * 7 | * Licensed under the Apache License, Version 2.0 (the "License"); 8 | * you may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | */ 19 | 20 | #ifndef CMT_OPTS_H 21 | #define CMT_OPTS_H 22 | 23 | #include 24 | 25 | struct cmt_opts { 26 | cfl_sds_t ns; /* namespace */ 27 | cfl_sds_t subsystem; /* subsystem */ 28 | cfl_sds_t name; /* metric name */ 29 | 30 | /* Help string: what's the metric about */ 31 | cfl_sds_t description; 32 | 33 | /* Formatted full qualified name: namespace_subsystem_name */ 34 | cfl_sds_t fqname; 35 | 36 | /* Resource index is only used by opentelemtry */ 37 | int resource_index; 38 | }; 39 | 40 | int cmt_opts_init(struct cmt_opts *opts, 41 | char *ns, char *subsystem, char *name, char *help); 42 | void cmt_opts_exit(struct cmt_opts *opts); 43 | 44 | #endif 45 | -------------------------------------------------------------------------------- /include/cmetrics/cmt_encode_splunk_hec.h: -------------------------------------------------------------------------------- 1 | /* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ 2 | 3 | /* CMetrics 4 | * ======== 5 | * Copyright 2022 The CMetrics Authors 6 | * 7 | * Licensed under the Apache License, Version 2.0 (the "License"); 8 | * you may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | */ 19 | 20 | 21 | #ifndef CMT_ENCODE_SPLUNK_HEC_H 22 | #define CMT_ENCODE_SPLUNK_HEC_H 23 | 24 | #include 25 | 26 | #define CMT_ENCODE_SPLUNK_HEC_SUCCESS 0 27 | #define CMT_ENCODE_SPLUNK_HEC_ALLOCATION_ERROR 1 28 | #define CMT_ENCODE_SPLUNK_HEC_INVALID_ARGUMENT_ERROR 2 29 | #define CMT_ENCODE_SPLUNK_HEC_UNEXPECTED_METRIC_TYPE 3 30 | #define CMT_ENCODE_SPLUNK_HEC_INVALID_DATA_ERROR 4 31 | 32 | struct cmt_splunk_hec_context { 33 | const char *host; 34 | const char *index; 35 | const char *source; 36 | const char *source_type; 37 | struct cmt *cmt; 38 | }; 39 | 40 | cfl_sds_t cmt_encode_splunk_hec_create(struct cmt *cmt, const char *host, 41 | const char *index, const char *source, const char *source_type); 42 | void cmt_encode_splunk_hec_destroy(cfl_sds_t text); 43 | 44 | #endif 45 | -------------------------------------------------------------------------------- /include/cmetrics/cmt_encode_cloudwatch_emf.h: -------------------------------------------------------------------------------- 1 | /* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ 2 | 3 | /* CMetrics 4 | * ======== 5 | * Copyright 2024 The CMetrics Authors 6 | * 7 | * Licensed under the Apache License, Version 2.0 (the "License"); 8 | * you may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | */ 19 | 20 | 21 | #ifndef CMT_ENCODE_CLOUDWATCH_EMF_H 22 | #define CMT_ENCODE_CLOUDWATCH_EMF_H 23 | 24 | #include 25 | #include 26 | #include 27 | 28 | #define CMT_ENCODE_CLOUDWATCH_EMF_SUCCESS 0 29 | #define CMT_ENCODE_CLOUDWATCH_EMF_INVALID_ARGUMENT_ERROR -1 30 | #define CMT_ENCODE_CLOUDWATCH_EMF_CREATION_FAILED -2 31 | #define CMT_ENCODE_CLOUDWATCH_EMF_INVALID_DATA_ERROR -4 32 | 33 | /* Metric Unit */ 34 | #define CMT_EMF_UNIT_PERCENT "Percent" 35 | #define CMT_EMF_UNIT_BYTES "Bytes" 36 | #define CMT_EMF_UNIT_COUNTER "Counter" 37 | 38 | int cmt_encode_cloudwatch_emf_create(struct cmt *cmt, 39 | char **out_buf, size_t *out_size, 40 | int wrap_array); 41 | void cmt_encode_cloudwatch_emf_destroy(char *out_buf); 42 | 43 | #endif 44 | -------------------------------------------------------------------------------- /include/cmetrics/cmt_mpack_utils_defs.h: -------------------------------------------------------------------------------- 1 | /* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ 2 | 3 | /* CMetrics 4 | * ======== 5 | * Copyright 2021-2022 The CMetrics Authors 6 | * 7 | * Licensed under the Apache License, Version 2.0 (the "License"); 8 | * you may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | */ 19 | 20 | #ifndef CMT_MPACK_UTILS_DEFS_H 21 | #define CMT_MPACK_UTILS_DEFS_H 22 | 23 | #define CMT_MPACK_SUCCESS 0 24 | #define CMT_MPACK_INSUFFICIENT_DATA 1 25 | #define CMT_MPACK_INVALID_ARGUMENT_ERROR 2 26 | #define CMT_MPACK_ALLOCATION_ERROR 3 27 | #define CMT_MPACK_CORRUPT_INPUT_DATA_ERROR 4 28 | #define CMT_MPACK_CONSUME_ERROR 5 29 | #define CMT_MPACK_ENGINE_ERROR 6 30 | #define CMT_MPACK_PENDING_MAP_ENTRIES 7 31 | #define CMT_MPACK_PENDING_ARRAY_ENTRIES 8 32 | #define CMT_MPACK_UNEXPECTED_KEY_ERROR 9 33 | #define CMT_MPACK_UNEXPECTED_DATA_TYPE_ERROR 10 34 | #define CMT_MPACK_ERROR_CUTOFF 20 35 | 36 | #define CMT_MPACK_MAX_ARRAY_ENTRY_COUNT 65535 37 | #define CMT_MPACK_MAX_MAP_ENTRY_COUNT 10 38 | #define CMT_MPACK_MAX_STRING_LENGTH 1024 39 | 40 | #endif -------------------------------------------------------------------------------- /tests/data/pr_168.txt: -------------------------------------------------------------------------------- 1 | # HELP prometheus_engine_query_duration_seconds Query timings 2 | # TYPE prometheus_engine_query_duration_seconds summary 3 | prometheus_engine_query_duration_seconds{slice="inner_eval",quantile="0.5"} NaN 4 | prometheus_engine_query_duration_seconds{slice="inner_eval",quantile="0.9"} NaN 5 | prometheus_engine_query_duration_seconds{slice="inner_eval",quantile="0.99"} NaN 6 | prometheus_engine_query_duration_seconds_sum{slice="inner_eval"} 0 7 | prometheus_engine_query_duration_seconds_count{slice="inner_eval"} 0 8 | prometheus_engine_query_duration_seconds{slice="prepare_time",quantile="0.5"} NaN 9 | prometheus_engine_query_duration_seconds{slice="prepare_time",quantile="0.9"} NaN 10 | prometheus_engine_query_duration_seconds{slice="prepare_time",quantile="0.99"} NaN 11 | prometheus_engine_query_duration_seconds_sum{slice="prepare_time"} 0 12 | prometheus_engine_query_duration_seconds_count{slice="prepare_time"} 0 13 | prometheus_engine_query_duration_seconds{slice="queue_time",quantile="0.5"} NaN 14 | prometheus_engine_query_duration_seconds{slice="queue_time",quantile="0.9"} NaN 15 | prometheus_engine_query_duration_seconds{slice="queue_time",quantile="0.99"} NaN 16 | prometheus_engine_query_duration_seconds_sum{slice="queue_time"} 0 17 | prometheus_engine_query_duration_seconds_count{slice="queue_time"} 0 18 | prometheus_engine_query_duration_seconds{slice="result_sort",quantile="0.5"} NaN 19 | prometheus_engine_query_duration_seconds{slice="result_sort",quantile="0.9"} NaN 20 | prometheus_engine_query_duration_seconds{slice="result_sort",quantile="0.99"} NaN 21 | prometheus_engine_query_duration_seconds_sum{slice="result_sort"} 0 22 | prometheus_engine_query_duration_seconds_count{slice="result_sort"} 0 23 | -------------------------------------------------------------------------------- /src/external/LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2008-2016, Dave Benson and the protobuf-c authors. 2 | All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions are 6 | met: 7 | 8 | * Redistributions of source code must retain the above copyright 9 | notice, this list of conditions and the following disclaimer. 10 | 11 | * Redistributions in binary form must reproduce the above 12 | copyright notice, this list of conditions and the following disclaimer 13 | in the documentation and/or other materials provided with the 14 | distribution. 15 | 16 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 17 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 18 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 19 | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 20 | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 21 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 22 | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24 | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 26 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 | 28 | The code generated by the protoc-gen-c code generator and by the 29 | protoc-c compiler is owned by the owner of the input files used when 30 | generating it. This code is not standalone and requires a support 31 | library to be linked with it. This support library is covered by the 32 | above license. 33 | -------------------------------------------------------------------------------- /include/cmetrics/cmt_cat.h: -------------------------------------------------------------------------------- 1 | /* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ 2 | 3 | /* CMetrics 4 | * ======== 5 | * Copyright 2021-2022 The CMetrics Authors 6 | * 7 | * Licensed under the Apache License, Version 2.0 (the "License"); 8 | * you may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | */ 19 | 20 | #ifndef CMT_CAT_H 21 | #define CMT_CAT_H 22 | 23 | #include 24 | 25 | struct cmt_counter; 26 | struct cmt_gauge; 27 | struct cmt_untyped; 28 | struct cmt_histogram; 29 | struct cmt_summary; 30 | 31 | int cmt_cat_copy_label_keys(struct cmt_map *map, char **out); 32 | int cmt_cat_copy_map(struct cmt_opts *opts, struct cmt_map *dst, struct cmt_map *src); 33 | int cmt_cat_counter(struct cmt *cmt, struct cmt_counter *counter, struct cmt_map *filtered_map); 34 | int cmt_cat_gauge(struct cmt *cmt, struct cmt_gauge *gauge, struct cmt_map *filtered_map); 35 | int cmt_cat_untyped(struct cmt *cmt, struct cmt_untyped *untyped, struct cmt_map *filtered_map); 36 | int cmt_cat_histogram(struct cmt *cmt, struct cmt_histogram *histogram, struct cmt_map *filtered_map); 37 | int cmt_cat_summary(struct cmt *cmt, struct cmt_summary *summary, struct cmt_map *filtered_map); 38 | int cmt_cat(struct cmt *dst, struct cmt *src); 39 | 40 | #endif 41 | -------------------------------------------------------------------------------- /include/cmetrics/cmt_untyped.h: -------------------------------------------------------------------------------- 1 | /* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ 2 | 3 | /* CMetrics 4 | * ======== 5 | * Copyright 2021-2022 The CMetrics Authors 6 | * 7 | * Licensed under the Apache License, Version 2.0 (the "License"); 8 | * you may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | */ 19 | 20 | #ifndef CMT_UNTYPED_H 21 | #define CMT_UNTYPED_H 22 | 23 | #include 24 | #include 25 | 26 | struct cmt_untyped { 27 | struct cmt_opts opts; 28 | struct cmt_map *map; 29 | struct cmt *cmt; 30 | struct cfl_list _head; 31 | }; 32 | 33 | struct cmt_untyped *cmt_untyped_create(struct cmt *cmt, 34 | char *ns, char *subsystem, 35 | char *name, char *help, 36 | int label_count, char **label_keys); 37 | 38 | int cmt_untyped_destroy(struct cmt_untyped *counter); 39 | 40 | int cmt_untyped_set(struct cmt_untyped *counter, uint64_t timestamp, double val, 41 | int labels_count, char **label_vals); 42 | 43 | int cmt_untyped_get_val(struct cmt_untyped *counter, 44 | int labels_count, char **label_vals, double *out_val); 45 | 46 | #endif 47 | -------------------------------------------------------------------------------- /tests/util.c: -------------------------------------------------------------------------------- 1 | /* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ 2 | 3 | /* CMetrics 4 | * ======== 5 | * Copyright 2021-2022 The CMetrics Authors 6 | * 7 | * Licensed under the Apache License, Version 2.0 (the "License"); 8 | * you may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | */ 19 | 20 | #include 21 | 22 | #include 23 | 24 | cfl_sds_t read_file(const char *path) 25 | { 26 | long flen; 27 | FILE *f = NULL; 28 | cfl_sds_t result = NULL; 29 | 30 | f = fopen(path, "rb"); 31 | if (!f) { 32 | return NULL; 33 | } 34 | 35 | if (fseek(f, 0, SEEK_END) == -1) { 36 | goto err; 37 | } 38 | 39 | flen = ftell(f); 40 | if (flen < 0) { 41 | goto err; 42 | } 43 | 44 | if (fseek(f, 0, SEEK_SET) == -1) { 45 | goto err; 46 | } 47 | 48 | result = cfl_sds_create_size(flen); 49 | if (!result) { 50 | goto err; 51 | } 52 | 53 | if (flen > 0 && fread(result, flen, 1, f) != 1) { 54 | goto err; 55 | } 56 | 57 | cfl_sds_set_len(result, flen); 58 | fclose(f); 59 | return result; 60 | 61 | err: 62 | fclose(f); 63 | if (result) { 64 | cfl_sds_destroy(result); 65 | } 66 | return NULL; 67 | } 68 | 69 | -------------------------------------------------------------------------------- /include/cmetrics/cmt_math.h: -------------------------------------------------------------------------------- 1 | /* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ 2 | 3 | /* CMetrics 4 | * ======== 5 | * Copyright 2021-2022 The CMetrics Authors 6 | * 7 | * Licensed under the Apache License, Version 2.0 (the "License"); 8 | * you may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | */ 19 | 20 | #ifndef CMT_MATH_H 21 | #define CMT_MATH_H 22 | 23 | #include 24 | #include 25 | 26 | union val_union { 27 | uint64_t u; 28 | double d; 29 | }; 30 | 31 | /* 32 | * This is not rocket-science and to make things easier we assume that operating on 33 | * floating pointer numbers we will lose precision. So we just do simple casts. 34 | */ 35 | 36 | static inline uint64_t cmt_math_d64_to_uint64(double val) 37 | { 38 | union val_union u; 39 | 40 | u.d = val; 41 | return u.u; 42 | } 43 | 44 | static inline double cmt_math_uint64_to_d64(uint64_t val) 45 | { 46 | union val_union u; 47 | 48 | u.u = val; 49 | return u.d; 50 | } 51 | 52 | static inline uint64_t cmt_math_sum_native_uint64_as_d64(uint64_t dst, uint64_t src) 53 | { 54 | double val; 55 | 56 | val = cmt_math_uint64_to_d64(dst); 57 | val += cmt_math_uint64_to_d64(src); 58 | 59 | return cmt_math_d64_to_uint64(val); 60 | } 61 | 62 | #endif 63 | -------------------------------------------------------------------------------- /include/cmetrics/cmt_filter.h: -------------------------------------------------------------------------------- 1 | /* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ 2 | 3 | /* CMetrics 4 | * ======== 5 | * Copyright 2021-2024 The CMetrics Authors 6 | * 7 | * Licensed under the Apache License, Version 2.0 (the "License"); 8 | * you may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | */ 19 | 20 | #ifndef CMT_FILTER_H 21 | #define CMT_FILTER_H 22 | 23 | #include 24 | #include 25 | 26 | #define CMT_FILTER_EXCLUDE (1 << 1) 27 | #define CMT_FILTER_PREFIX (1 << 2) 28 | #define CMT_FILTER_SUBSTRING (1 << 3) 29 | #define CMT_FILTER_REGEX_SEARCH_LABELS (1 << 4) 30 | 31 | #define CMT_FILTER_SUCCESS 0 32 | #define CMT_FILTER_INVALID_ARGUMENT -1 33 | #define CMT_FILTER_INVALID_FLAGS -2 34 | #define CMT_FILTER_FAILED_OPERATION -3 35 | 36 | int cmt_filter(struct cmt *dst, struct cmt *src, 37 | const char *fqname, const char *label_key, 38 | void *compare_ctx, int (*compare)(void *compare_ctx, const char *str, size_t slen), 39 | int flags); 40 | 41 | int cmt_filter_with_label_pair(struct cmt *dst, struct cmt *src, 42 | const char *label_key, 43 | const char *label_value); 44 | 45 | #endif 46 | -------------------------------------------------------------------------------- /include/cmetrics/cmt_encode_opentelemetry.h: -------------------------------------------------------------------------------- 1 | /* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ 2 | 3 | /* CMetrics 4 | * ======== 5 | * Copyright 2021-2022 The CMetrics Authors 6 | * 7 | * Licensed under the Apache License, Version 2.0 (the "License"); 8 | * you may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | */ 19 | 20 | 21 | #ifndef CMT_ENCODE_OPENTELEMETRY_H 22 | #define CMT_ENCODE_OPENTELEMETRY_H 23 | 24 | #include 25 | #include 26 | #include 27 | 28 | #define CMT_ENCODE_OPENTELEMETRY_SUCCESS 0 29 | #define CMT_ENCODE_OPENTELEMETRY_ALLOCATION_ERROR 1 30 | #define CMT_ENCODE_OPENTELEMETRY_INVALID_ARGUMENT_ERROR 2 31 | #define CMT_ENCODE_OPENTELEMETRY_UNEXPECTED_METRIC_TYPE 3 32 | #define CMT_ENCODE_OPENTELEMETRY_DATA_POINT_INIT_ERROR 4 33 | 34 | struct cmt_opentelemetry_context 35 | { 36 | size_t resource_index; 37 | Opentelemetry__Proto__Metrics__V1__MetricsData *metrics_data; 38 | struct cmt *cmt; 39 | }; 40 | 41 | cfl_sds_t cmt_encode_opentelemetry_create(struct cmt *cmt); 42 | void cmt_encode_opentelemetry_destroy(cfl_sds_t text); 43 | 44 | #endif 45 | -------------------------------------------------------------------------------- /include/cmetrics/cmt_decode_prometheus_remote_write.h: -------------------------------------------------------------------------------- 1 | /* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ 2 | 3 | /* CMetrics 4 | * ======== 5 | * Copyright 2021-2024 The CMetrics Authors 6 | * 7 | * Licensed under the Apache License, Version 2.0 (the "License"); 8 | * you may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | */ 19 | 20 | 21 | #ifndef CMT_DECODE_PROMETHEUS_REMOTE_WRITE_H 22 | #define CMT_DECODE_PROMETHEUS_REMOTE_WRITE_H 23 | 24 | #include 25 | #include 26 | 27 | #define CMT_DECODE_PROMETHEUS_REMOTE_WRITE_SUCCESS 0 28 | #define CMT_DECODE_PROMETHEUS_REMOTE_WRITE_ALLOCATION_ERROR 1 29 | #define CMT_DECODE_PROMETHEUS_REMOTE_WRITE_UNEXPECTED_ERROR 2 30 | #define CMT_DECODE_PROMETHEUS_REMOTE_WRITE_INVALID_ARGUMENT_ERROR 3 31 | #define CMT_DECODE_PROMETHEUS_REMOTE_WRITE_UNEXPECTED_METRIC_TYPE 4 32 | #define CMT_DECODE_PROMETHEUS_REMOTE_WRITE_DECODE_ERROR 5 33 | #define CMT_DECODE_PROMETHEUS_REMOTE_WRITE_UNPACK_ERROR 6 34 | #define CMT_DECODE_PROMETHEUS_REMOTE_WRITE_UNSUPPORTED_METRIC_TYPE 7 35 | 36 | int cmt_decode_prometheus_remote_write_create(struct cmt **out_cmt, char *in_buf, size_t in_size); 37 | void cmt_decode_prometheus_remote_write_destroy(struct cmt *cmt); 38 | 39 | #endif 40 | -------------------------------------------------------------------------------- /include/cmetrics/cmt_decode_opentelemetry.h: -------------------------------------------------------------------------------- 1 | /* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ 2 | 3 | /* CMetrics 4 | * ======== 5 | * Copyright 2021-2022 The CMetrics Authors 6 | * 7 | * Licensed under the Apache License, Version 2.0 (the "License"); 8 | * you may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | */ 19 | 20 | 21 | #ifndef CMT_DECODE_OPENTELEMETRY_H 22 | #define CMT_DECODE_OPENTELEMETRY_H 23 | 24 | #include 25 | #include 26 | #include 27 | 28 | #define CMT_DECODE_OPENTELEMETRY_SUCCESS 0 29 | #define CMT_DECODE_OPENTELEMETRY_ALLOCATION_ERROR 1 30 | #define CMT_DECODE_OPENTELEMETRY_INVALID_ARGUMENT_ERROR 2 31 | #define CMT_DECODE_OPENTELEMETRY_KVLIST_ACCESS_ERROR 3 32 | #define CMT_DECODE_OPENTELEMETRY_ARRAY_ACCESS_ERROR 4 33 | 34 | struct cmt_opentelemetry_decode_context { 35 | struct cmt *cmt; 36 | struct cmt_map *map; 37 | struct cmt_metric *metric; 38 | char **namespace_identifiers; 39 | char **subsystem_identifiers; 40 | }; 41 | 42 | int cmt_decode_opentelemetry_create(struct cfl_list *result_context_list, 43 | char *in_buf, size_t in_size, 44 | size_t *offset); 45 | 46 | void cmt_decode_opentelemetry_destroy(struct cfl_list *context_list); 47 | 48 | #endif 49 | -------------------------------------------------------------------------------- /include/cmetrics/cmt_mpack_utils.h: -------------------------------------------------------------------------------- 1 | /* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ 2 | 3 | /* CMetrics 4 | * ======== 5 | * Copyright 2021-2022 The CMetrics Authors 6 | * 7 | * Licensed under the Apache License, Version 2.0 (the "License"); 8 | * you may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | */ 19 | 20 | #ifndef CMT_MPACK_UTILS_H 21 | #define CMT_MPACK_UTILS_H 22 | 23 | #include 24 | #include 25 | #include 26 | 27 | typedef int (*cmt_mpack_unpacker_entry_callback_fn_t)(mpack_reader_t *reader, 28 | size_t index, void *context); 29 | 30 | struct cmt_mpack_map_entry_callback_t { 31 | const char *identifier; 32 | cmt_mpack_unpacker_entry_callback_fn_t handler; 33 | }; 34 | 35 | int cmt_mpack_consume_double_tag(mpack_reader_t *reader, double *output_buffer); 36 | int cmt_mpack_consume_uint_tag(mpack_reader_t *reader, uint64_t *output_buffer); 37 | int cmt_mpack_consume_string_tag(mpack_reader_t *reader, cfl_sds_t *output_buffer); 38 | int cmt_mpack_unpack_map(mpack_reader_t *reader, 39 | struct cmt_mpack_map_entry_callback_t *callback_list, 40 | void *context); 41 | int cmt_mpack_unpack_array(mpack_reader_t *reader, 42 | cmt_mpack_unpacker_entry_callback_fn_t entry_processor_callback, 43 | void *context); 44 | int cmt_mpack_peek_array_length(mpack_reader_t *reader); 45 | 46 | #endif 47 | -------------------------------------------------------------------------------- /include/cmetrics/cmt_counter.h: -------------------------------------------------------------------------------- 1 | /* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ 2 | 3 | /* CMetrics 4 | * ======== 5 | * Copyright 2021-2022 The CMetrics Authors 6 | * 7 | * Licensed under the Apache License, Version 2.0 (the "License"); 8 | * you may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | */ 19 | 20 | #ifndef CMT_COUNTER_H 21 | #define CMT_COUNTER_H 22 | 23 | #include 24 | #include 25 | 26 | struct cmt_counter { 27 | struct cmt_opts opts; 28 | struct cmt_map *map; 29 | struct cfl_list _head; 30 | struct cmt *cmt; 31 | int allow_reset; 32 | int aggregation_type; 33 | }; 34 | 35 | struct cmt_counter *cmt_counter_create(struct cmt *cmt, 36 | char *ns, char *subsystem, 37 | char *name, char *help, 38 | int label_count, char **label_keys); 39 | void cmt_counter_allow_reset(struct cmt_counter *counter); 40 | int cmt_counter_destroy(struct cmt_counter *counter); 41 | int cmt_counter_inc(struct cmt_counter *counter, uint64_t timestamp, 42 | int labels_count, char **label_vals); 43 | int cmt_counter_add(struct cmt_counter *counter, uint64_t timestamp, 44 | double val, int labels_count, char **label_vals); 45 | int cmt_counter_set(struct cmt_counter *counter, uint64_t timestamp, double val, 46 | int labels_count, char **label_vals); 47 | int cmt_counter_get_val(struct cmt_counter *counter, 48 | int labels_count, char **label_vals, double *out_val); 49 | #endif 50 | 51 | -------------------------------------------------------------------------------- /include/cmetrics/cmt_decode_statsd.h: -------------------------------------------------------------------------------- 1 | /* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ 2 | 3 | /* CMetrics 4 | * ======== 5 | * Copyright 2021-2022 The CMetrics Authors 6 | * 7 | * Licensed under the Apache License, Version 2.0 (the "License"); 8 | * you may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | */ 19 | 20 | 21 | #ifndef CMT_DECODE_STATSD_H 22 | #define CMT_DECODE_STATSD_H 23 | 24 | #include 25 | 26 | #define CMT_DECODE_STATSD_TYPE_COUNTER 1 27 | #define CMT_DECODE_STATSD_TYPE_GAUGE 2 28 | #define CMT_DECODE_STATSD_TYPE_TIMER 3 29 | #define CMT_DECODE_STATSD_TYPE_SET 4 30 | 31 | #define CMT_DECODE_STATSD_SUCCESS 0 32 | #define CMT_DECODE_STATSD_ALLOCATION_ERROR 1 33 | #define CMT_DECODE_STATSD_UNEXPECTED_ERROR 2 34 | #define CMT_DECODE_STATSD_INVALID_ARGUMENT_ERROR 3 35 | #define CMT_DECODE_STATSD_UNEXPECTED_METRIC_TYPE 4 36 | #define CMT_DECODE_STATSD_DECODE_ERROR 5 37 | #define CMT_DECODE_STATSD_UNPACK_ERROR 6 38 | #define CMT_DECODE_STATSD_UNSUPPORTED_METRIC_TYPE 7 39 | #define CMT_DECODE_STATSD_INVALID_TAG_FORMAT_ERROR 8 40 | 41 | #define CMT_DECODE_STATSD_GAUGE_OBSERVER 1 << 0 42 | 43 | /* 44 | * The "cmt_statsd_message" represents a single line in UDP packet. 45 | * It's just a bunch of pointers to ephemeral buffer. 46 | */ 47 | struct cmt_statsd_message { 48 | char *bucket; 49 | int bucket_len; 50 | char *value; 51 | char *labels; 52 | int value_len; 53 | int type; 54 | double sample_rate; 55 | }; 56 | 57 | int cmt_decode_statsd_create(struct cmt **out_cmt, char *in_buf, size_t in_size, int flags); 58 | void cmt_decode_statsd_destroy(struct cmt *cmt); 59 | 60 | #endif 61 | -------------------------------------------------------------------------------- /include/cmetrics/cmt_gauge.h: -------------------------------------------------------------------------------- 1 | /* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ 2 | 3 | /* CMetrics 4 | * ======== 5 | * Copyright 2021-2022 The CMetrics Authors 6 | * 7 | * Licensed under the Apache License, Version 2.0 (the "License"); 8 | * you may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | */ 19 | 20 | #ifndef CMT_GAUGE_H 21 | #define CMT_GAUGE_H 22 | 23 | #include 24 | #include 25 | 26 | struct cmt_gauge { 27 | struct cmt_opts opts; /* Metric options */ 28 | struct cmt_map *map; 29 | struct cmt *cmt; 30 | struct cfl_list _head; /* Link to list struct cmt->gauges */ 31 | }; 32 | 33 | struct cmt_gauge *cmt_gauge_create(struct cmt *cmt, 34 | char *ns, char *subsystem, char *name, 35 | char *help, int label_count, char **label_keys); 36 | int cmt_gauge_destroy(struct cmt_gauge *gauge); 37 | 38 | int cmt_gauge_set(struct cmt_gauge *gauge, uint64_t timestamp, double val, 39 | int labels_count, char **label_vals); 40 | int cmt_gauge_inc(struct cmt_gauge *gauge, uint64_t timestamp, 41 | int labels_count, char **label_vals); 42 | int cmt_gauge_dec(struct cmt_gauge *gauge, uint64_t timestamp, 43 | int labels_count, char **label_vals); 44 | int cmt_gauge_add(struct cmt_gauge *gauge, uint64_t timestamp, 45 | double val, int labels_count, char **label_vals); 46 | int cmt_gauge_sub(struct cmt_gauge *gauge, uint64_t timestamp, double val, 47 | int labels_count, char **label_vals); 48 | int cmt_gauge_get_val(struct cmt_gauge *gauge, 49 | int labels_count, char **label_vals, double *out_val); 50 | 51 | #endif 52 | -------------------------------------------------------------------------------- /tests/encode_output.c: -------------------------------------------------------------------------------- 1 | /* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ 2 | 3 | /* CMetrics 4 | * ======== 5 | * Copyright 2021-2022 The CMetrics Authors 6 | * 7 | * Licensed under the Apache License, Version 2.0 (the "License"); 8 | * you may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | */ 19 | 20 | 21 | /* 22 | * This file is a helper utility just to try out all the encoders: given a specific 23 | * CMetrics context, encode to all possible formats and destroy them. This is 24 | * useful to trap potential memory leaks or errors when doing changes to the 25 | * metric types. 26 | */ 27 | 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include 33 | #include 34 | #include 35 | 36 | int cmt_test_encode_all(struct cmt *cmt) 37 | { 38 | char *out_buf; 39 | size_t out_size; 40 | cfl_sds_t sds_buf; 41 | 42 | /* text */ 43 | sds_buf = cmt_encode_text_create(cmt); 44 | cmt_encode_text_destroy(sds_buf); 45 | 46 | /* prometheus */ 47 | sds_buf = cmt_encode_prometheus_create(cmt, CMT_TRUE); 48 | cmt_encode_prometheus_destroy(sds_buf); 49 | 50 | /* prometheus remote write */ 51 | sds_buf = cmt_encode_prometheus_remote_write_create(cmt); 52 | cmt_encode_prometheus_remote_write_destroy(sds_buf); 53 | 54 | /* msgpack */ 55 | cmt_encode_msgpack_create(cmt, &out_buf, &out_size); 56 | cmt_encode_msgpack_destroy(out_buf); 57 | 58 | /* influx */ 59 | sds_buf = cmt_encode_influx_create(cmt); 60 | cmt_encode_influx_destroy(sds_buf); 61 | 62 | /* opentelemetry */ 63 | sds_buf = cmt_encode_opentelemetry_create(cmt); 64 | cmt_encode_opentelemetry_destroy(sds_buf); 65 | 66 | return 0; 67 | } 68 | -------------------------------------------------------------------------------- /include/cmetrics/cmt_encode_prometheus_remote_write.h: -------------------------------------------------------------------------------- 1 | /* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ 2 | 3 | /* CMetrics 4 | * ======== 5 | * Copyright 2021-2022 The CMetrics Authors 6 | * 7 | * Licensed under the Apache License, Version 2.0 (the "License"); 8 | * you may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | */ 19 | 20 | 21 | #ifndef CMT_ENCODE_PROMETHEUS_REMOTE_WRITE_H 22 | #define CMT_ENCODE_PROMETHEUS_REMOTE_WRITE_H 23 | 24 | #include 25 | #include 26 | 27 | #define CMT_ENCODE_PROMETHEUS_REMOTE_WRITE_ADD_METADATA CMT_FALSE 28 | #define CMT_ENCODE_PROMETHEUS_REMOTE_WRITE_CUTOFF_THRESHOLD 3600000000000L /* One hour in nanoseconds */ 29 | 30 | #define CMT_ENCODE_PROMETHEUS_REMOTE_WRITE_SUCCESS 0 31 | #define CMT_ENCODE_PROMETHEUS_REMOTE_WRITE_ALLOCATION_ERROR 1 32 | #define CMT_ENCODE_PROMETHEUS_REMOTE_WRITE_UNEXPECTED_ERROR 2 33 | #define CMT_ENCODE_PROMETHEUS_REMOTE_WRITE_INVALID_ARGUMENT_ERROR 3 34 | #define CMT_ENCODE_PROMETHEUS_REMOTE_WRITE_UNEXPECTED_METRIC_TYPE 4 35 | #define CMT_ENCODE_PROMETHEUS_REMOTE_WRITE_CUTOFF_ERROR 5 36 | 37 | struct cmt_prometheus_metric_metadata { 38 | Prometheus__MetricMetadata data; 39 | struct cfl_list _head; 40 | }; 41 | 42 | struct cmt_prometheus_time_series { 43 | uint64_t label_set_hash; 44 | size_t entries_set; 45 | Prometheus__TimeSeries data; 46 | struct cfl_list _head; 47 | }; 48 | 49 | struct cmt_prometheus_remote_write_context 50 | { 51 | struct cfl_list time_series_entries; 52 | struct cfl_list metadata_entries; 53 | uint64_t sequence_number; 54 | Prometheus__WriteRequest write_request; 55 | struct cmt *cmt; 56 | }; 57 | 58 | cfl_sds_t cmt_encode_prometheus_remote_write_create(struct cmt *cmt); 59 | void cmt_encode_prometheus_remote_write_destroy(cfl_sds_t text); 60 | 61 | #endif 62 | -------------------------------------------------------------------------------- /include/cmetrics/cmetrics.h: -------------------------------------------------------------------------------- 1 | /* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ 2 | 3 | /* CMetrics 4 | * ======== 5 | * Copyright 2021-2022 The CMetrics Authors 6 | * 7 | * Licensed under the Apache License, Version 2.0 (the "License"); 8 | * you may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | */ 19 | 20 | #ifndef CMT_H 21 | #define CMT_H 22 | 23 | #define CMT_FALSE 0 24 | #define CMT_TRUE !CMT_FALSE 25 | 26 | #define CMT_COUNTER 0 27 | #define CMT_GAUGE 1 28 | #define CMT_HISTOGRAM 2 29 | #define CMT_SUMMARY 3 30 | #define CMT_UNTYPED 4 31 | 32 | #define CMT_AGGREGATION_TYPE_UNSPECIFIED 0 33 | #define CMT_AGGREGATION_TYPE_DELTA 1 34 | #define CMT_AGGREGATION_TYPE_CUMULATIVE 2 35 | 36 | #include 37 | #include 38 | #include 39 | 40 | #include 41 | 42 | #include 43 | #include 44 | #include 45 | #include 46 | #include 47 | #include 48 | #include 49 | 50 | struct cmt { 51 | /* logging */ 52 | int log_level; 53 | void (*log_cb)(void *, int, const char *, int, const char *); 54 | 55 | /* cmetrics metadata */ 56 | struct cfl_kvlist *internal_metadata; 57 | 58 | /* third party metadata (ie. otlp resource & instrumentation library) */ 59 | struct cfl_kvlist *external_metadata; 60 | 61 | /* static labels */ 62 | struct cmt_labels *static_labels; 63 | 64 | /* Metrics list */ 65 | struct cfl_list counters; 66 | struct cfl_list gauges; 67 | struct cfl_list histograms; 68 | struct cfl_list summaries; 69 | struct cfl_list untypeds; 70 | 71 | /* Only used by the otlp decoder */ 72 | struct cfl_list _head; 73 | }; 74 | 75 | void cmt_initialize(); 76 | 77 | struct cmt *cmt_create(); 78 | void cmt_destroy(struct cmt *cmt); 79 | int cmt_label_add(struct cmt *cmt, char *key, char *val); 80 | char *cmt_version(); 81 | 82 | #endif 83 | -------------------------------------------------------------------------------- /include/cmetrics/cmt_map.h: -------------------------------------------------------------------------------- 1 | /* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ 2 | 3 | /* CMetrics 4 | * ======== 5 | * Copyright 2021-2022 The CMetrics Authors 6 | * 7 | * Licensed under the Apache License, Version 2.0 (the "License"); 8 | * you may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | */ 19 | 20 | #ifndef CMT_MAP_H 21 | #define CMT_MAP_H 22 | 23 | #include 24 | #include 25 | #include 26 | 27 | struct cmt_map_label { 28 | cfl_sds_t name; /* Label key name */ 29 | struct cfl_list _head; /* Link to list cmt_labels_map->labels */ 30 | }; 31 | 32 | struct cmt_map { 33 | int type; /* Metric type */ 34 | struct cmt_opts *opts; /* Reference to parent 'opts' */ 35 | cfl_sds_t unit; /* Metric unit */ 36 | 37 | /* A map without label keys, uses direct access to the static metric ctx */ 38 | int metric_static_set; /* is the static metric set ? */ 39 | struct cmt_metric metric; 40 | 41 | /* Used when labels are set */ 42 | struct cfl_list metrics; /* List of metrics */ 43 | int label_count; /* Number of labels */ 44 | struct cfl_list label_keys; /* Linked list of labels */ 45 | void *parent; 46 | }; 47 | 48 | struct cmt_map *cmt_map_create(int type, struct cmt_opts *opts, 49 | int count, char **labels, void *parent); 50 | void cmt_map_destroy(struct cmt_map *map); 51 | 52 | struct cmt_metric *cmt_map_metric_get(struct cmt_opts *opts, struct cmt_map *map, 53 | int labels_count, char **labels_val, 54 | int write_op); 55 | int cmt_map_metric_get_val(struct cmt_opts *opts, struct cmt_map *map, 56 | int labels_count, char **labels_val, 57 | double *out_val); 58 | void cmt_map_metric_destroy(struct cmt_metric *metric); 59 | 60 | void destroy_label_list(struct cfl_list *label_list); 61 | 62 | #endif 63 | -------------------------------------------------------------------------------- /include/cmetrics/cmt_summary.h: -------------------------------------------------------------------------------- 1 | /* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ 2 | 3 | /* CMetrics 4 | * ======== 5 | * Copyright 2021-2022 The CMetrics Authors 6 | * 7 | * Licensed under the Apache License, Version 2.0 (the "License"); 8 | * you may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | */ 19 | 20 | #ifndef CMT_SUMMARY_H 21 | #define CMT_SUMMARY_H 22 | 23 | #include 24 | #include 25 | #include 26 | 27 | /* 28 | * The structure only is aware about final 'quantile' values, not percentiles or 29 | * any other involved variable. We won't do calculations. 30 | */ 31 | struct cmt_summary { 32 | /* summary specific */ 33 | double *quantiles; 34 | size_t quantiles_count; 35 | 36 | /* metrics common */ 37 | struct cmt_opts opts; 38 | struct cmt_map *map; 39 | struct cfl_list _head; 40 | struct cmt *cmt; 41 | 42 | }; 43 | 44 | struct cmt_summary *cmt_summary_create(struct cmt *cmt, 45 | char *ns, char *subsystem, 46 | char *name, char *help, 47 | size_t quantiles_count, 48 | double *quantiles, 49 | int label_count, char **label_keys); 50 | 51 | int cmt_summary_destroy(struct cmt_summary *summary); 52 | 53 | int cmt_summary_set_default(struct cmt_summary *summary, 54 | uint64_t timestamp, 55 | double *quantile_values, 56 | double sum, 57 | uint64_t count, 58 | int labels_count, char **label_vars); 59 | 60 | /* quantiles */ 61 | double cmt_summary_quantile_get_value(struct cmt_metric *metric, int quantile_id); 62 | 63 | double cmt_summary_get_sum_value(struct cmt_metric *metric); 64 | uint64_t cmt_summary_get_count_value(struct cmt_metric *metric); 65 | 66 | void cmt_summary_quantile_set(struct cmt_metric *metric, uint64_t timestamp, 67 | int quantile_id, double val); 68 | 69 | 70 | #endif 71 | -------------------------------------------------------------------------------- /include/cmetrics/cmt_log.h: -------------------------------------------------------------------------------- 1 | /* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ 2 | 3 | /* CMetrics 4 | * ======== 5 | * Copyright 2021-2022 The CMetrics Authors 6 | * 7 | * Licensed under the Apache License, Version 2.0 (the "License"); 8 | * you may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | */ 19 | 20 | #ifndef CMT_LOG_H 21 | #define CMT_LOG_H 22 | 23 | #include 24 | 25 | /* Message types */ 26 | #define CMT_LOG_OFF 0 27 | #define CMT_LOG_ERROR 1 28 | #define CMT_LOG_WARN 2 29 | #define CMT_LOG_INFO 3 /* default */ 30 | #define CMT_LOG_DEBUG 4 31 | #define CMT_LOG_TRACE 5 32 | 33 | 34 | #define CMT_LOG_BUF_SIZE 256 35 | 36 | void cmt_log_print(void *ctx, int level, const char *file, int line, 37 | const char *fmt, ...); 38 | int cmt_errno_print(int errnum, const char *file, int line); 39 | 40 | #define cmt_log_error(ctx, fmt, ...) \ 41 | cmt_log_print(ctx, CMT_LOG_ERROR, __CMT_FILENAME__, \ 42 | __LINE__, fmt, ##__VA_ARGS__) 43 | 44 | #define cmt_log_warn(ctx, fmt, ...) \ 45 | cmt_log_print(ctx, CMT_LOG_WARN, __CMT_FILENAME__, \ 46 | __LINE__, fmt, ##__VA_ARGS__) 47 | 48 | #define cmt_log_info(ctx, fmt, ...) \ 49 | cmt_log_print(ctx, CMT_LOG_INFO, __CMT_FILENAME__, \ 50 | __LINE__, fmt, ##__VA_ARGS__) 51 | 52 | #define cmt_log_debug(ctx, fmt, ...) \ 53 | cmt_log_print(ctx, CMT_LOG_DEBUG, __CMT_FILENAME__, \ 54 | __LINE__, fmt, ##__VA_ARGS__) 55 | 56 | #define cmt_log_trace(ctx, fmt, ...) \ 57 | cmt_log_print(ctx, CMT_LOG_TRACE, __CMT_FILENAME__, \ 58 | __LINE__, fmt, ##__VA_ARGS__) 59 | 60 | #ifdef __CMT_FILENAME__ 61 | #define cmt_errno() cmt_errno_print(errno, __CMT_FILENAME__, __LINE__) 62 | #else 63 | #define cmt_errno() cmt_errno_print(errno, __FILE__, __LINE__) 64 | #endif 65 | 66 | #ifdef _WIN32 67 | void cmt_winapi_error_print(const char *func, int line); 68 | #define cmt_winapi_error() cmt_winapi_error_print(__func__, __LINE__) 69 | #endif 70 | 71 | #endif 72 | -------------------------------------------------------------------------------- /src/cmt_log.c: -------------------------------------------------------------------------------- 1 | /* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ 2 | 3 | /* CMetrics 4 | * ======== 5 | * Copyright 2021-2022 The CMetrics Authors 6 | * 7 | * Licensed under the Apache License, Version 2.0 (the "License"); 8 | * you may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | */ 19 | 20 | #include 21 | #include 22 | #include 23 | 24 | #include 25 | #include 26 | #include 27 | 28 | #ifdef _WIN32 29 | #define strerror_r(errnum, buf, buf_size) strerror_s(buf, buf_size, errnum) 30 | #endif 31 | 32 | void cmt_log_print(void *ctx, int level, const char *file, int line, 33 | const char *fmt, ...) 34 | { 35 | int ret; 36 | char buf[CMT_LOG_BUF_SIZE]; 37 | va_list args; 38 | struct cmt *cmt = ctx; 39 | 40 | if (!cmt->log_cb) { 41 | return; 42 | } 43 | 44 | if (level > cmt->log_level) { 45 | return; 46 | } 47 | 48 | va_start(args, fmt); 49 | ret = vsnprintf(buf, CMT_LOG_BUF_SIZE - 1, fmt, args); 50 | 51 | if (ret >= 0) { 52 | buf[ret] = '\0'; 53 | } 54 | va_end(args); 55 | 56 | cmt->log_cb(ctx, level, file, line, buf); 57 | } 58 | 59 | int cmt_errno_print(int errnum, const char *file, int line) 60 | { 61 | char buf[256]; 62 | 63 | strerror_r(errnum, buf, sizeof(buf) - 1); 64 | fprintf(stderr, "[%s:%i errno=%i] %s\n", 65 | file, line, errnum, buf); 66 | return 0; 67 | } 68 | 69 | #ifdef _WIN32 70 | void cmt_winapi_error_print(const char *func, int line) 71 | { 72 | int error = GetLastError(); 73 | char buf[256]; 74 | int success; 75 | 76 | success = FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM | 77 | FORMAT_MESSAGE_IGNORE_INSERTS, 78 | NULL, 79 | error, 80 | LANG_SYSTEM_DEFAULT, 81 | buf, 82 | sizeof(buf), 83 | NULL); 84 | if (success) { 85 | fprintf(stderr, "[%s() line=%i error=%i] %s\n", func, line, error, buf); 86 | } 87 | else { 88 | fprintf(stderr, "[%s() line=%i error=%i] Win32 API failed\n", func, line, error); 89 | } 90 | } 91 | #endif 92 | -------------------------------------------------------------------------------- /include/cmetrics/cmt_decode_msgpack.h: -------------------------------------------------------------------------------- 1 | /* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ 2 | 3 | /* CMetrics 4 | * ======== 5 | * Copyright 2021-2022 The CMetrics Authors 6 | * 7 | * Licensed under the Apache License, Version 2.0 (the "License"); 8 | * you may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | */ 19 | 20 | 21 | #ifndef CMT_DECODE_MSGPACK_H 22 | #define CMT_DECODE_MSGPACK_H 23 | 24 | #include 25 | #include 26 | 27 | #define CMT_DECODE_MSGPACK_SUCCESS CMT_MPACK_SUCCESS 28 | #define CMT_DECODE_MSGPACK_INSUFFICIENT_DATA CMT_MPACK_INSUFFICIENT_DATA 29 | #define CMT_DECODE_MSGPACK_INVALID_ARGUMENT_ERROR CMT_MPACK_INVALID_ARGUMENT_ERROR 30 | #define CMT_DECODE_MSGPACK_ALLOCATION_ERROR CMT_MPACK_ALLOCATION_ERROR 31 | #define CMT_DECODE_MSGPACK_CORRUPT_INPUT_DATA_ERROR CMT_MPACK_CORRUPT_INPUT_DATA_ERROR 32 | #define CMT_DECODE_MSGPACK_CONSUME_ERROR CMT_MPACK_CONSUME_ERROR 33 | #define CMT_DECODE_MSGPACK_ENGINE_ERROR CMT_MPACK_ENGINE_ERROR 34 | #define CMT_DECODE_MSGPACK_PENDING_MAP_ENTRIES CMT_MPACK_PENDING_MAP_ENTRIES 35 | #define CMT_DECODE_MSGPACK_PENDING_ARRAY_ENTRIES CMT_MPACK_PENDING_ARRAY_ENTRIES 36 | #define CMT_DECODE_MSGPACK_UNEXPECTED_KEY_ERROR CMT_MPACK_UNEXPECTED_KEY_ERROR 37 | #define CMT_DECODE_MSGPACK_UNEXPECTED_DATA_TYPE_ERROR CMT_MPACK_UNEXPECTED_DATA_TYPE_ERROR 38 | 39 | #define CMT_DECODE_MSGPACK_DICTIONARY_LOOKUP_ERROR CMT_MPACK_ERROR_CUTOFF + 1 40 | #define CMT_DECODE_MSGPACK_VERSION_ERROR CMT_MPACK_ERROR_CUTOFF + 2 41 | 42 | struct cmt_msgpack_temporary_bucket { 43 | double upper_bound; 44 | struct cfl_list _head; 45 | }; 46 | 47 | struct cmt_msgpack_decode_context { 48 | struct cmt *cmt; 49 | struct cmt_map *map; 50 | struct cmt_metric *metric; 51 | double *bucket_list; 52 | size_t bucket_count; 53 | double *quantile_list; 54 | size_t quantile_count; 55 | uint64_t *summary_quantiles; 56 | size_t summary_quantiles_count; 57 | int aggregation_type; 58 | }; 59 | 60 | int cmt_decode_msgpack_create(struct cmt **out_cmt, char *in_buf, size_t in_size, 61 | size_t *offset); 62 | void cmt_decode_msgpack_destroy(struct cmt *cmt); 63 | 64 | #endif 65 | -------------------------------------------------------------------------------- /src/cmt_label.c: -------------------------------------------------------------------------------- 1 | /* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ 2 | 3 | /* CMetrics 4 | * ======== 5 | * Copyright 2021-2022 The CMetrics Authors 6 | * 7 | * Licensed under the Apache License, Version 2.0 (the "License"); 8 | * you may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | */ 19 | 20 | #include 21 | #include 22 | 23 | /* 24 | * This interface file provide helper functions to compose a dynamic list 25 | * of custom labels with specific keys and values. Note that this is not 26 | * about labels defined by metrics upon creation, but label lists to be 27 | * used by the encoders when formatting the data. 28 | */ 29 | struct cmt_labels *cmt_labels_create() 30 | { 31 | struct cmt_labels *l; 32 | 33 | l = malloc(sizeof(struct cmt_labels)); 34 | if (!l) { 35 | cmt_errno(); 36 | return NULL; 37 | } 38 | cfl_list_init(&l->list); 39 | return l; 40 | } 41 | 42 | void cmt_labels_destroy(struct cmt_labels *labels) 43 | { 44 | struct cfl_list *tmp; 45 | struct cfl_list *head; 46 | struct cmt_label *l; 47 | 48 | cfl_list_foreach_safe(head, tmp, &labels->list) { 49 | l = cfl_list_entry(head, struct cmt_label, _head); 50 | if (l->key) { 51 | cfl_sds_destroy(l->key); 52 | } 53 | if (l->val) { 54 | cfl_sds_destroy(l->val); 55 | } 56 | cfl_list_del(&l->_head); 57 | free(l); 58 | } 59 | 60 | free(labels); 61 | } 62 | 63 | int cmt_labels_add_kv(struct cmt_labels *labels, char *key, char *val) 64 | { 65 | struct cmt_label *l; 66 | 67 | l = malloc(sizeof(struct cmt_label)); 68 | if (!l) { 69 | cmt_errno(); 70 | return -1; 71 | } 72 | 73 | l->key = cfl_sds_create(key); 74 | if (!l->key) { 75 | free(l); 76 | return -1; 77 | } 78 | 79 | l->val = cfl_sds_create(val); 80 | if (!l->val) { 81 | cfl_sds_destroy(l->key); 82 | free(l); 83 | return -1; 84 | } 85 | 86 | cfl_list_add(&l->_head, &labels->list); 87 | return 0; 88 | } 89 | 90 | int cmt_labels_count(struct cmt_labels *labels) 91 | { 92 | int c = 0; 93 | struct cfl_list *head; 94 | 95 | cfl_list_foreach(head, &labels->list) { 96 | c++; 97 | } 98 | 99 | return c; 100 | } 101 | -------------------------------------------------------------------------------- /src/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | if (CMT_BUILD_PROMETHEUS_TEXT_DECODER) 2 | flex_target(cmt_decode_prometheus_lexer cmt_decode_prometheus.l 3 | "${FLEX_BISON_GENERATED_DIR}/cmt_decode_prometheus_lexer.c" 4 | DEFINES_FILE "${FLEX_BISON_GENERATED_DIR}/cmt_decode_prometheus_lexer.h" 5 | ) 6 | bison_target(cmt_decode_prometheus_parser cmt_decode_prometheus.y 7 | "${FLEX_BISON_GENERATED_DIR}/cmt_decode_prometheus_parser.c") 8 | add_flex_bison_dependency(cmt_decode_prometheus_lexer cmt_decode_prometheus_parser) 9 | endif() 10 | 11 | set(src 12 | cmt_gauge.c 13 | cmt_counter.c 14 | cmt_untyped.c 15 | cmt_summary.c 16 | cmt_histogram.c 17 | cmt_metric.c 18 | cmt_metric_histogram.c 19 | cmt_map.c 20 | cmt_log.c 21 | cmt_opts.c 22 | cmt_time.c 23 | cmt_label.c 24 | cmt_cat.c 25 | cmt_filter.c 26 | cmetrics.c 27 | cmt_encode_opentelemetry.c 28 | cmt_decode_opentelemetry.c 29 | cmt_encode_prometheus.c 30 | cmt_encode_prometheus_remote_write.c 31 | cmt_encode_splunk_hec.c 32 | cmt_encode_cloudwatch_emf.c 33 | cmt_encode_text.c 34 | cmt_encode_influx.c 35 | cmt_encode_msgpack.c 36 | cmt_decode_msgpack.c 37 | cmt_decode_statsd.c 38 | cmt_mpack_utils.c 39 | ) 40 | 41 | # Add Prometheus remote write decoder (always available, only needs protobuf) 42 | set(src ${src} 43 | cmt_decode_prometheus_remote_write.c 44 | # Prometheus related protobuf files 45 | external/remote.pb-c.c 46 | external/types.pb-c.c 47 | ) 48 | 49 | 50 | if (MSVC) 51 | set(PLATFORM_SPECIFIC_ATOMIC_MODULE cmt_atomic_msvc.c) 52 | elseif("${CMAKE_C_COMPILER_ID}" STREQUAL "Clang") 53 | set(PLATFORM_SPECIFIC_ATOMIC_MODULE cmt_atomic_clang.c) 54 | elseif("${CMAKE_C_COMPILER_ID}" MATCHES "AppleClang") 55 | set(PLATFORM_SPECIFIC_ATOMIC_MODULE cmt_atomic_clang.c) 56 | elseif("${CMAKE_C_COMPILER_ID}" STREQUAL "GNU") 57 | set(PLATFORM_SPECIFIC_ATOMIC_MODULE cmt_atomic_gcc.c) 58 | else() 59 | set(PLATFORM_SPECIFIC_ATOMIC_MODULE cmt_atomic_generic.c) 60 | endif() 61 | 62 | message(STATUS "Compiler: ${CMAKE_C_COMPILER_ID}, Platform: ${CMAKE_SYSTEM_NAME}") 63 | 64 | set(src 65 | ${src} 66 | ${PLATFORM_SPECIFIC_ATOMIC_MODULE} 67 | ) 68 | 69 | if (CMT_BUILD_PROMETHEUS_TEXT_DECODER) 70 | set(src ${src} 71 | ${FLEX_cmt_decode_prometheus_lexer_OUTPUTS} 72 | ${BISON_cmt_decode_prometheus_parser_OUTPUTS} 73 | ) 74 | endif() 75 | 76 | # Static Library 77 | add_library(cmetrics-static STATIC ${src}) 78 | target_link_libraries(cmetrics-static mpack-static cfl-static fluent-otel-proto) 79 | 80 | # Install Library 81 | if(MSVC) 82 | # Rename the output for Windows environment to avoid naming issues 83 | set_target_properties(cmetrics-static PROPERTIES OUTPUT_NAME libcmetrics) 84 | else() 85 | set_target_properties(cmetrics-static PROPERTIES OUTPUT_NAME cmetrics) 86 | endif(MSVC) 87 | 88 | install(TARGETS cmetrics-static 89 | RUNTIME DESTINATION ${CMT_INSTALL_BINDIR} 90 | LIBRARY DESTINATION ${CMT_INSTALL_LIBDIR} 91 | ARCHIVE DESTINATION ${CMT_INSTALL_LIBDIR} 92 | COMPONENT library) 93 | -------------------------------------------------------------------------------- /include/cmetrics/cmt_histogram.h: -------------------------------------------------------------------------------- 1 | /* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ 2 | 3 | /* CMetrics 4 | * ======== 5 | * Copyright 2021-2022 The CMetrics Authors 6 | * 7 | * Licensed under the Apache License, Version 2.0 (the "License"); 8 | * you may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | */ 19 | 20 | #ifndef CMT_HISTOGRAM_H 21 | #define CMT_HISTOGRAM_H 22 | 23 | #include 24 | #include 25 | 26 | struct cmt_histogram_buckets { 27 | size_t count; 28 | double *upper_bounds; 29 | }; 30 | 31 | struct cmt_histogram { 32 | struct cmt_histogram_buckets *buckets; 33 | struct cmt_opts opts; 34 | struct cmt_map *map; 35 | struct cfl_list _head; 36 | struct cmt *cmt; 37 | int aggregation_type; 38 | }; 39 | 40 | /* Buckets */ 41 | struct cmt_histogram_buckets *cmt_histogram_buckets_create_size(double *bkts, size_t count); 42 | struct cmt_histogram_buckets *cmt_histogram_buckets_create(size_t count, ...); 43 | void cmt_histogram_buckets_destroy(struct cmt_histogram_buckets *buckets); 44 | 45 | struct cmt_histogram_buckets *cmt_histogram_buckets_default_create(); 46 | struct cmt_histogram_buckets *cmt_histogram_buckets_linear_create(double start, 47 | double width, 48 | size_t count); 49 | struct cmt_histogram_buckets *cmt_histogram_buckets_exponential_create(double start, 50 | double factor, 51 | size_t count); 52 | /* Histogram */ 53 | struct cmt_histogram *cmt_histogram_create(struct cmt *cmt, 54 | char *ns, char *subsystem, 55 | char *name, char *help, 56 | struct cmt_histogram_buckets *buckets, 57 | int label_count, char **label_keys); 58 | 59 | int cmt_histogram_observe(struct cmt_histogram *histogram, uint64_t timestamp, 60 | double val, int labels_count, char **label_vals); 61 | 62 | int cmt_histogram_set_default(struct cmt_histogram *histogram, 63 | uint64_t timestamp, 64 | uint64_t *bucket_defaults, 65 | double sum, 66 | uint64_t count, 67 | int labels_count, char **label_vals); 68 | 69 | int cmt_histogram_destroy(struct cmt_histogram *h); 70 | 71 | #endif 72 | -------------------------------------------------------------------------------- /include/cmetrics/cmt_metric.h: -------------------------------------------------------------------------------- 1 | /* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ 2 | 3 | /* CMetrics 4 | * ======== 5 | * Copyright 2021-2022 The CMetrics Authors 6 | * 7 | * Licensed under the Apache License, Version 2.0 (the "License"); 8 | * you may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | */ 19 | 20 | #ifndef CMT_METRIC_H 21 | #define CMT_METRIC_H 22 | 23 | #include 24 | 25 | struct cmt_metric { 26 | /* counters and gauges */ 27 | uint64_t val; 28 | 29 | /* histogram */ 30 | uint64_t *hist_buckets; 31 | uint64_t hist_count; 32 | uint64_t hist_sum; 33 | 34 | /* summary */ 35 | int sum_quantiles_set; /* specify if quantive values has been set */ 36 | uint64_t *sum_quantiles; /* 0, 0.25, 0.5, 0.75 and 1 */ 37 | size_t sum_quantiles_count; 38 | uint64_t sum_count; 39 | uint64_t sum_sum; 40 | 41 | /* internal */ 42 | uint64_t hash; 43 | uint64_t timestamp; 44 | struct cfl_list labels; 45 | struct cfl_list _head; 46 | }; 47 | 48 | void cmt_metric_set(struct cmt_metric *metric, uint64_t timestamp, double val); 49 | void cmt_metric_inc(struct cmt_metric *metric, uint64_t timestamp); 50 | void cmt_metric_dec(struct cmt_metric *metric, uint64_t timestamp); 51 | void cmt_metric_add(struct cmt_metric *metric, uint64_t timestamp, double val); 52 | void cmt_metric_sub(struct cmt_metric *metric, uint64_t timestamp, double val); 53 | double cmt_metric_get_value(struct cmt_metric *metric); 54 | uint64_t cmt_metric_get_timestamp(struct cmt_metric *metric); 55 | 56 | void cmt_metric_hist_inc(struct cmt_metric *metric, uint64_t timestamp, 57 | int bucket_id); 58 | 59 | void cmt_metric_hist_count_inc(struct cmt_metric *metric, uint64_t timestamp); 60 | void cmt_metric_hist_count_set(struct cmt_metric *metric, uint64_t timestamp, 61 | uint64_t count); 62 | 63 | void cmt_metric_hist_sum_add(struct cmt_metric *metric, uint64_t timestamp, 64 | double val); 65 | void cmt_metric_hist_set(struct cmt_metric *metric, uint64_t timestamp, 66 | int bucket_id, double val); 67 | 68 | uint64_t cmt_metric_hist_get_value(struct cmt_metric *metric, int bucket_id); 69 | 70 | double cmt_metric_hist_get_sum_value(struct cmt_metric *metric); 71 | 72 | uint64_t cmt_metric_hist_get_count_value(struct cmt_metric *metric); 73 | 74 | void cmt_metric_hist_sum_add(struct cmt_metric *metric, 75 | uint64_t timestamp, double val); 76 | void cmt_metric_hist_sum_set(struct cmt_metric *metric, uint64_t timestamp, 77 | double val); 78 | 79 | #endif 80 | -------------------------------------------------------------------------------- /src/cmt_decode_prometheus.y: -------------------------------------------------------------------------------- 1 | %define api.pure true 2 | %name-prefix "cmt_decode_prometheus_" 3 | %define parse.error verbose 4 | 5 | %param {void *yyscanner} 6 | %param {struct cmt_decode_prometheus_context *context} 7 | 8 | %{ 9 | // we inline cmt_decode_prometheus.c which contains all the actions to avoid 10 | // having to export a bunch of symbols that are only used by the generated 11 | // parser code 12 | #include "cmt_decode_prometheus.c" 13 | %} 14 | 15 | %union { 16 | cfl_sds_t str; 17 | char numstr[64]; 18 | int integer; 19 | } 20 | 21 | %token '=' '{' '}' ',' 22 | %token IDENTIFIER QUOTED HELP TYPE METRIC_DOC 23 | %token COUNTER GAUGE SUMMARY UNTYPED HISTOGRAM 24 | %token START_HEADER START_LABELS START_SAMPLES 25 | %token NUMSTR INFNAN 26 | 27 | %type metric_type 28 | %type value 29 | 30 | %destructor { 31 | cfl_sds_destroy($$); 32 | } 33 | 34 | %start start; 35 | 36 | %% 37 | 38 | start: 39 | START_HEADER header 40 | | START_LABELS labels 41 | | START_SAMPLES samples 42 | | metrics { 43 | if (finish_metric(context, true, NULL)) { 44 | YYABORT; 45 | } 46 | } 47 | ; 48 | 49 | metrics: 50 | metrics metric 51 | | metric 52 | ; 53 | 54 | metric: 55 | header samples 56 | | samples 57 | | header 58 | ; 59 | 60 | header: 61 | help type 62 | | help 63 | | type help 64 | | type 65 | ; 66 | 67 | help: 68 | HELP METRIC_DOC { 69 | if (parse_metric_name(context, $1)) { 70 | YYABORT; 71 | } 72 | context->metric.docstring = $2; 73 | } 74 | ; 75 | 76 | type: 77 | TYPE metric_type { 78 | if (parse_metric_name(context, $1)) { 79 | YYABORT; 80 | } 81 | context->metric.type = $2; 82 | } 83 | ; 84 | 85 | metric_type: 86 | COUNTER { $$ = COUNTER; } 87 | | GAUGE { $$ = GAUGE; } 88 | | SUMMARY { $$ = SUMMARY; } 89 | | UNTYPED { $$ = UNTYPED; } 90 | | HISTOGRAM { $$ = HISTOGRAM; } 91 | ; 92 | 93 | samples: 94 | samples sample 95 | | sample 96 | ; 97 | 98 | sample: 99 | IDENTIFIER { 100 | if (parse_metric_name(context, $1)) { 101 | YYABORT; 102 | } 103 | $1 = NULL; 104 | if (sample_start(context)) { 105 | YYABORT; 106 | } 107 | } sample_data 108 | ; 109 | 110 | sample_data: 111 | '{' '}' values 112 | | '{' labels '}' values 113 | | values 114 | ; 115 | 116 | labels: 117 | labellist ',' 118 | | labellist 119 | ; 120 | 121 | labellist: 122 | labellist ',' label 123 | | label 124 | ; 125 | 126 | label: 127 | IDENTIFIER '=' QUOTED { 128 | if (parse_label(context, $1, $3)) { 129 | YYABORT; 130 | } 131 | } 132 | ; 133 | 134 | values: 135 | value value { 136 | if (parse_sample(context, $1, $2)) { 137 | YYABORT; 138 | } 139 | } 140 | | value { 141 | if (parse_sample(context, $1, "")) { 142 | YYABORT; 143 | } 144 | } 145 | ; 146 | 147 | value: 148 | NUMSTR | INFNAN 149 | ; 150 | 151 | %% 152 | -------------------------------------------------------------------------------- /src/cmt_opts.c: -------------------------------------------------------------------------------- 1 | /* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ 2 | 3 | /* CMetrics 4 | * ======== 5 | * Copyright 2021-2022 The CMetrics Authors 6 | * 7 | * Licensed under the Apache License, Version 2.0 (the "License"); 8 | * you may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | */ 19 | 20 | #include 21 | #include 22 | 23 | /* Initialize an 'opts' context with given values */ 24 | int cmt_opts_init(struct cmt_opts *opts, 25 | char *ns, char *subsystem, char *name, 26 | char *description) 27 | { 28 | int len; 29 | cfl_sds_t tmp; 30 | 31 | if (!name) { 32 | return -1; 33 | } 34 | 35 | if (ns) { 36 | opts->ns = cfl_sds_create(ns); 37 | if (!opts->ns) { 38 | return -1; 39 | } 40 | 41 | opts->fqname = cfl_sds_create(ns); 42 | if (!opts->fqname) { 43 | return -1; 44 | } 45 | 46 | if (strlen(ns) > 0) { 47 | tmp = cfl_sds_cat(opts->fqname, "_", 1); 48 | if (!tmp) { 49 | return -1; 50 | } 51 | 52 | opts->fqname = tmp; 53 | } 54 | } 55 | 56 | if (subsystem) { 57 | opts->subsystem = cfl_sds_create(subsystem); 58 | if (!opts->subsystem) { 59 | return -1; 60 | } 61 | 62 | if (strlen(opts->subsystem) > 0) { 63 | tmp = cfl_sds_cat(opts->fqname, 64 | opts->subsystem, cfl_sds_len(opts->subsystem)); 65 | if (!tmp) { 66 | return -1; 67 | } 68 | opts->fqname = tmp; 69 | 70 | len = cfl_sds_len(opts->fqname); 71 | if (opts->fqname[len - 1] != '_') { 72 | tmp = cfl_sds_cat(opts->fqname, "_", 1); 73 | if (!tmp) { 74 | return -1; 75 | } 76 | opts->fqname = tmp; 77 | } 78 | } 79 | } 80 | 81 | opts->name = cfl_sds_create(name); 82 | opts->description = cfl_sds_create(description); 83 | 84 | if (!opts->name || !opts->description) { 85 | return -1; 86 | } 87 | 88 | tmp = cfl_sds_cat(opts->fqname, opts->name, cfl_sds_len(opts->name)); 89 | if (!tmp) { 90 | return -1; 91 | } 92 | opts->fqname = tmp; 93 | 94 | return 0; 95 | } 96 | 97 | void cmt_opts_exit(struct cmt_opts *opts) 98 | { 99 | if (opts->ns) { 100 | cfl_sds_destroy(opts->ns); 101 | } 102 | 103 | if (opts->subsystem) { 104 | cfl_sds_destroy(opts->subsystem); 105 | } 106 | 107 | if (opts->name) { 108 | cfl_sds_destroy(opts->name); 109 | } 110 | 111 | if (opts->description) { 112 | cfl_sds_destroy(opts->description); 113 | } 114 | 115 | if (opts->fqname) { 116 | cfl_sds_destroy(opts->fqname); 117 | } 118 | } 119 | -------------------------------------------------------------------------------- /tests/atomic_operations.c: -------------------------------------------------------------------------------- 1 | /* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ 2 | 3 | /* CMetrics 4 | * ======== 5 | * Copyright 2021-2022 The CMetrics Authors 6 | * 7 | * Licensed under the Apache License, Version 2.0 (the "License"); 8 | * you may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | */ 19 | 20 | #include 21 | #include 22 | 23 | #if defined (_WIN32) || defined (_WIN64) 24 | #include 25 | #else 26 | #include 27 | #endif 28 | 29 | #include "cmt_tests.h" 30 | 31 | #define THREAD_COUNT 100 32 | #define CYCLE_COUNT 10000 33 | #define EXPECTED_VALUE (THREAD_COUNT * CYCLE_COUNT) 34 | 35 | uint64_t global_counter; 36 | 37 | static inline void add_through_compare_exchange(uint64_t val) 38 | { 39 | uint64_t old; 40 | uint64_t new; 41 | int result; 42 | 43 | do { 44 | old = global_counter; 45 | new = old + val; 46 | 47 | result = cmt_atomic_compare_exchange(&global_counter, old, new); 48 | } 49 | while(0 == result); 50 | } 51 | 52 | void *worker_thread_add_through_compare_exchange(void *ptr) 53 | { 54 | int local_counter; 55 | 56 | for (local_counter = 0 ; local_counter < CYCLE_COUNT ; local_counter++) { 57 | add_through_compare_exchange(1); 58 | } 59 | 60 | return NULL; 61 | } 62 | 63 | #if defined (_WIN32) || defined (_WIN64) 64 | 65 | void test_atomic_operations() 66 | { 67 | HANDLE threads[THREAD_COUNT]; 68 | DWORD thread_ids[THREAD_COUNT]; 69 | int thread_index; 70 | DWORD result; 71 | 72 | cmt_initialize(); 73 | 74 | global_counter = 0; 75 | 76 | for(thread_index = 0 ; thread_index < THREAD_COUNT ; thread_index++) 77 | { 78 | threads[thread_index] = CreateThread(NULL, 0, 79 | (LPTHREAD_START_ROUTINE) worker_thread_add_through_compare_exchange, 80 | NULL, 0, &thread_ids[thread_index]); 81 | } 82 | 83 | for(thread_index = 0 ; thread_index < THREAD_COUNT ; thread_index++) 84 | { 85 | result = WaitForSingleObject(threads[thread_index], INFINITE); 86 | } 87 | 88 | TEST_CHECK(global_counter == EXPECTED_VALUE); 89 | } 90 | 91 | #else 92 | 93 | void test_atomic_operations() 94 | { 95 | pthread_t threads[THREAD_COUNT]; 96 | int thread_index; 97 | 98 | cmt_initialize(); 99 | 100 | global_counter = 0; 101 | 102 | for(thread_index = 0 ; thread_index < THREAD_COUNT ; thread_index++) 103 | { 104 | pthread_create(&threads[thread_index], NULL, 105 | worker_thread_add_through_compare_exchange, NULL); 106 | } 107 | 108 | for(thread_index = 0 ; thread_index < THREAD_COUNT ; thread_index++) 109 | { 110 | pthread_join(threads[thread_index], NULL); 111 | } 112 | 113 | TEST_CHECK(global_counter == EXPECTED_VALUE); 114 | } 115 | #endif 116 | 117 | TEST_LIST = { 118 | {"atomic_operations", test_atomic_operations}, 119 | { 0 } 120 | }; 121 | -------------------------------------------------------------------------------- /tests/untyped.c: -------------------------------------------------------------------------------- 1 | /* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ 2 | 3 | /* CMetrics 4 | * ======== 5 | * Copyright 2021-2022 The CMetrics Authors 6 | * 7 | * Licensed under the Apache License, Version 2.0 (the "License"); 8 | * you may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | */ 19 | 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | 28 | #include "cmt_tests.h" 29 | 30 | static struct cmt *generate_encoder_test_data() 31 | { 32 | int ret; 33 | double val; 34 | uint64_t ts; 35 | struct cmt *cmt; 36 | struct cmt_untyped *u; 37 | 38 | printf("version: %s\n\n", cmt_version()); 39 | cmt = cmt_create(); 40 | 41 | u = cmt_untyped_create(cmt, "kubernetes", "network", "load", "Network load", 42 | 2, (char *[]) {"hostname", "app"}); 43 | 44 | ts = cfl_time_now(); 45 | 46 | ret = cmt_untyped_get_val(u, 0, NULL, &val); 47 | TEST_CHECK(ret == -1); 48 | 49 | cmt_untyped_set(u, ts, 2, 0, NULL); 50 | cmt_untyped_get_val(u, 0, NULL, &val); 51 | TEST_CHECK(val == 2.0); 52 | 53 | cmt_untyped_get_val(u, 2, (char *[]) {"localhost", "cmetrics"}, &val); 54 | cmt_untyped_get_val(u, 2, (char *[]) {"localhost", "test"}, &val); 55 | cmt_untyped_set(u, ts, 12.15, 2, (char *[]) {"localhost", "test"}); 56 | cmt_untyped_set(u, ts, 1, 2, (char *[]) {"localhost", "test"}); 57 | 58 | return cmt; 59 | } 60 | 61 | void test_prometheus() 62 | { 63 | struct cmt *cmt = NULL; 64 | cfl_sds_t prom = NULL; 65 | 66 | cmt_initialize(); 67 | 68 | cmt = generate_encoder_test_data(); 69 | TEST_CHECK(cmt != NULL); 70 | 71 | prom = cmt_encode_prometheus_create(cmt, CMT_TRUE); 72 | TEST_CHECK(prom != NULL); 73 | printf("%s\n", prom); 74 | 75 | cmt_encode_prometheus_destroy(prom); 76 | cmt_destroy(cmt); 77 | } 78 | 79 | void test_text() 80 | { 81 | struct cmt *cmt = NULL; 82 | cfl_sds_t text = NULL; 83 | 84 | cmt_initialize(); 85 | 86 | cmt = generate_encoder_test_data(); 87 | TEST_CHECK(cmt != NULL); 88 | 89 | text = cmt_encode_text_create(cmt); 90 | TEST_CHECK(text != NULL); 91 | 92 | printf("%s\n", text); 93 | 94 | cmt_encode_text_destroy(text); 95 | cmt_destroy(cmt); 96 | } 97 | 98 | void test_influx() 99 | { 100 | struct cmt *cmt = NULL; 101 | cfl_sds_t text = NULL; 102 | 103 | cmt_initialize(); 104 | 105 | cmt = generate_encoder_test_data(); 106 | TEST_CHECK(cmt != NULL); 107 | 108 | text = cmt_encode_influx_create(cmt); 109 | TEST_CHECK(text != NULL); 110 | 111 | printf("%s\n", text); 112 | 113 | cmt_encode_influx_destroy(text); 114 | cmt_destroy(cmt); 115 | } 116 | 117 | TEST_LIST = { 118 | {"prometheus", test_prometheus}, 119 | {"text" , test_text}, 120 | {"influx" , test_influx}, 121 | { 0 } 122 | }; 123 | -------------------------------------------------------------------------------- /src/cmt_atomic_generic.c: -------------------------------------------------------------------------------- 1 | /* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ 2 | 3 | /* CMetrics 4 | * ======== 5 | * Copyright 2021-2022 The CMetrics Authors 6 | * 7 | * Licensed under the Apache License, Version 2.0 (the "License"); 8 | * you may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | */ 19 | 20 | #include 21 | #include 22 | #include 23 | #include 24 | 25 | pthread_mutex_t atomic_operation_lock; 26 | static int atomic_operation_system_initialized = 0; 27 | 28 | /* TODO: Determne if we want to keep this backend as well as how / if we want to handle 29 | * pthread_mutex_unlock errors (investigate and understand what could cause them), 30 | * as well as pthread_mutex_lock (determine if we want to apply some sort of retry 31 | * limit there as well) 32 | * 33 | */ 34 | 35 | inline int cmt_atomic_initialize() 36 | { 37 | int result; 38 | 39 | if (0 == atomic_operation_system_initialized) { 40 | result = pthread_mutex_init(&atomic_operation_lock, NULL); 41 | 42 | if (0 != result) { 43 | return 1; 44 | } 45 | 46 | atomic_operation_system_initialized = 1; 47 | } 48 | 49 | return 0; 50 | } 51 | 52 | inline int cmt_atomic_compare_exchange(uint64_t *storage, 53 | uint64_t old_value, uint64_t new_value) 54 | { 55 | int result; 56 | 57 | if (0 == atomic_operation_system_initialized) { 58 | printf("CMT ATOMIC : Atomic operation backend not initalized\n"); 59 | exit(1); 60 | } 61 | 62 | result = pthread_mutex_lock(&atomic_operation_lock); 63 | 64 | if (result != 0) { 65 | return 0; 66 | } 67 | 68 | if (*storage == old_value) { 69 | *storage = new_value; 70 | 71 | result = 1; 72 | } 73 | else { 74 | result = 0; 75 | } 76 | 77 | pthread_mutex_unlock(&atomic_operation_lock); 78 | 79 | return result; 80 | } 81 | 82 | inline void cmt_atomic_store(uint64_t *storage, uint64_t new_value) 83 | { 84 | int result; 85 | 86 | if (0 == atomic_operation_system_initialized) { 87 | printf("CMT ATOMIC : Atomic operation backend not initalized\n"); 88 | exit(1); 89 | } 90 | 91 | result = pthread_mutex_lock(&atomic_operation_lock); 92 | 93 | if (result != 0) { 94 | /* We should notify the user somehow */ 95 | } 96 | 97 | *storage = new_value; 98 | 99 | pthread_mutex_unlock(&atomic_operation_lock); 100 | } 101 | 102 | inline uint64_t cmt_atomic_load(uint64_t *storage) 103 | { 104 | int result; 105 | uint64_t retval; 106 | 107 | if (0 == atomic_operation_system_initialized) { 108 | printf("CMT ATOMIC : Atomic operation backend not initalized\n"); 109 | exit(1); 110 | } 111 | 112 | result = pthread_mutex_lock(&atomic_operation_lock); 113 | 114 | if (result != 0) { 115 | /* We should notify the user somehow */ 116 | } 117 | 118 | retval = *storage; 119 | 120 | pthread_mutex_unlock(&atomic_operation_lock); 121 | 122 | return retval; 123 | } 124 | -------------------------------------------------------------------------------- /src/cmt_atomic_msvc.c: -------------------------------------------------------------------------------- 1 | /* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ 2 | 3 | /* CMetrics 4 | * ======== 5 | * Copyright 2021-2022 The CMetrics Authors 6 | * 7 | * Licensed under the Apache License, Version 2.0 (the "License"); 8 | * you may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | */ 19 | 20 | #include 21 | #include 22 | 23 | /* This allows cmt_atomic_initialize to be automatically called 24 | * as soon as the program starts if enabled. 25 | */ 26 | 27 | #ifndef _WIN64 28 | CRITICAL_SECTION atomic_operation_lock; 29 | static int atomic_operation_system_initialized = 0; 30 | 31 | int cmt_atomic_initialize() 32 | { 33 | if (0 == atomic_operation_system_initialized) { 34 | InitializeCriticalSection(&atomic_operation_lock); 35 | 36 | atomic_operation_system_initialized = 1; 37 | } 38 | 39 | return 0; 40 | } 41 | 42 | int cmt_atomic_compare_exchange(uint64_t *storage, 43 | uint64_t old_value, uint64_t new_value) 44 | { 45 | uint64_t result; 46 | 47 | if (0 == atomic_operation_system_initialized) { 48 | printf("CMT ATOMIC : Atomic operation backend not initalized\n"); 49 | exit(1); 50 | } 51 | 52 | EnterCriticalSection(&atomic_operation_lock); 53 | 54 | if (*storage == old_value) { 55 | *storage = new_value; 56 | 57 | result = 1; 58 | } 59 | else { 60 | result = 0; 61 | } 62 | 63 | LeaveCriticalSection(&atomic_operation_lock); 64 | 65 | return result; 66 | } 67 | 68 | void cmt_atomic_store(uint64_t *storage, uint64_t new_value) 69 | { 70 | if (0 == atomic_operation_system_initialized) { 71 | printf("CMT ATOMIC : Atomic operation backend not initalized\n"); 72 | exit(1); 73 | } 74 | 75 | EnterCriticalSection(&atomic_operation_lock); 76 | 77 | *storage = new_value; 78 | 79 | LeaveCriticalSection(&atomic_operation_lock); 80 | } 81 | 82 | uint64_t cmt_atomic_load(uint64_t *storage) 83 | { 84 | uint64_t result; 85 | 86 | if (0 == atomic_operation_system_initialized) { 87 | printf("CMT ATOMIC : Atomic operation backend not initalized\n"); 88 | exit(1); 89 | } 90 | 91 | EnterCriticalSection(&atomic_operation_lock); 92 | 93 | result = *storage; 94 | 95 | LeaveCriticalSection(&atomic_operation_lock); 96 | 97 | return result; 98 | } 99 | 100 | #else /* _WIN64 */ 101 | 102 | int cmt_atomic_initialize() 103 | { 104 | return 0; 105 | } 106 | 107 | int cmt_atomic_compare_exchange(uint64_t *storage, 108 | uint64_t old_value, uint64_t new_value) 109 | { 110 | uint64_t result; 111 | 112 | result = _InterlockedCompareExchange64(storage, new_value, old_value); 113 | 114 | if (result != old_value) { 115 | return 0; 116 | } 117 | 118 | return 1; 119 | } 120 | 121 | void cmt_atomic_store(uint64_t *storage, uint64_t new_value) 122 | { 123 | _InterlockedExchange64(storage, new_value); 124 | } 125 | 126 | uint64_t cmt_atomic_load(uint64_t *storage) 127 | { 128 | return _InterlockedOr64(storage, 0); 129 | } 130 | 131 | #endif 132 | -------------------------------------------------------------------------------- /include/cmetrics/cmt_decode_prometheus.h: -------------------------------------------------------------------------------- 1 | /* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ 2 | 3 | /* CMetrics 4 | * ======== 5 | * Copyright 2021-2022 The CMetrics Authors 6 | * 7 | * Licensed under the Apache License, Version 2.0 (the "License"); 8 | * you may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | */ 19 | 20 | #ifndef CMT_DECODE_PROMETHEUS_H 21 | #define CMT_DECODE_PROMETHEUS_H 22 | 23 | #include 24 | 25 | #ifdef CMT_HAVE_PROMETHEUS_TEXT_DECODER 26 | 27 | #include 28 | 29 | #include 30 | #include 31 | 32 | #define CMT_DECODE_PROMETHEUS_SUCCESS 0 33 | #define CMT_DECODE_PROMETHEUS_SYNTAX_ERROR 1 34 | #define CMT_DECODE_PROMETHEUS_ALLOCATION_ERROR 10 35 | #define CMT_DECODE_PROMETHEUS_MAX_LABEL_COUNT_EXCEEDED 30 36 | #define CMT_DECODE_PROMETHEUS_CMT_SET_ERROR 40 37 | #define CMT_DECODE_PROMETHEUS_CMT_CREATE_ERROR 50 38 | #define CMT_DECODE_PROMETHEUS_PARSE_VALUE_FAILED 60 39 | #define CMT_DECODE_PROMETHEUS_PARSE_TIMESTAMP_FAILED 70 40 | #define CMT_DECODE_PROMETHEUS_SAMPLE_VALUE_TOO_LONG 80 41 | 42 | #define CMT_DECODE_PROMETHEUS_MAX_LABEL_COUNT 128 43 | 44 | enum cmt_decode_prometheus_context_sample_type { 45 | CMT_DECODE_PROMETHEUS_CONTEXT_SAMPLE_TYPE_NORMAL = 0, 46 | CMT_DECODE_PROMETHEUS_CONTEXT_SAMPLE_TYPE_BUCKET = 1, 47 | CMT_DECODE_PROMETHEUS_CONTEXT_SAMPLE_TYPE_SUM = 2, 48 | CMT_DECODE_PROMETHEUS_CONTEXT_SAMPLE_TYPE_COUNT = 3 49 | }; 50 | 51 | struct cmt_decode_prometheus_context_sample { 52 | char value1[64]; 53 | char value2[64]; 54 | int type; 55 | cfl_sds_t label_values[CMT_DECODE_PROMETHEUS_MAX_LABEL_COUNT]; 56 | 57 | struct cfl_list _head; 58 | }; 59 | 60 | struct cmt_decode_prometheus_context_metric { 61 | cfl_sds_t name_orig; 62 | char *ns; 63 | char *subsystem; 64 | char *name; 65 | int type; 66 | int current_sample_type; 67 | cfl_sds_t docstring; 68 | size_t label_count; 69 | cfl_sds_t labels[CMT_DECODE_PROMETHEUS_MAX_LABEL_COUNT]; 70 | struct cfl_list samples; 71 | }; 72 | 73 | struct cmt_decode_prometheus_parse_opts { 74 | int start_token; 75 | uint64_t default_timestamp; 76 | uint64_t override_timestamp; 77 | char *errbuf; 78 | size_t errbuf_size; 79 | }; 80 | 81 | struct cmt_decode_prometheus_context { 82 | union { 83 | struct cmt_summary *summary; 84 | struct cmt_histogram *histogram; 85 | } current; 86 | struct cmt *cmt; 87 | struct cmt_decode_prometheus_parse_opts opts; 88 | int errcode; 89 | cfl_sds_t strbuf; 90 | struct cmt_decode_prometheus_context_metric metric; 91 | }; 92 | 93 | #define LEX_DECL int cmt_decode_prometheus_lex \ 94 | (YYSTYPE * yylval_param, \ 95 | void* yyscanner, \ 96 | struct cmt_decode_prometheus_context *context) 97 | 98 | #define YY_DECL LEX_DECL 99 | 100 | #include "cmt_decode_prometheus_parser.h" 101 | 102 | #ifndef FLEX_SCANNER 103 | // lexer header should not be included in the generated lexer c file, 104 | // which defines FLEX_SCANNER 105 | #include "cmt_decode_prometheus_lexer.h" 106 | #endif 107 | 108 | LEX_DECL; /* Declear as an entity of yylex function declaration. */ 109 | 110 | int cmt_decode_prometheus_create( 111 | struct cmt **out_cmt, 112 | const char *in_buf, 113 | size_t in_size, 114 | struct cmt_decode_prometheus_parse_opts *opts); 115 | void cmt_decode_prometheus_destroy(struct cmt *cmt); 116 | 117 | #endif /* CMT_HAVE_PROMETHEUS_TEXT_DECODER */ 118 | 119 | #endif 120 | -------------------------------------------------------------------------------- /.github/workflows/packages.yaml: -------------------------------------------------------------------------------- 1 | name: Build packages for master or a tagged release 2 | 3 | on: 4 | push: 5 | branches: 6 | - master 7 | # Any tag starting with 'v' 8 | tags: 9 | - 'v*' 10 | workflow_dispatch: 11 | 12 | jobs: 13 | build-distro-packages-arm64: 14 | runs-on: ubuntu-latest 15 | name: build arm64 packages 16 | strategy: 17 | fail-fast: true 18 | matrix: 19 | format: [ rpm, deb ] 20 | steps: 21 | - uses: actions/checkout@v6 22 | with: 23 | submodules: true 24 | 25 | - uses: uraimo/run-on-arch-action@v3.0.1 26 | name: Build the ${{matrix.format}} packages 27 | with: 28 | arch: aarch64 29 | distro: ubuntu_latest 30 | run: | 31 | apt-get update && \ 32 | apt-get install -y --no-install-recommends \ 33 | build-essential \ 34 | cmake \ 35 | file \ 36 | rpm \ 37 | make 38 | cmake . 39 | echo ${{ matrix.format }} | awk '{print toupper($0)}' | xargs -I{} cpack -G {} 40 | 41 | - name: Store the master package artifacts 42 | uses: actions/upload-artifact@v6 43 | with: 44 | name: ${{ matrix.format }}-arm64 45 | path: | 46 | ./*.${{matrix.format}} 47 | 48 | build-distro-packages-amd64: 49 | name: build amd64 packages 50 | strategy: 51 | fail-fast: true 52 | matrix: 53 | format: [ rpm, deb ] 54 | 55 | runs-on: [ ubuntu-latest ] 56 | steps: 57 | - uses: actions/checkout@v6 58 | with: 59 | submodules: true 60 | 61 | - name: Build the ${{matrix.format}} packages 62 | run: | 63 | cmake . 64 | echo ${{ matrix.format }} | awk '{print toupper($0)}' | xargs -I{} cpack -G {} 65 | 66 | - name: Store the master package artifacts 67 | uses: actions/upload-artifact@v6 68 | with: 69 | name: ${{ matrix.format }}-amd64 70 | path: | 71 | ./*.${{matrix.format}} 72 | 73 | build-macos-packages-arm64: 74 | name: build macOS Apple Silicon packages 75 | strategy: 76 | fail-fast: true 77 | matrix: 78 | config: 79 | - format: productbuild 80 | arch: apple 81 | ext: pkg 82 | runs-on: macos-14 83 | steps: 84 | - uses: actions/checkout@v6 85 | with: 86 | submodules: true 87 | 88 | - name: Build the ${{matrix.config.format}} packages 89 | run: | 90 | cmake . -DCPACK_GENERATOR=${{ matrix.config.format }} 91 | echo ${{ matrix.config.format }} | xargs -I{} cpack -G {} 92 | 93 | - name: Store the master package artifacts 94 | uses: actions/upload-artifact@v6 95 | with: 96 | name: ${{ matrix.config.format }}-${{matrix.config.arch}} 97 | path: | 98 | ./*-${{matrix.config.arch}}.${{matrix.config.ext}} 99 | 100 | release: 101 | name: Create release and upload packages 102 | needs: 103 | - build-distro-packages-amd64 104 | - build-distro-packages-arm64 105 | - build-macos-packages-arm64 106 | 107 | runs-on: ubuntu-latest 108 | permissions: 109 | contents: write 110 | steps: 111 | - name: Download all artefacts 112 | uses: actions/download-artifact@v7 113 | with: 114 | path: artifacts/ 115 | 116 | - name: Display structure of downloaded files 117 | run: ls -R 118 | working-directory: artifacts 119 | shell: bash 120 | 121 | - name: Unstable release on push to master to make it easier to download 122 | uses: pyTooling/Actions/releaser@r0 123 | continue-on-error: true 124 | with: 125 | token: ${{ secrets.GITHUB_TOKEN }} 126 | tag: 'unstable' 127 | rm: true 128 | files: | 129 | artifacts/**/* 130 | 131 | - name: Release on tag 132 | uses: softprops/action-gh-release@v2 133 | if: startsWith(github.ref, 'refs/tags/') 134 | with: 135 | generate_release_notes: true 136 | files: | 137 | artifacts/**/* 138 | -------------------------------------------------------------------------------- /src/cmt_metric.c: -------------------------------------------------------------------------------- 1 | /* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ 2 | 3 | /* CMetrics 4 | * ======== 5 | * Copyright 2021-2022 The CMetrics Authors 6 | * 7 | * Licensed under the Apache License, Version 2.0 (the "License"); 8 | * you may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | */ 19 | 20 | #include 21 | #include 22 | #include 23 | #include 24 | 25 | static inline int metric_exchange(struct cmt_metric *metric, uint64_t timestamp, 26 | double new_value, double old_value) 27 | { 28 | uint64_t tmp_new; 29 | uint64_t tmp_old; 30 | int result; 31 | 32 | tmp_new = cmt_math_d64_to_uint64(new_value); 33 | tmp_old = cmt_math_d64_to_uint64(old_value); 34 | 35 | result = cmt_atomic_compare_exchange(&metric->val, tmp_old, tmp_new); 36 | 37 | if(0 == result) { 38 | return 0; 39 | } 40 | 41 | cmt_atomic_store(&metric->timestamp, timestamp); 42 | 43 | return 1; 44 | } 45 | 46 | static inline void add(struct cmt_metric *metric, uint64_t timestamp, double val) 47 | { 48 | double old; 49 | double new; 50 | int result; 51 | 52 | do { 53 | old = cmt_metric_get_value(metric); 54 | new = old + val; 55 | 56 | result = metric_exchange(metric, timestamp, new, old); 57 | } 58 | while(0 == result); 59 | } 60 | 61 | void cmt_metric_set(struct cmt_metric *metric, uint64_t timestamp, double val) 62 | { 63 | uint64_t tmp; 64 | 65 | tmp = cmt_math_d64_to_uint64(val); 66 | 67 | cmt_atomic_store(&metric->val, tmp); 68 | cmt_atomic_store(&metric->timestamp, timestamp); 69 | } 70 | 71 | static inline int metric_hist_exchange(struct cmt_metric *metric, 72 | uint64_t timestamp, 73 | int bucket_id, 74 | uint64_t new, uint64_t old) 75 | { 76 | int result; 77 | 78 | result = cmt_atomic_compare_exchange(&metric->hist_buckets[bucket_id], 79 | old, new); 80 | if (result == 0) { 81 | return 0; 82 | } 83 | 84 | cmt_atomic_store(&metric->timestamp, timestamp); 85 | return 1; 86 | } 87 | 88 | void cmt_metric_hist_bucket_inc(struct cmt_metric *metric, uint64_t timestamp, 89 | int bucket_id) 90 | { 91 | int result; 92 | uint64_t old; 93 | uint64_t new; 94 | 95 | do { 96 | old = cmt_atomic_load(&metric->hist_buckets[bucket_id]); 97 | new = old + 1; 98 | result = metric_hist_exchange(metric, timestamp, bucket_id, new, old); 99 | } 100 | while (result == 0); 101 | } 102 | 103 | 104 | void cmt_metric_inc(struct cmt_metric *metric, uint64_t timestamp) 105 | { 106 | add(metric, timestamp, 1); 107 | } 108 | 109 | void cmt_metric_dec(struct cmt_metric *metric, uint64_t timestamp) 110 | { 111 | double volatile val = 1.0; 112 | 113 | add(metric, timestamp, val * -1); 114 | } 115 | 116 | void cmt_metric_add(struct cmt_metric *metric, uint64_t timestamp, double val) 117 | { 118 | add(metric, timestamp, val); 119 | } 120 | 121 | void cmt_metric_sub(struct cmt_metric *metric, uint64_t timestamp, double val) 122 | { 123 | add(metric, timestamp, (double volatile) val * -1); 124 | } 125 | 126 | double cmt_metric_get_value(struct cmt_metric *metric) 127 | { 128 | uint64_t val; 129 | 130 | val = cmt_atomic_load(&metric->val); 131 | 132 | return cmt_math_uint64_to_d64(val); 133 | } 134 | 135 | uint64_t cmt_metric_get_timestamp(struct cmt_metric *metric) 136 | { 137 | uint64_t val; 138 | 139 | val = cmt_atomic_load(&metric->timestamp); 140 | 141 | return val; 142 | } 143 | -------------------------------------------------------------------------------- /src/cmetrics.c: -------------------------------------------------------------------------------- 1 | /* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ 2 | 3 | /* CMetrics 4 | * ======== 5 | * Copyright 2021-2022 The CMetrics Authors 6 | * 7 | * Licensed under the Apache License, Version 2.0 (the "License"); 8 | * you may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | */ 19 | 20 | #include 21 | 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include 33 | 34 | #include 35 | 36 | void cmt_initialize() 37 | { 38 | cmt_atomic_initialize(); 39 | } 40 | 41 | struct cmt *cmt_create() 42 | { 43 | struct cmt *cmt; 44 | 45 | cmt = calloc(1, sizeof(struct cmt)); 46 | if (!cmt) { 47 | cmt_errno(); 48 | return NULL; 49 | } 50 | 51 | cmt->static_labels = cmt_labels_create(); 52 | if (!cmt->static_labels) { 53 | free(cmt); 54 | return NULL; 55 | } 56 | 57 | cmt->internal_metadata = cfl_kvlist_create(); 58 | 59 | if (cmt->internal_metadata == NULL) { 60 | cmt_labels_destroy(cmt->static_labels); 61 | 62 | free(cmt); 63 | return NULL; 64 | } 65 | 66 | cmt->external_metadata = cfl_kvlist_create(); 67 | 68 | if (cmt->external_metadata == NULL) { 69 | cfl_kvlist_destroy(cmt->internal_metadata); 70 | cmt_labels_destroy(cmt->static_labels); 71 | 72 | free(cmt); 73 | return NULL; 74 | } 75 | 76 | cfl_list_init(&cmt->counters); 77 | cfl_list_init(&cmt->gauges); 78 | cfl_list_init(&cmt->histograms); 79 | cfl_list_init(&cmt->summaries); 80 | cfl_list_init(&cmt->untypeds); 81 | 82 | cmt->log_level = CMT_LOG_ERROR; 83 | 84 | cfl_list_entry_init(&cmt->_head); 85 | 86 | return cmt; 87 | } 88 | 89 | void cmt_destroy(struct cmt *cmt) 90 | { 91 | struct cfl_list *tmp; 92 | struct cfl_list *head; 93 | struct cmt_counter *c; 94 | struct cmt_gauge *g; 95 | struct cmt_summary *s; 96 | struct cmt_histogram *h; 97 | struct cmt_untyped *u; 98 | 99 | cfl_list_foreach_safe(head, tmp, &cmt->counters) { 100 | c = cfl_list_entry(head, struct cmt_counter, _head); 101 | cmt_counter_destroy(c); 102 | } 103 | 104 | cfl_list_foreach_safe(head, tmp, &cmt->gauges) { 105 | g = cfl_list_entry(head, struct cmt_gauge, _head); 106 | cmt_gauge_destroy(g); 107 | } 108 | 109 | cfl_list_foreach_safe(head, tmp, &cmt->summaries) { 110 | s = cfl_list_entry(head, struct cmt_summary, _head); 111 | cmt_summary_destroy(s); 112 | } 113 | 114 | cfl_list_foreach_safe(head, tmp, &cmt->histograms) { 115 | h = cfl_list_entry(head, struct cmt_histogram, _head); 116 | cmt_histogram_destroy(h); 117 | } 118 | 119 | cfl_list_foreach_safe(head, tmp, &cmt->untypeds) { 120 | u = cfl_list_entry(head, struct cmt_untyped, _head); 121 | cmt_untyped_destroy(u); 122 | } 123 | 124 | if (cmt->static_labels) { 125 | cmt_labels_destroy(cmt->static_labels); 126 | } 127 | 128 | if (cmt->internal_metadata != NULL) { 129 | cfl_kvlist_destroy(cmt->internal_metadata); 130 | } 131 | 132 | if (cmt->external_metadata != NULL) { 133 | cfl_kvlist_destroy(cmt->external_metadata); 134 | } 135 | 136 | free(cmt); 137 | } 138 | 139 | int cmt_label_add(struct cmt *cmt, char *key, char *val) 140 | { 141 | return cmt_labels_add_kv(cmt->static_labels, key, val); 142 | } 143 | 144 | char *cmt_version() 145 | { 146 | return CMT_VERSION_STR; 147 | } 148 | -------------------------------------------------------------------------------- /tests/issues.c: -------------------------------------------------------------------------------- 1 | /* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ 2 | 3 | /* CMetrics 4 | * ======== 5 | * Copyright 2021-2022 The CMetrics Authors 6 | * 7 | * Licensed under the Apache License, Version 2.0 (the "License"); 8 | * you may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | */ 19 | 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | 28 | #include "cmt_tests.h" 29 | 30 | static struct cmt *generate_encoder_test_data() 31 | { 32 | uint64_t ts; 33 | struct cmt *cmt; 34 | struct cmt_counter *c1; 35 | struct cmt_counter *c2; 36 | 37 | ts = 0; 38 | cmt = cmt_create(); 39 | 40 | c1 = cmt_counter_create(cmt, "kubernetes", "", "load", "Network load", 41 | 2, (char *[]) {"hostname", "app"}); 42 | cmt_counter_set(c1, ts, 10, 0, NULL); 43 | 44 | c2 = cmt_counter_create(cmt, "kubernetes", "", "cpu", "CPU load", 45 | 2, (char *[]) {"hostname", "app"}); 46 | cmt_counter_set(c2, ts, 10, 0, NULL); 47 | 48 | return cmt; 49 | } 50 | 51 | 52 | void test_issue_54() 53 | { 54 | const char expected_text[] = "1970-01-01T00:00:00.000000000Z kubernetes_load{tag1=\"tag1\",tag2=\"tag2\"} = 10\n" \ 55 | "1970-01-01T00:00:00.000000000Z kubernetes_cpu{tag1=\"tag1\",tag2=\"tag2\"} = 10\n"; 56 | cfl_sds_t text_result; 57 | size_t mp1_size; 58 | char *mp1_buf; 59 | size_t offset; 60 | int result; 61 | struct cmt *cmt2; 62 | struct cmt *cmt1; 63 | 64 | cmt_initialize(); 65 | 66 | /* Generate context with data */ 67 | cmt1 = generate_encoder_test_data(); 68 | TEST_CHECK(NULL != cmt1); 69 | 70 | /* append static labels */ 71 | cmt_label_add(cmt1, "tag1", "tag1"); 72 | cmt_label_add(cmt1, "tag2", "tag2"); 73 | 74 | /* CMT1 -> Msgpack */ 75 | result = cmt_encode_msgpack_create(cmt1, &mp1_buf, &mp1_size); 76 | TEST_CHECK(0 == result); 77 | 78 | /* Msgpack -> CMT2 */ 79 | offset = 0; 80 | result = cmt_decode_msgpack_create(&cmt2, mp1_buf, mp1_size, &offset); 81 | TEST_CHECK(0 == result); 82 | 83 | text_result = cmt_encode_text_create(cmt2); 84 | 85 | TEST_CHECK(NULL != text_result); 86 | TEST_CHECK(0 == strcmp(text_result, expected_text)); 87 | 88 | cmt_encode_text_destroy(text_result); 89 | cmt_decode_msgpack_destroy(cmt2); 90 | cmt_encode_msgpack_destroy(mp1_buf); 91 | cmt_destroy(cmt1); 92 | } 93 | 94 | #ifdef CMT_HAVE_PROMETHEUS_TEXT_DECODER 95 | 96 | /* issue: https://github.com/fluent/fluent-bit/issues/10761 */ 97 | void test_prometheus_metric_no_subsystem() 98 | { 99 | const char text[] = 100 | "# HELP up A simple example metric no subsystem\n" 101 | "# TYPE up gauge\n" 102 | "up{job=\"42\"} 1\n"; 103 | struct cmt *cmt; 104 | cfl_sds_t result; 105 | int ret; 106 | 107 | cmt_initialize(); 108 | 109 | ret = cmt_decode_prometheus_create(&cmt, text, strlen(text), NULL); 110 | TEST_CHECK(ret == CMT_DECODE_PROMETHEUS_SUCCESS); 111 | if (ret == CMT_DECODE_PROMETHEUS_SUCCESS) { 112 | result = cmt_encode_prometheus_create(cmt, CMT_TRUE); 113 | TEST_CHECK(result != NULL); 114 | if (result) { 115 | TEST_CHECK(strstr(result, "up{job=\"42\"} 1") != NULL); 116 | cmt_encode_prometheus_destroy(result); 117 | } 118 | cmt_decode_prometheus_destroy(cmt); 119 | } 120 | } 121 | 122 | #endif 123 | 124 | TEST_LIST = { 125 | {"issue_54", test_issue_54}, 126 | #ifdef CMT_HAVE_PROMETHEUS_TEXT_DECODER 127 | {"prometheus_metric_no_subsystem", test_prometheus_metric_no_subsystem}, 128 | #endif 129 | { 0 } 130 | }; 131 | -------------------------------------------------------------------------------- /tests/basic.c: -------------------------------------------------------------------------------- 1 | /* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ 2 | 3 | /* CMetrics 4 | * ======== 5 | * Copyright 2021-2022 The CMetrics Authors 6 | * 7 | * Licensed under the Apache License, Version 2.0 (the "License"); 8 | * you may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | */ 19 | 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | 26 | #include "cmt_tests.h" 27 | 28 | static struct cmt *sample_data() 29 | { 30 | double val; 31 | uint64_t ts; 32 | struct cmt *cmt; 33 | struct cmt_counter *c1; 34 | struct cmt_counter *c2; 35 | 36 | cmt = cmt_create(); 37 | 38 | c1 = cmt_counter_create(cmt, "kubernetes", "network", "load", "Network load", 39 | 2, (char *[]) {"hostname", "app"}); 40 | 41 | ts = 0; 42 | 43 | cmt_counter_get_val(c1, 0, NULL, &val); 44 | cmt_counter_inc(c1, ts, 0, NULL); 45 | cmt_counter_add(c1, ts, 2, 0, NULL); 46 | cmt_counter_get_val(c1, 0, NULL, &val); 47 | 48 | cmt_counter_inc(c1, ts, 2, (char *[]) {"localhost", "cmetrics"}); 49 | cmt_counter_get_val(c1, 2, (char *[]) {"localhost", "cmetrics"}, &val); 50 | cmt_counter_add(c1, ts, 10.55, 2, (char *[]) {"localhost", "test"}); 51 | cmt_counter_get_val(c1, 2, (char *[]) {"localhost", "test"}, &val); 52 | cmt_counter_set(c1, ts, 12.15, 2, (char *[]) {"localhost", "test"}); 53 | cmt_counter_set(c1, ts, 1, 2, (char *[]) {"localhost", "test"}); 54 | 55 | 56 | c2 = cmt_counter_create(cmt, "kubernetes", "network", "cpu", "CPU load", 57 | 2, (char *[]) {"hostname", "app"}); 58 | 59 | ts = 0; 60 | 61 | cmt_counter_get_val(c2, 0, NULL, &val); 62 | cmt_counter_inc(c2, ts, 0, NULL); 63 | cmt_counter_add(c2, ts, 2, 0, NULL); 64 | cmt_counter_get_val(c2, 0, NULL, &val); 65 | 66 | cmt_counter_inc(c2, ts, 2, (char *[]) {"localhost", "cmetrics"}); 67 | cmt_counter_get_val(c2, 2, (char *[]) {"localhost", "cmetrics"}, &val); 68 | cmt_counter_add(c2, ts, 10.55, 2, (char *[]) {"localhost", "test"}); 69 | cmt_counter_get_val(c2, 2, (char *[]) {"localhost", "test"}, &val); 70 | cmt_counter_set(c2, ts, 12.15, 2, (char *[]) {"localhost", "test"}); 71 | cmt_counter_set(c2, ts, 1, 2, (char *[]) {"localhost", "test"}); 72 | 73 | return cmt; 74 | } 75 | 76 | void test_basic() 77 | { 78 | int ret; 79 | int error; 80 | size_t off = 0; 81 | cfl_sds_t text1; 82 | cfl_sds_t text2; 83 | char *mp_buf; 84 | size_t mp_size; 85 | struct cmt *cmt1; 86 | struct cmt *cmt2; 87 | 88 | cmt1 = sample_data(); 89 | TEST_CHECK(cmt1 != NULL); 90 | 91 | /* encode to text */ 92 | text1 = cmt_encode_text_create(cmt1); 93 | TEST_CHECK(text1 != NULL); 94 | 95 | /* encode to msgpack */ 96 | ret = cmt_encode_msgpack_create(cmt1, &mp_buf, &mp_size); 97 | TEST_CHECK(ret == 0); 98 | 99 | /* decode msgpack into cmt2 */ 100 | ret = cmt_decode_msgpack_create(&cmt2, mp_buf, mp_size, &off); 101 | TEST_CHECK(ret == 0); 102 | 103 | /* encode cmt2 to text */ 104 | text2 = cmt_encode_text_create(cmt2); 105 | TEST_CHECK(text2 != NULL); 106 | 107 | /* compate both texts */ 108 | error = 0; 109 | if ((cfl_sds_len(text1) != cfl_sds_len(text2)) || 110 | strcmp(text1, text2) != 0) { 111 | 112 | printf("\n"); 113 | printf("====== EXPECTED OUTPUT =====\n%s", text1); 114 | printf("\n\n"); 115 | printf("====== RECEIVED OUTPUT =====\n%s\n", text2); 116 | error = 1; 117 | } 118 | TEST_CHECK(error == 0); 119 | 120 | cmt_encode_msgpack_destroy(mp_buf); 121 | cmt_encode_text_destroy(text1); 122 | cmt_encode_text_destroy(text2); 123 | cmt_destroy(cmt1); 124 | cmt_destroy(cmt2); 125 | } 126 | 127 | TEST_LIST = { 128 | {"basic", test_basic}, 129 | { 0 } 130 | }; 131 | -------------------------------------------------------------------------------- /src/external/opentelemetry_resource.pb-c.c: -------------------------------------------------------------------------------- 1 | /* Generated by the protocol buffer compiler. DO NOT EDIT! */ 2 | /* Generated from: resource.proto */ 3 | 4 | /* Do not generate deprecated warnings for self */ 5 | #ifndef PROTOBUF_C__NO_DEPRECATED 6 | #define PROTOBUF_C__NO_DEPRECATED 7 | #endif 8 | 9 | #include 10 | void opentelemetry__proto__resource__v1__resource__init 11 | (Opentelemetry__Proto__Resource__V1__Resource *message) 12 | { 13 | static const Opentelemetry__Proto__Resource__V1__Resource init_value = OPENTELEMETRY__PROTO__RESOURCE__V1__RESOURCE__INIT; 14 | *message = init_value; 15 | } 16 | size_t opentelemetry__proto__resource__v1__resource__get_packed_size 17 | (const Opentelemetry__Proto__Resource__V1__Resource *message) 18 | { 19 | assert(message->base.descriptor == &opentelemetry__proto__resource__v1__resource__descriptor); 20 | return protobuf_c_message_get_packed_size ((const ProtobufCMessage*)(message)); 21 | } 22 | size_t opentelemetry__proto__resource__v1__resource__pack 23 | (const Opentelemetry__Proto__Resource__V1__Resource *message, 24 | uint8_t *out) 25 | { 26 | assert(message->base.descriptor == &opentelemetry__proto__resource__v1__resource__descriptor); 27 | return protobuf_c_message_pack ((const ProtobufCMessage*)message, out); 28 | } 29 | size_t opentelemetry__proto__resource__v1__resource__pack_to_buffer 30 | (const Opentelemetry__Proto__Resource__V1__Resource *message, 31 | ProtobufCBuffer *buffer) 32 | { 33 | assert(message->base.descriptor == &opentelemetry__proto__resource__v1__resource__descriptor); 34 | return protobuf_c_message_pack_to_buffer ((const ProtobufCMessage*)message, buffer); 35 | } 36 | Opentelemetry__Proto__Resource__V1__Resource * 37 | opentelemetry__proto__resource__v1__resource__unpack 38 | (ProtobufCAllocator *allocator, 39 | size_t len, 40 | const uint8_t *data) 41 | { 42 | return (Opentelemetry__Proto__Resource__V1__Resource *) 43 | protobuf_c_message_unpack (&opentelemetry__proto__resource__v1__resource__descriptor, 44 | allocator, len, data); 45 | } 46 | void opentelemetry__proto__resource__v1__resource__free_unpacked 47 | (Opentelemetry__Proto__Resource__V1__Resource *message, 48 | ProtobufCAllocator *allocator) 49 | { 50 | if(!message) 51 | return; 52 | assert(message->base.descriptor == &opentelemetry__proto__resource__v1__resource__descriptor); 53 | protobuf_c_message_free_unpacked ((ProtobufCMessage*)message, allocator); 54 | } 55 | static const ProtobufCFieldDescriptor opentelemetry__proto__resource__v1__resource__field_descriptors[2] = 56 | { 57 | { 58 | "attributes", 59 | 1, 60 | PROTOBUF_C_LABEL_REPEATED, 61 | PROTOBUF_C_TYPE_MESSAGE, 62 | offsetof(Opentelemetry__Proto__Resource__V1__Resource, n_attributes), 63 | offsetof(Opentelemetry__Proto__Resource__V1__Resource, attributes), 64 | &opentelemetry__proto__common__v1__key_value__descriptor, 65 | NULL, 66 | 0, /* flags */ 67 | 0,NULL,NULL /* reserved1,reserved2, etc */ 68 | }, 69 | { 70 | "dropped_attributes_count", 71 | 2, 72 | PROTOBUF_C_LABEL_NONE, 73 | PROTOBUF_C_TYPE_UINT32, 74 | 0, /* quantifier_offset */ 75 | offsetof(Opentelemetry__Proto__Resource__V1__Resource, dropped_attributes_count), 76 | NULL, 77 | NULL, 78 | 0, /* flags */ 79 | 0,NULL,NULL /* reserved1,reserved2, etc */ 80 | }, 81 | }; 82 | static const unsigned opentelemetry__proto__resource__v1__resource__field_indices_by_name[] = { 83 | 0, /* field[0] = attributes */ 84 | 1, /* field[1] = dropped_attributes_count */ 85 | }; 86 | static const ProtobufCIntRange opentelemetry__proto__resource__v1__resource__number_ranges[1 + 1] = 87 | { 88 | { 1, 0 }, 89 | { 0, 2 } 90 | }; 91 | const ProtobufCMessageDescriptor opentelemetry__proto__resource__v1__resource__descriptor = 92 | { 93 | PROTOBUF_C__MESSAGE_DESCRIPTOR_MAGIC, 94 | "opentelemetry.proto.resource.v1.Resource", 95 | "Resource", 96 | "Opentelemetry__Proto__Resource__V1__Resource", 97 | "opentelemetry.proto.resource.v1", 98 | sizeof(Opentelemetry__Proto__Resource__V1__Resource), 99 | 2, 100 | opentelemetry__proto__resource__v1__resource__field_descriptors, 101 | opentelemetry__proto__resource__v1__resource__field_indices_by_name, 102 | 1, opentelemetry__proto__resource__v1__resource__number_ranges, 103 | (ProtobufCMessageInit) opentelemetry__proto__resource__v1__resource__init, 104 | NULL,NULL,NULL /* reserved[123] */ 105 | }; 106 | -------------------------------------------------------------------------------- /src/cmt_untyped.c: -------------------------------------------------------------------------------- 1 | /* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ 2 | 3 | /* CMetrics 4 | * ======== 5 | * Copyright 2021-2022 The CMetrics Authors 6 | * 7 | * Licensed under the Apache License, Version 2.0 (the "License"); 8 | * you may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | */ 19 | 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | 26 | struct cmt_untyped *cmt_untyped_create(struct cmt *cmt, 27 | char *ns, char *subsystem, 28 | char *name, char *help, 29 | int label_count, char **label_keys) 30 | { 31 | int ret; 32 | struct cmt_untyped *untyped; 33 | 34 | if (!ns) { 35 | cmt_log_error(cmt, "null ns not allowed"); 36 | return NULL; 37 | } 38 | 39 | if (!subsystem) { 40 | cmt_log_error(cmt, "null subsystem not allowed"); 41 | return NULL; 42 | } 43 | 44 | if (!help || strlen(help) == 0) { 45 | cmt_log_error(cmt, "undefined help"); 46 | return NULL; 47 | } 48 | 49 | if (!name || strlen(name) == 0) { 50 | cmt_log_error(cmt, "undefined name"); 51 | return NULL; 52 | } 53 | 54 | if (!help || strlen(help) == 0) { 55 | cmt_log_error(cmt, "undefined help"); 56 | return NULL; 57 | } 58 | 59 | untyped = calloc(1, sizeof(struct cmt_untyped)); 60 | if (!untyped) { 61 | cmt_errno(); 62 | return NULL; 63 | } 64 | cfl_list_add(&untyped->_head, &cmt->untypeds); 65 | 66 | ret = cmt_opts_init(&untyped->opts, ns, subsystem, name, help); 67 | if (ret == -1) { 68 | cmt_log_error(cmt, "unable to initialize options for untyped"); 69 | cmt_untyped_destroy(untyped); 70 | return NULL; 71 | } 72 | 73 | /* Create the map */ 74 | untyped->map = cmt_map_create(CMT_UNTYPED, &untyped->opts, label_count, label_keys, 75 | (void *) untyped); 76 | if (!untyped->map) { 77 | cmt_log_error(cmt, "unable to allocate map for untyped"); 78 | cmt_untyped_destroy(untyped); 79 | return NULL; 80 | } 81 | 82 | untyped->cmt = cmt; 83 | 84 | return untyped; 85 | } 86 | 87 | int cmt_untyped_destroy(struct cmt_untyped *untyped) 88 | { 89 | cfl_list_del(&untyped->_head); 90 | cmt_opts_exit(&untyped->opts); 91 | 92 | if (untyped->map) { 93 | cmt_map_destroy(untyped->map); 94 | } 95 | free(untyped); 96 | return 0; 97 | } 98 | 99 | /* Set untyped value, new value cannot be smaller than current value */ 100 | int cmt_untyped_set(struct cmt_untyped *untyped, uint64_t timestamp, double val, 101 | int labels_count, char **label_vals) 102 | { 103 | struct cmt_metric *metric; 104 | 105 | metric = cmt_map_metric_get(&untyped->opts, untyped->map, 106 | labels_count, label_vals, 107 | CMT_TRUE); 108 | if (!metric) { 109 | cmt_log_error(untyped->cmt, "unable to retrieve metric for untyped %s_%s_%s", 110 | untyped->opts.ns, untyped->opts.subsystem, 111 | untyped->opts.name); 112 | return -1; 113 | } 114 | 115 | if (cmt_metric_get_value(metric) > val) { 116 | return -1; 117 | } 118 | cmt_metric_set(metric, timestamp, val); 119 | return 0; 120 | } 121 | 122 | int cmt_untyped_get_val(struct cmt_untyped *untyped, 123 | int labels_count, char **label_vals, double *out_val) 124 | { 125 | int ret; 126 | double val = 0; 127 | 128 | ret = cmt_map_metric_get_val(&untyped->opts, 129 | untyped->map, labels_count, label_vals, 130 | &val); 131 | if (ret == -1) { 132 | cmt_log_error(untyped->cmt, 133 | "unable to retrieve metric value for untyped %s_%s_%s", 134 | untyped->opts.ns, untyped->opts.subsystem, 135 | untyped->opts.name); 136 | return -1; 137 | } 138 | *out_val = val; 139 | return 0; 140 | } 141 | -------------------------------------------------------------------------------- /tests/gauge.c: -------------------------------------------------------------------------------- 1 | /* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ 2 | 3 | /* CMetrics 4 | * ======== 5 | * Copyright 2021-2022 The CMetrics Authors 6 | * 7 | * Licensed under the Apache License, Version 2.0 (the "License"); 8 | * you may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | */ 19 | 20 | #include 21 | #include 22 | #include 23 | 24 | #include "cmt_tests.h" 25 | 26 | void test_gauge() 27 | { 28 | int ret; 29 | double val; 30 | uint64_t ts; 31 | struct cmt *cmt; 32 | struct cmt_gauge *g; 33 | 34 | cmt_initialize(); 35 | 36 | cmt = cmt_create(); 37 | TEST_CHECK(cmt != NULL); 38 | 39 | /* Create a gauge metric type */ 40 | g = cmt_gauge_create(cmt, "kubernetes", "network", "load", "Network load", 0, NULL); 41 | TEST_CHECK(g != NULL); 42 | 43 | /* Timestamp */ 44 | ts = cfl_time_now(); 45 | 46 | /* Default value */ 47 | ret = cmt_gauge_get_val(g, 0, NULL, &val); 48 | TEST_CHECK(val == 0.0); 49 | 50 | /* Set a value of two */ 51 | cmt_gauge_set(g, ts, 2.0, 0, NULL); 52 | ret = cmt_gauge_get_val(g, 0, NULL, &val); 53 | TEST_CHECK(ret == 0); 54 | TEST_CHECK(val == 2.0); 55 | 56 | /* Increment one */ 57 | cmt_gauge_inc(g, ts, 0, NULL); 58 | ret = cmt_gauge_get_val(g, 0, NULL, &val); 59 | TEST_CHECK(ret == 0); 60 | TEST_CHECK(val == 3.0); 61 | 62 | /* Substract 2 */ 63 | ret = cmt_gauge_sub(g, ts, 2, 0, NULL); 64 | TEST_CHECK(ret == 0); 65 | 66 | ret = cmt_gauge_get_val(g, 0, NULL, &val); 67 | TEST_CHECK(ret == 0); 68 | TEST_CHECK(val == 1.0); 69 | 70 | /* Decrement by one */ 71 | ret = cmt_gauge_dec(g, ts, 0, NULL); 72 | TEST_CHECK(ret == 0); 73 | 74 | ret = cmt_gauge_get_val(g, 0, NULL, &val); 75 | TEST_CHECK(ret == 0); 76 | TEST_CHECK(val == 0.0); 77 | 78 | cmt_destroy(cmt); 79 | } 80 | 81 | void test_labels() 82 | { 83 | int ret; 84 | double val; 85 | uint64_t ts; 86 | cfl_sds_t prom; 87 | struct cmt *cmt; 88 | struct cmt_gauge *g; 89 | 90 | cmt_initialize(); 91 | 92 | cmt = cmt_create(); 93 | TEST_CHECK(cmt != NULL); 94 | 95 | /* Create a counter metric type */ 96 | g = cmt_gauge_create(cmt, "kubernetes", "network", "load", "Network load", 97 | 2, (char *[]) {"hostname", "app"}); 98 | TEST_CHECK(g != NULL); 99 | 100 | /* Timestamp */ 101 | ts = cfl_time_now(); 102 | 103 | /* 104 | * Test 1: hash zero (no labels) 105 | * ----------------------------- 106 | */ 107 | 108 | /* Default value for hash zero */ 109 | ret = cmt_gauge_get_val(g, 0, NULL, &val); 110 | TEST_CHECK(ret == -1); 111 | 112 | /* Increment hash zero by 1 */ 113 | ret = cmt_gauge_inc(g, ts, 0, NULL); 114 | TEST_CHECK(ret == 0); 115 | 116 | /* Check the new value */ 117 | ret = cmt_gauge_get_val(g, 0, NULL, &val); 118 | TEST_CHECK(ret == 0); 119 | TEST_CHECK(val == 1.0); 120 | 121 | /* Add two */ 122 | ret = cmt_gauge_add(g, ts, 2, 0, NULL); 123 | TEST_CHECK(ret == 0); 124 | 125 | /* Check that hash zero val is 3.0 */ 126 | ret = cmt_gauge_get_val(g, 0, NULL, &val); 127 | TEST_CHECK(ret == 0); 128 | TEST_CHECK(val == 3.0); 129 | 130 | /* 131 | * Test 2: custom labels 132 | * --------------------- 133 | */ 134 | 135 | /* Increment custom metric */ 136 | ret = cmt_gauge_inc(g, ts, 2, (char *[]) {"localhost", "cmetrics"}); 137 | TEST_CHECK(ret == 0); 138 | 139 | /* Check ret = 1 */ 140 | ret = cmt_gauge_get_val(g, 2, (char *[]) {"localhost", "cmetrics"}, &val); 141 | TEST_CHECK(ret == 0); 142 | TEST_CHECK(val == 1.000); 143 | 144 | /* Add 10 to another metric using a different second label */ 145 | ret = cmt_gauge_add(g, ts, 10, 2, (char *[]) {"localhost", "test"}); 146 | TEST_CHECK(ret == 0); 147 | 148 | /* Validate the value */ 149 | ret = cmt_gauge_get_val(g, 2, (char *[]) {"localhost", "test"}, &val); 150 | TEST_CHECK(ret == 0); 151 | TEST_CHECK(val == 10.00); 152 | 153 | /* Substract two */ 154 | ret = cmt_gauge_sub(g, ts, 2.5, 2, (char *[]) {"localhost", "test"}); 155 | TEST_CHECK(ret == 0); 156 | 157 | /* Validate the value */ 158 | ret = cmt_gauge_get_val(g, 2, (char *[]) {"localhost", "test"}, &val); 159 | TEST_CHECK(ret == 0); 160 | TEST_CHECK(val == 7.50); 161 | 162 | printf("\n"); 163 | prom = cmt_encode_prometheus_create(cmt, CMT_TRUE); 164 | printf("%s\n", prom); 165 | cmt_encode_prometheus_destroy(prom); 166 | 167 | cmt_destroy(cmt); 168 | } 169 | 170 | TEST_LIST = { 171 | {"basic" , test_gauge}, 172 | {"labels", test_labels}, 173 | { 0 } 174 | }; 175 | -------------------------------------------------------------------------------- /tests/summary.c: -------------------------------------------------------------------------------- 1 | /* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ 2 | 3 | /* CMetrics 4 | * ======== 5 | * Copyright 2021-2022 The CMetrics Authors 6 | * 7 | * Licensed under the Apache License, Version 2.0 (the "License"); 8 | * you may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | */ 19 | 20 | #include 21 | #include 22 | #include 23 | #include 24 | 25 | #include "cmt_tests.h" 26 | 27 | static void prometheus_encode_test(struct cmt *cmt) 28 | { 29 | cfl_sds_t buf; 30 | 31 | buf = cmt_encode_prometheus_create(cmt, CMT_FALSE); 32 | printf("\n%s\n", buf); 33 | cmt_encode_prometheus_destroy(buf); 34 | 35 | /* encode to all possible formats */ 36 | cmt_test_encode_all(cmt); 37 | } 38 | 39 | void test_set_defaults() 40 | { 41 | double sum; 42 | uint64_t count; 43 | uint64_t ts; 44 | double q[6]; 45 | double r[6]; 46 | struct cmt *cmt; 47 | struct cmt_summary *s; 48 | 49 | cmt_initialize(); 50 | 51 | /* Timestamp */ 52 | ts = cfl_time_now(); 53 | 54 | /* CMetrics context */ 55 | cmt = cmt_create(); 56 | TEST_CHECK(cmt != NULL); 57 | 58 | /* set quantiles, no labels */ 59 | q[0] = 0.1; 60 | q[1] = 0.2; 61 | q[2] = 0.3; 62 | q[3] = 0.4; 63 | q[4] = 0.5; 64 | q[5] = 1.0; 65 | 66 | r[0] = 1; 67 | r[1] = 2; 68 | r[2] = 3; 69 | r[3] = 4; 70 | r[4] = 5; 71 | r[5] = 6; 72 | 73 | /* Create a gauge metric type */ 74 | s = cmt_summary_create(cmt, 75 | "k8s", "network", "load", "Network load", 76 | 6, q, 77 | 1, (char *[]) {"my_label"}); 78 | TEST_CHECK(s != NULL); 79 | 80 | count = 10; 81 | sum = 51.612894511314444; 82 | 83 | /* no quantiles, no labels */ 84 | cmt_summary_set_default(s, ts, NULL, sum, count, 0, NULL); 85 | prometheus_encode_test(cmt); 86 | 87 | cmt_summary_set_default(s, ts, r, sum, count, 0, NULL); 88 | prometheus_encode_test(cmt); 89 | 90 | /* static label: register static label for the context */ 91 | cmt_label_add(cmt, "static", "test"); 92 | prometheus_encode_test(cmt); 93 | 94 | cmt_destroy(cmt); 95 | } 96 | 97 | /* ref: https://github.com/fluent/fluent-bit/issues/5894 */ 98 | void fluentbit_bug_5894() 99 | { 100 | double sum; 101 | uint64_t count; 102 | uint64_t ts; 103 | double q[6]; 104 | double r[6]; 105 | struct cmt *cmt; 106 | struct cmt_summary *s; 107 | 108 | cmt_initialize(); 109 | 110 | /* Timestamp */ 111 | ts = cfl_time_now(); 112 | 113 | /* CMetrics context */ 114 | cmt = cmt_create(); 115 | TEST_CHECK(cmt != NULL); 116 | 117 | /* set quantiles, no labels */ 118 | q[0] = 0.1; 119 | q[1] = 0.2; 120 | q[2] = 0.3; 121 | q[3] = 0.4; 122 | q[4] = 0.5; 123 | q[5] = 1.0; 124 | 125 | r[0] = 1; 126 | r[1] = 2; 127 | r[2] = 3; 128 | r[3] = 4; 129 | r[4] = 5; 130 | r[5] = 6; 131 | 132 | /* Create a gauge metric type */ 133 | s = cmt_summary_create(cmt, 134 | "spring", "kafka_listener", "seconds", "Kafka Listener Timer", 135 | 6, q, 136 | 3, (char *[]) {"exception", "name", "result"}); 137 | TEST_CHECK(s != NULL); 138 | 139 | /* no quantiles, labels */ 140 | sum = 0.0; 141 | count = 1; 142 | 143 | cmt_summary_set_default(s, ts, NULL, sum, count, 144 | 3, (char *[]) {"ListenerExecutionFailedException", 145 | "org.springframework.kafka.KafkaListenerEndpointContainer#0-0", 146 | "failure"}); 147 | 148 | /* no quantiles, labels */ 149 | sum = 0.1; 150 | count = 2; 151 | cmt_summary_set_default(s, ts, NULL, sum, count, 152 | 3, (char *[]) {"none", 153 | "org.springframework.kafka.KafkaListenerEndpointContainer#0-0", 154 | "success"}); 155 | 156 | /* quantiles, labels */ 157 | sum = 0.2; 158 | count = 3; 159 | cmt_summary_set_default(s, ts, r, sum, count, 160 | 3, (char *[]) {"extra test", 161 | "org.springframework.kafka.KafkaListenerEndpointContainer#0-0", 162 | "success"}); 163 | 164 | prometheus_encode_test(cmt); 165 | cmt_destroy(cmt); 166 | } 167 | 168 | TEST_LIST = { 169 | {"set_defaults" , test_set_defaults}, 170 | {"fluentbit_bug_5894", fluentbit_bug_5894}, 171 | { 0 } 172 | }; 173 | -------------------------------------------------------------------------------- /src/cmt_decode_prometheus.l: -------------------------------------------------------------------------------- 1 | %option prefix="cmt_decode_prometheus_" 2 | 3 | %option reentrant bison-bridge 4 | %option noyywrap nounput noinput 5 | %option nodefault 6 | 7 | %{ 8 | 9 | #include 10 | 11 | #define STRBUF_RET \ 12 | yylval->str = context->strbuf; \ 13 | context->strbuf = NULL 14 | 15 | %} 16 | 17 | /* here we define some states that allow us to create rules only 18 | matched in certain situations */ 19 | 20 | %x INQUOTE HELPTAG INHELPTAG TYPETAG INTYPETAG COMMENT COMMENT_START 21 | 22 | %% 23 | 24 | %{ 25 | if (context->opts.start_token) { 26 | int t = context->opts.start_token; 27 | context->opts.start_token = 0; 28 | return t; 29 | } 30 | %} 31 | 32 | <*>\r\n|\n { 33 | int top_state = YYSTATE; 34 | // We always return to the INITIAL state on a linefeed, no matter which 35 | // state we are on (the "<*>" means this rule is applied on every state) 36 | BEGIN(INITIAL); 37 | if (top_state == INHELPTAG) { 38 | // But if we were on the INHELPTAG state, we return everything collected 39 | // in strbuf 40 | STRBUF_RET; 41 | return METRIC_DOC; 42 | } 43 | } 44 | 45 | ^[ ]*#[ ]* { 46 | // Lines with "#" as the first non-whitespace character begin a comment 47 | // unless the first token is either HELP or TYPE. To handle this ambiguity, 48 | // we enter the COMMENT_START state, which contains rules for selecting 49 | // if this is a HELP/TYPE tag or just a normal comment 50 | BEGIN(COMMENT_START); 51 | } 52 | 53 | HELP[ \t]+ { 54 | // Begin a help tag 55 | BEGIN(HELPTAG); 56 | } 57 | 58 | TYPE[ \t]+ { 59 | // Begin a type tag 60 | BEGIN(TYPETAG); 61 | } 62 | 63 | [^\n] { 64 | // Any character that is not a newline begins the COMMENT state where 65 | // everything is ignored until the next linefeed. This works because flex 66 | // will prioritize the two rules above this one since they have longer 67 | // matches. 68 | BEGIN(COMMENT); 69 | } 70 | 71 | [^\n]+ { 72 | // ignore 73 | } 74 | 75 | [^ \t]+ { 76 | // The next token will be the metric name 77 | yylval->str = cfl_sds_create(yytext); 78 | return YYSTATE == HELPTAG ? HELP : TYPE; 79 | } 80 | 81 | [ \t]* { 82 | // Every whitespace after the metric name is ignored 83 | if (YYSTATE == HELPTAG) { 84 | // For HELPTAG we enter the INHELPTAG start condition which we will use to 85 | // read everything until the end of line into context->strbuf. We enter a 86 | // separate start condition for this to handle "\\" and "\n" escapes 87 | // more easily. 88 | BEGIN(INHELPTAG); 89 | context->strbuf = cfl_sds_create_size(256); 90 | } 91 | else { 92 | // For TYPETAG we enter INTYPETAG start condition to check only valid 93 | // metric types are accepted. This prevents us from having to do 94 | // manual validation later. 95 | BEGIN(INTYPETAG); 96 | } 97 | } 98 | 99 | <> { 100 | // Handle EOF when in the INHELPTAG state by returning the buffered docstring. 101 | // While this is not strictly necessary, it makes easier unit testing the 102 | // lexer 103 | BEGIN(INITIAL); 104 | STRBUF_RET; 105 | return METRIC_DOC; 106 | } 107 | 108 | \\n { 109 | // Process linefeed escape sequence 110 | context->strbuf = cfl_sds_cat(context->strbuf, "\n", 1); 111 | } 112 | 113 | \\\\ { 114 | // Process backslack escape sequence 115 | context->strbuf = cfl_sds_cat(context->strbuf, "\\", 1); 116 | } 117 | 118 | [^\r\n\\]+ { 119 | // Put everything that is not a backslash or a line feed into strbuf 120 | context->strbuf = cfl_sds_cat(context->strbuf, yytext, yyleng); 121 | } 122 | 123 | counter { 124 | return COUNTER; 125 | } 126 | 127 | gauge { 128 | return GAUGE; 129 | } 130 | 131 | summary { 132 | return SUMMARY; 133 | } 134 | 135 | untyped { 136 | return UNTYPED; 137 | } 138 | 139 | histogram { 140 | return HISTOGRAM; 141 | } 142 | 143 | [ \t]+ { 144 | /* ignore whitespace */ 145 | } 146 | 147 | ["] { 148 | BEGIN(INQUOTE); 149 | if (context->strbuf != NULL) { 150 | cfl_sds_destroy(context->strbuf); 151 | } 152 | context->strbuf = cfl_sds_create_size(256); 153 | } 154 | 155 | [\\]["] { 156 | context->strbuf = cfl_sds_cat(context->strbuf, "\"", 1); 157 | } 158 | 159 | \\n { 160 | context->strbuf = cfl_sds_cat(context->strbuf, "\n", 1); 161 | } 162 | 163 | \\\\ { 164 | context->strbuf = cfl_sds_cat(context->strbuf, "\\", 1); 165 | } 166 | 167 | [^\r\n\\"]+ { 168 | context->strbuf = cfl_sds_cat(context->strbuf, yytext, yyleng); 169 | } 170 | 171 | ["] { 172 | BEGIN(INITIAL); 173 | STRBUF_RET; 174 | return QUOTED; 175 | } 176 | 177 | [+-]?(?i:(INF|NAN)) { 178 | strncpy(yylval->numstr, yytext, sizeof(yylval->numstr) - 1); 179 | return INFNAN; 180 | } 181 | 182 | [a-zA-Z_][a-zA-Z_0-9]* { 183 | yylval->str = cfl_sds_create(yytext); 184 | return IDENTIFIER; 185 | } 186 | 187 | [0-9.eE+-]+ { 188 | strncpy(yylval->numstr, yytext, sizeof(yylval->numstr) - 1); 189 | return NUMSTR; 190 | } 191 | 192 | . { 193 | // Catch all workaround to avoid having to define token types for every 194 | // possible delimiter. We simply return the character to the parser. 195 | return *yytext; 196 | } 197 | 198 | %% 199 | -------------------------------------------------------------------------------- /src/cmt_metric_histogram.c: -------------------------------------------------------------------------------- 1 | /* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ 2 | 3 | /* CMetrics 4 | * ======== 5 | * Copyright 2021-2022 The CMetrics Authors 6 | * 7 | * Licensed under the Apache License, Version 2.0 (the "License"); 8 | * you may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | */ 19 | 20 | #include 21 | #include 22 | #include 23 | #include 24 | 25 | static inline int metric_hist_exchange(struct cmt_metric *metric, 26 | uint64_t timestamp, 27 | int bucket_id, 28 | uint64_t new, uint64_t old) 29 | { 30 | int result; 31 | 32 | result = cmt_atomic_compare_exchange(&metric->hist_buckets[bucket_id], 33 | old, new); 34 | if (result == 0) { 35 | return 0; 36 | } 37 | 38 | cmt_atomic_store(&metric->timestamp, timestamp); 39 | return 1; 40 | } 41 | 42 | static inline int metric_hist_count_exchange(struct cmt_metric *metric, 43 | uint64_t timestamp, 44 | uint64_t new, uint64_t old) 45 | { 46 | int result; 47 | 48 | result = cmt_atomic_compare_exchange(&metric->hist_count, old, new); 49 | if (result == 0) { 50 | return 0; 51 | } 52 | 53 | cmt_atomic_store(&metric->timestamp, timestamp); 54 | return 1; 55 | } 56 | 57 | static inline int metric_sum_exchange(struct cmt_metric *metric, 58 | uint64_t timestamp, 59 | double new_value, double old_value) 60 | { 61 | uint64_t tmp_new; 62 | uint64_t tmp_old; 63 | int result; 64 | 65 | tmp_new = cmt_math_d64_to_uint64(new_value); 66 | tmp_old = cmt_math_d64_to_uint64(old_value); 67 | 68 | result = cmt_atomic_compare_exchange(&metric->hist_sum, tmp_old, tmp_new); 69 | 70 | if (result == 0) { 71 | return 0; 72 | } 73 | 74 | cmt_atomic_store(&metric->timestamp, timestamp); 75 | return 1; 76 | } 77 | 78 | void cmt_metric_hist_inc(struct cmt_metric *metric, uint64_t timestamp, 79 | int bucket_id) 80 | { 81 | int result; 82 | uint64_t old; 83 | uint64_t new; 84 | 85 | do { 86 | old = cmt_atomic_load(&metric->hist_buckets[bucket_id]); 87 | new = old + 1; 88 | result = metric_hist_exchange(metric, timestamp, bucket_id, new, old); 89 | } 90 | while (result == 0); 91 | } 92 | 93 | void cmt_metric_hist_count_inc(struct cmt_metric *metric, uint64_t timestamp) 94 | { 95 | int result; 96 | uint64_t old; 97 | uint64_t new; 98 | 99 | do { 100 | old = cmt_atomic_load(&metric->hist_count); 101 | new = old + 1; 102 | 103 | result = metric_hist_count_exchange(metric, timestamp, new, old); 104 | } 105 | while (result == 0); 106 | } 107 | 108 | void cmt_metric_hist_count_set(struct cmt_metric *metric, uint64_t timestamp, 109 | uint64_t count) 110 | { 111 | int result; 112 | uint64_t old; 113 | uint64_t new; 114 | 115 | do { 116 | old = cmt_atomic_load(&metric->hist_count); 117 | new = count; 118 | 119 | result = metric_hist_count_exchange(metric, timestamp, new, old); 120 | } 121 | while (result == 0); 122 | } 123 | 124 | void cmt_metric_hist_sum_add(struct cmt_metric *metric, uint64_t timestamp, 125 | double val) 126 | { 127 | double old; 128 | double new; 129 | int result; 130 | 131 | do { 132 | old = cmt_metric_hist_get_sum_value(metric); 133 | new = old + val; 134 | result = metric_sum_exchange(metric, timestamp, new, old); 135 | } 136 | while (0 == result); 137 | } 138 | 139 | void cmt_metric_hist_sum_set(struct cmt_metric *metric, uint64_t timestamp, 140 | double val) 141 | { 142 | double old; 143 | double new; 144 | int result; 145 | 146 | do { 147 | old = cmt_metric_hist_get_sum_value(metric); 148 | new = val; 149 | result = metric_sum_exchange(metric, timestamp, new, old); 150 | } 151 | while (0 == result); 152 | } 153 | 154 | void cmt_metric_hist_set(struct cmt_metric *metric, uint64_t timestamp, 155 | int bucket_id, double val) 156 | { 157 | int result; 158 | uint64_t old; 159 | uint64_t new; 160 | 161 | do { 162 | old = cmt_atomic_load(&metric->hist_buckets[bucket_id]); 163 | new = val; 164 | 165 | result = metric_hist_exchange(metric, timestamp, bucket_id, new, old); 166 | } 167 | while (result == 0); 168 | } 169 | 170 | uint64_t cmt_metric_hist_get_value(struct cmt_metric *metric, int bucket_id) 171 | { 172 | uint64_t val; 173 | 174 | val = cmt_atomic_load(&metric->hist_buckets[bucket_id]); 175 | return val; 176 | } 177 | 178 | uint64_t cmt_metric_hist_get_count_value(struct cmt_metric *metric) 179 | { 180 | uint64_t val; 181 | 182 | val = cmt_atomic_load(&metric->hist_count); 183 | return val; 184 | } 185 | 186 | double cmt_metric_hist_get_sum_value(struct cmt_metric *metric) 187 | { 188 | uint64_t val; 189 | 190 | val = cmt_atomic_load(&metric->hist_sum); 191 | return cmt_math_uint64_to_d64(val); 192 | } 193 | -------------------------------------------------------------------------------- /tests/null_label.c: -------------------------------------------------------------------------------- 1 | /* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ 2 | 3 | /* CMetrics 4 | * ======== 5 | * Copyright 2021-2022 The CMetrics Authors 6 | * 7 | * Licensed under the Apache License, Version 2.0 (the "License"); 8 | * you may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | */ 19 | 20 | #include 21 | #include 22 | #include 23 | 24 | #include "cmt_tests.h" 25 | 26 | void test_labels() 27 | { 28 | int ret; 29 | double val = 1; 30 | uint64_t ts; 31 | struct cmt *cmt; 32 | struct cmt_counter *c; 33 | 34 | cmt = cmt_create(); 35 | c = cmt_counter_create(cmt, "test", "dummy", "labels", "testing labels", 36 | 6, (char *[]) {"A", "B", "C", "D", "E", "F"}); 37 | 38 | ts = cfl_time_now(); 39 | 40 | ret = cmt_counter_get_val(c, 0, NULL, &val); 41 | TEST_CHECK(ret == -1); 42 | TEST_CHECK((uint64_t) val == 1); 43 | 44 | cmt_counter_inc(c, ts, 0, NULL); 45 | cmt_counter_add(c, ts, 2, 0, NULL); 46 | cmt_counter_get_val(c, 0, NULL, &val); 47 | TEST_CHECK((uint64_t) val == 3); 48 | 49 | /* --- case 1 --- */ 50 | cmt_counter_inc(c, ts, 6, (char *[]) {"1", NULL, "98", NULL, NULL, NULL}); 51 | 52 | /* check retrieval with no labels */ 53 | cmt_counter_get_val(c, 0, NULL, &val); 54 | TEST_CHECK((uint64_t) val == 3); 55 | 56 | /* check real value */ 57 | cmt_counter_get_val(c, 6, (char *[]) {"1", NULL, "98", NULL, NULL, NULL}, &val); 58 | TEST_CHECK((uint64_t) val == 1); 59 | 60 | 61 | /* --- case 2 --- */ 62 | cmt_counter_set(c, ts, 5, 6, (char *[]) {"1", "2", "98", "100", "200", "300"}); 63 | 64 | /* check retrieval with no labels */ 65 | cmt_counter_get_val(c, 0, NULL, &val); 66 | TEST_CHECK((uint64_t) val == 3); 67 | 68 | /* check real value */ 69 | cmt_counter_get_val(c, 6, (char *[]) {"1", "2", "98", "100", "200", "300"}, &val); 70 | TEST_CHECK((uint64_t) val == 5); 71 | 72 | /* --- check that 'case 1' still matches --- */ 73 | cmt_counter_get_val(c, 0, NULL, &val); 74 | TEST_CHECK((uint64_t) val == 3); 75 | 76 | /* check real value */ 77 | cmt_counter_get_val(c, 6, (char *[]) {"1", NULL, "98", NULL, NULL, NULL}, &val); 78 | TEST_CHECK((uint64_t) val == 1); 79 | 80 | cmt_destroy(cmt); 81 | } 82 | 83 | void test_encoding() 84 | { 85 | cfl_sds_t result; 86 | struct cmt *cmt; 87 | struct cmt_counter *c; 88 | 89 | cmt = cmt_create(); 90 | c = cmt_counter_create(cmt, "test", "dummy", "labels", "testing labels", 91 | 6, (char *[]) {"A", "B", "C", "D", "E", "F"}); 92 | 93 | cmt_counter_inc(c, 0, 6, (char *[]) {NULL,NULL,NULL,NULL,NULL,NULL}); 94 | cmt_counter_inc(c, 0, 6, (char *[]) {NULL,NULL,NULL,NULL,NULL,NULL}); 95 | result = cmt_encode_prometheus_create(cmt, CMT_TRUE); 96 | TEST_CHECK(strcmp(result, 97 | "# HELP test_dummy_labels testing labels\n" 98 | "# TYPE test_dummy_labels counter\n" 99 | "test_dummy_labels 2 0\n" 100 | ) == 0); 101 | cfl_sds_destroy(result); 102 | 103 | cmt_counter_inc(c, 0, 6, (char *[]) {NULL,"b",NULL,NULL,NULL,NULL}); 104 | result = cmt_encode_prometheus_create(cmt, CMT_TRUE); 105 | TEST_CHECK(strcmp(result, 106 | "# HELP test_dummy_labels testing labels\n" 107 | "# TYPE test_dummy_labels counter\n" 108 | "test_dummy_labels 2 0\n" 109 | "test_dummy_labels{B=\"b\"} 1 0\n" 110 | ) == 0); 111 | cfl_sds_destroy(result); 112 | 113 | cmt_counter_inc(c, 0, 6, (char *[]) {NULL,"b",NULL,NULL,NULL,NULL}); 114 | result = cmt_encode_prometheus_create(cmt, CMT_TRUE); 115 | TEST_CHECK(strcmp(result, 116 | "# HELP test_dummy_labels testing labels\n" 117 | "# TYPE test_dummy_labels counter\n" 118 | "test_dummy_labels 2 0\n" 119 | "test_dummy_labels{B=\"b\"} 2 0\n" 120 | ) == 0); 121 | cfl_sds_destroy(result); 122 | 123 | 124 | cmt_counter_set(c, 0, 5, 6, (char *[]) {NULL,NULL,NULL,"d",NULL,NULL}); 125 | result = cmt_encode_prometheus_create(cmt, CMT_TRUE); 126 | TEST_CHECK(strcmp(result, 127 | "# HELP test_dummy_labels testing labels\n" 128 | "# TYPE test_dummy_labels counter\n" 129 | "test_dummy_labels 2 0\n" 130 | "test_dummy_labels{B=\"b\"} 2 0\n" 131 | "test_dummy_labels{D=\"d\"} 5 0\n" 132 | ) == 0); 133 | cfl_sds_destroy(result); 134 | 135 | cmt_counter_set(c, 0, 50, 6, (char *[]) {NULL,"b",NULL,"d",NULL,"f"}); 136 | result = cmt_encode_prometheus_create(cmt, CMT_TRUE); 137 | TEST_CHECK(strcmp(result, 138 | "# HELP test_dummy_labels testing labels\n" 139 | "# TYPE test_dummy_labels counter\n" 140 | "test_dummy_labels 2 0\n" 141 | "test_dummy_labels{B=\"b\"} 2 0\n" 142 | "test_dummy_labels{D=\"d\"} 5 0\n" 143 | "test_dummy_labels{B=\"b\",D=\"d\",F=\"f\"} 50 0\n" 144 | ) == 0); 145 | cfl_sds_destroy(result); 146 | 147 | cmt_counter_inc(c, 0, 6, (char *[]) {"a","b","c","d","e","f"}); 148 | result = cmt_encode_prometheus_create(cmt, CMT_TRUE); 149 | TEST_CHECK(strcmp(result, 150 | "# HELP test_dummy_labels testing labels\n" 151 | "# TYPE test_dummy_labels counter\n" 152 | "test_dummy_labels 2 0\n" 153 | "test_dummy_labels{B=\"b\"} 2 0\n" 154 | "test_dummy_labels{D=\"d\"} 5 0\n" 155 | "test_dummy_labels{B=\"b\",D=\"d\",F=\"f\"} 50 0\n" 156 | "test_dummy_labels{A=\"a\",B=\"b\",C=\"c\",D=\"d\",E=\"e\",F=\"f\"} 1 0\n" 157 | ) == 0); 158 | cfl_sds_destroy(result); 159 | 160 | cmt_destroy(cmt); 161 | } 162 | 163 | TEST_LIST = { 164 | {"labels", test_labels}, 165 | {"encoding", test_encoding}, 166 | { 0 } 167 | }; 168 | -------------------------------------------------------------------------------- /src/cmt_counter.c: -------------------------------------------------------------------------------- 1 | /* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ 2 | 3 | /* CMetrics 4 | * ======== 5 | * Copyright 2021-2022 The CMetrics Authors 6 | * 7 | * Licensed under the Apache License, Version 2.0 (the "License"); 8 | * you may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | */ 19 | 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | 26 | struct cmt_counter *cmt_counter_create(struct cmt *cmt, 27 | char *ns, char *subsystem, 28 | char *name, char *help, 29 | int label_count, char **label_keys) 30 | { 31 | int ret; 32 | struct cmt_counter *counter; 33 | 34 | if (!ns) { 35 | cmt_log_error(cmt, "null ns not allowed"); 36 | return NULL; 37 | } 38 | 39 | if (!subsystem) { 40 | cmt_log_error(cmt, "null subsystem not allowed"); 41 | return NULL; 42 | } 43 | 44 | if (!name || strlen(name) == 0) { 45 | cmt_log_error(cmt, "undefined name"); 46 | return NULL; 47 | } 48 | 49 | if (!help || strlen(help) == 0) { 50 | cmt_log_error(cmt, "undefined help"); 51 | return NULL; 52 | } 53 | 54 | counter = calloc(1, sizeof(struct cmt_counter)); 55 | if (!counter) { 56 | cmt_errno(); 57 | return NULL; 58 | } 59 | cfl_list_add(&counter->_head, &cmt->counters); 60 | 61 | ret = cmt_opts_init(&counter->opts, ns, subsystem, name, help); 62 | if (ret == -1) { 63 | cmt_log_error(cmt, "unable to initialize options for counter"); 64 | cmt_counter_destroy(counter); 65 | return NULL; 66 | } 67 | 68 | /* Create the map */ 69 | counter->map = cmt_map_create(CMT_COUNTER, &counter->opts, label_count, label_keys, 70 | (void *) counter); 71 | if (!counter->map) { 72 | cmt_log_error(cmt, "unable to allocate map for counter"); 73 | cmt_counter_destroy(counter); 74 | return NULL; 75 | } 76 | /* set default counter aggregation type to cumulative */ 77 | counter->aggregation_type = CMT_AGGREGATION_TYPE_CUMULATIVE; 78 | 79 | counter->cmt = cmt; 80 | return counter; 81 | } 82 | 83 | void cmt_counter_allow_reset(struct cmt_counter *counter) 84 | { 85 | counter->allow_reset = 1; 86 | } 87 | 88 | int cmt_counter_destroy(struct cmt_counter *counter) 89 | { 90 | cfl_list_del(&counter->_head); 91 | cmt_opts_exit(&counter->opts); 92 | 93 | if (counter->map) { 94 | cmt_map_destroy(counter->map); 95 | } 96 | free(counter); 97 | return 0; 98 | } 99 | 100 | int cmt_counter_inc(struct cmt_counter *counter, 101 | uint64_t timestamp, 102 | int labels_count, char **label_vals) 103 | { 104 | struct cmt_metric *metric; 105 | 106 | metric = cmt_map_metric_get(&counter->opts, 107 | counter->map, labels_count, label_vals, 108 | CMT_TRUE); 109 | if (!metric) { 110 | cmt_log_error(counter->cmt, "unable to retrieve metric for counter %s_%s_%s", 111 | counter->opts.ns, counter->opts.subsystem, 112 | counter->opts.name); 113 | return -1; 114 | } 115 | cmt_metric_inc(metric, timestamp); 116 | return 0; 117 | } 118 | 119 | int cmt_counter_add(struct cmt_counter *counter, uint64_t timestamp, double val, 120 | int labels_count, char **label_vals) 121 | { 122 | struct cmt_metric *metric; 123 | 124 | metric = cmt_map_metric_get(&counter->opts, 125 | counter->map, labels_count, label_vals, 126 | CMT_TRUE); 127 | if (!metric) { 128 | cmt_log_error(counter->cmt, "unable to retrieve metric for counter %s_%s_%s", 129 | counter->opts.ns, counter->opts.subsystem, 130 | counter->opts.name); 131 | return -1; 132 | } 133 | cmt_metric_add(metric, timestamp, val); 134 | return 0; 135 | } 136 | 137 | /* Set counter value, new value cannot be smaller than current value */ 138 | int cmt_counter_set(struct cmt_counter *counter, uint64_t timestamp, double val, 139 | int labels_count, char **label_vals) 140 | { 141 | struct cmt_metric *metric; 142 | 143 | metric = cmt_map_metric_get(&counter->opts, counter->map, 144 | labels_count, label_vals, 145 | CMT_TRUE); 146 | if (!metric) { 147 | cmt_log_error(counter->cmt, "unable to retrieve metric for counter %s_%s_%s", 148 | counter->opts.ns, counter->opts.subsystem, 149 | counter->opts.name); 150 | return -1; 151 | } 152 | 153 | if (cmt_metric_get_value(metric) > val && counter->allow_reset == 0) { 154 | cmt_log_error(counter->cmt, "attempting to reset unresetable counter: %s_%s_%s", 155 | counter->opts.ns, counter->opts.subsystem, 156 | counter->opts.name); 157 | return -1; 158 | } 159 | cmt_metric_set(metric, timestamp, val); 160 | return 0; 161 | } 162 | 163 | int cmt_counter_get_val(struct cmt_counter *counter, 164 | int labels_count, char **label_vals, double *out_val) 165 | { 166 | int ret; 167 | double val = 0; 168 | 169 | ret = cmt_map_metric_get_val(&counter->opts, 170 | counter->map, labels_count, label_vals, 171 | &val); 172 | if (ret == -1) { 173 | cmt_log_error(counter->cmt, "unable to retrieve metric for counter %s_%s_%s", 174 | counter->opts.ns, counter->opts.subsystem, 175 | counter->opts.name); 176 | return -1; 177 | } 178 | *out_val = val; 179 | return 0; 180 | } 181 | -------------------------------------------------------------------------------- /src/cmt_gauge.c: -------------------------------------------------------------------------------- 1 | /* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ 2 | 3 | /* CMetrics 4 | * ======== 5 | * Copyright 2021-2022 The CMetrics Authors 6 | * 7 | * Licensed under the Apache License, Version 2.0 (the "License"); 8 | * you may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | */ 19 | 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | 27 | struct cmt_gauge *cmt_gauge_create(struct cmt *cmt, 28 | char *ns, char *subsystem, char *name, 29 | char *help, int label_count, char **label_keys) 30 | { 31 | int ret; 32 | struct cmt_gauge *gauge; 33 | 34 | if (!ns) { 35 | cmt_log_error(cmt, "null ns not allowed"); 36 | return NULL; 37 | } 38 | 39 | if (!subsystem) { 40 | cmt_log_error(cmt, "null subsystem not allowed"); 41 | return NULL; 42 | } 43 | 44 | if (!name || strlen(name) == 0) { 45 | cmt_log_error(cmt, "undefined name"); 46 | return NULL; 47 | } 48 | 49 | if (!help || strlen(help) == 0) { 50 | cmt_log_error(cmt, "undefined help"); 51 | return NULL; 52 | } 53 | 54 | gauge = calloc(1, sizeof(struct cmt_gauge)); 55 | if (!gauge) { 56 | cmt_errno(); 57 | return NULL; 58 | } 59 | cfl_list_add(&gauge->_head, &cmt->gauges); 60 | 61 | /* Initialize options */ 62 | ret = cmt_opts_init(&gauge->opts, ns, subsystem, name, help); 63 | if (ret == -1) { 64 | cmt_log_error(cmt, "unable to initialize options for gauge"); 65 | cmt_gauge_destroy(gauge); 66 | return NULL; 67 | } 68 | 69 | /* Create the map */ 70 | gauge->map = cmt_map_create(CMT_GAUGE, &gauge->opts, label_count, label_keys, 71 | (void *) gauge); 72 | if (!gauge->map) { 73 | cmt_log_error(cmt, "unable to allocate map for gauge"); 74 | cmt_gauge_destroy(gauge); 75 | return NULL; 76 | } 77 | 78 | gauge->cmt = cmt; 79 | 80 | return gauge; 81 | } 82 | 83 | int cmt_gauge_destroy(struct cmt_gauge *gauge) 84 | { 85 | cfl_list_del(&gauge->_head); 86 | cmt_opts_exit(&gauge->opts); 87 | if (gauge->map) { 88 | cmt_map_destroy(gauge->map); 89 | } 90 | free(gauge); 91 | return 0; 92 | } 93 | 94 | int cmt_gauge_set(struct cmt_gauge *gauge, uint64_t timestamp, double val, 95 | int labels_count, char **label_vals) 96 | { 97 | struct cmt_metric *metric; 98 | 99 | metric = cmt_map_metric_get(&gauge->opts, gauge->map, labels_count, label_vals, 100 | CMT_TRUE); 101 | if (!metric) { 102 | cmt_log_error(gauge->cmt, "unable to retrieve metric for gauge %s_%s_%s", 103 | gauge->opts.ns, gauge->opts.subsystem, 104 | gauge->opts.name); 105 | return -1; 106 | } 107 | cmt_metric_set(metric, timestamp, val); 108 | return 0; 109 | } 110 | 111 | int cmt_gauge_inc(struct cmt_gauge *gauge, uint64_t timestamp, 112 | int labels_count, char **label_vals) 113 | 114 | { 115 | struct cmt_metric *metric; 116 | 117 | metric = cmt_map_metric_get(&gauge->opts, gauge->map, labels_count, label_vals, 118 | CMT_TRUE); 119 | if (!metric) { 120 | cmt_log_error(gauge->cmt, "unable to retrieve metric for gauge %s_%s_%s", 121 | gauge->opts.ns, gauge->opts.subsystem, 122 | gauge->opts.name); 123 | return -1; 124 | } 125 | cmt_metric_inc(metric, timestamp); 126 | return 0; 127 | } 128 | 129 | int cmt_gauge_dec(struct cmt_gauge *gauge, uint64_t timestamp, 130 | int labels_count, char **label_vals) 131 | { 132 | struct cmt_metric *metric; 133 | 134 | metric = cmt_map_metric_get(&gauge->opts, gauge->map, labels_count, label_vals, 135 | CMT_TRUE); 136 | if (!metric) { 137 | cmt_log_error(gauge->cmt, "unable to retrieve metric for gauge %s_%s_%s", 138 | gauge->opts.ns, gauge->opts.subsystem, 139 | gauge->opts.name); 140 | return -1; 141 | } 142 | cmt_metric_dec(metric, timestamp); 143 | return 0; 144 | } 145 | 146 | int cmt_gauge_add(struct cmt_gauge *gauge, uint64_t timestamp, double val, 147 | int labels_count, char **label_vals) 148 | { 149 | struct cmt_metric *metric; 150 | 151 | metric = cmt_map_metric_get(&gauge->opts, gauge->map, labels_count, label_vals, 152 | CMT_TRUE); 153 | if (!metric) { 154 | cmt_log_error(gauge->cmt, "unable to retrieve metric for gauge %s_%s_%s", 155 | gauge->opts.ns, gauge->opts.subsystem, 156 | gauge->opts.name); 157 | return -1; 158 | } 159 | cmt_metric_add(metric, timestamp, val); 160 | return 0; 161 | } 162 | 163 | int cmt_gauge_sub(struct cmt_gauge *gauge, uint64_t timestamp, double val, 164 | int labels_count, char **label_vals) 165 | { 166 | struct cmt_metric *metric; 167 | 168 | metric = cmt_map_metric_get(&gauge->opts, gauge->map, labels_count, label_vals, 169 | CMT_TRUE); 170 | if (!metric) { 171 | cmt_log_error(gauge->cmt, "unable to retrieve metric for gauge %s_%s_%s", 172 | gauge->opts.ns, gauge->opts.subsystem, 173 | gauge->opts.name); 174 | return -1; 175 | } 176 | cmt_metric_sub(metric, timestamp, val); 177 | return 0; 178 | } 179 | 180 | int cmt_gauge_get_val(struct cmt_gauge *gauge, 181 | int labels_count, char **label_vals, double *out_val) 182 | { 183 | int ret; 184 | double val = 0; 185 | 186 | ret = cmt_map_metric_get_val(&gauge->opts, 187 | gauge->map, labels_count, label_vals, 188 | &val); 189 | if (ret == -1) { 190 | cmt_log_error(gauge->cmt, 191 | "unable to retrieve metric value for gauge %s_%s_%s", 192 | gauge->opts.ns, gauge->opts.subsystem, 193 | gauge->opts.name); 194 | return -1; 195 | } 196 | *out_val = val; 197 | return 0; 198 | } 199 | -------------------------------------------------------------------------------- /tests/prometheus_lexer.c: -------------------------------------------------------------------------------- 1 | /* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ 2 | 3 | /* CMetrics 4 | * ======== 5 | * Copyright 2021-2022 The CMetrics Authors 6 | * 7 | * Licensed under the Apache License, Version 2.0 (the "License"); 8 | * you may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | */ 19 | 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | 26 | #include "cmt_decode_prometheus_parser.h" 27 | #include "cmt_tests.h" 28 | 29 | struct fixture { 30 | yyscan_t scanner; 31 | YY_BUFFER_STATE buf; 32 | YYSTYPE lval; 33 | struct cmt_decode_prometheus_context context; 34 | const char *text; 35 | }; 36 | 37 | struct fixture *init(const char *test) 38 | { 39 | struct fixture *f = malloc(sizeof(*f)); 40 | memset(f, 0, sizeof(*f)); 41 | cmt_decode_prometheus_lex_init(&f->scanner); 42 | f->buf = cmt_decode_prometheus__scan_string(test, f->scanner); 43 | return f; 44 | } 45 | 46 | void destroy(struct fixture *f) 47 | { 48 | cmt_decode_prometheus__delete_buffer(f->buf, f->scanner); 49 | cmt_decode_prometheus_lex_destroy(f->scanner); 50 | free(f); 51 | } 52 | 53 | int lex(struct fixture *f) 54 | { 55 | return cmt_decode_prometheus_lex(&f->lval, f->scanner, &(f->context)); 56 | } 57 | 58 | void test_comment() 59 | { 60 | struct fixture *f = init("# this is just a comment"); 61 | TEST_CHECK(lex(f) == 0); // 0 means EOF 62 | destroy(f); 63 | } 64 | 65 | void test_help() 66 | { 67 | struct fixture *f = init("# HELP cmt_labels_test Static \\\\labels\\n test"); 68 | 69 | TEST_CHECK(lex(f) == HELP); 70 | TEST_CHECK(strcmp(f->lval.str, "cmt_labels_test") == 0); 71 | cfl_sds_destroy(f->lval.str); 72 | 73 | TEST_CHECK(lex(f) == METRIC_DOC); 74 | TEST_CHECK(strcmp(f->lval.str, "Static \\labels\n test") == 0); 75 | cfl_sds_destroy(f->lval.str); 76 | 77 | destroy(f); 78 | 79 | f = init("# HELP cmt_labels_test Static \\\\labels\\n test\n"); 80 | 81 | TEST_CHECK(lex(f) == HELP); 82 | TEST_CHECK(strcmp(f->lval.str, "cmt_labels_test") == 0); 83 | cfl_sds_destroy(f->lval.str); 84 | 85 | TEST_CHECK(lex(f) == METRIC_DOC); 86 | TEST_CHECK(strcmp(f->lval.str, "Static \\labels\n test") == 0); 87 | cfl_sds_destroy(f->lval.str); 88 | 89 | destroy(f); 90 | } 91 | 92 | void test_type() 93 | { 94 | struct fixture *f = init("# TYPE metric_name gauge"); 95 | 96 | TEST_CHECK(lex(f) == TYPE); 97 | TEST_CHECK(strcmp(f->lval.str, "metric_name") == 0); 98 | cfl_sds_destroy(f->lval.str); 99 | 100 | TEST_CHECK(lex(f) == GAUGE); 101 | 102 | destroy(f); 103 | } 104 | 105 | void test_simple() 106 | { 107 | struct fixture *f = init( 108 | "# HELP cmt_labels_test Static labels test\n" 109 | "# TYPE cmt_labels_test counter\n" 110 | "cmt_labels_test 1 0\n" 111 | "metric2{host=\"calyptia.com\",app=\"cmetrics \\n \\\\ \\\"\"} 2.5 0\n" 112 | "# HELP metric1 Second HELP tag\n" 113 | "metric1{escapes=\"\\n \\\\ \\\"\"} 4.12 5\n" 114 | ); 115 | 116 | TEST_CHECK(lex(f) == HELP); 117 | TEST_CHECK(strcmp(f->lval.str, "cmt_labels_test") == 0); 118 | cfl_sds_destroy(f->lval.str); 119 | 120 | TEST_CHECK(lex(f) == METRIC_DOC); 121 | TEST_CHECK(strcmp(f->lval.str, "Static labels test") == 0); 122 | cfl_sds_destroy(f->lval.str); 123 | 124 | TEST_CHECK(lex(f) == TYPE); 125 | TEST_CHECK(strcmp(f->lval.str, "cmt_labels_test") == 0); 126 | cfl_sds_destroy(f->lval.str); 127 | 128 | TEST_CHECK(lex(f) == COUNTER); 129 | 130 | TEST_CHECK(lex(f) == IDENTIFIER); 131 | TEST_CHECK(strcmp(f->lval.str, "cmt_labels_test") == 0); 132 | cfl_sds_destroy(f->lval.str); 133 | 134 | TEST_CHECK(lex(f) == NUMSTR); 135 | TEST_CHECK(strcmp(f->lval.numstr, "1") == 0); 136 | 137 | TEST_CHECK(lex(f) == NUMSTR); 138 | TEST_CHECK(strcmp(f->lval.numstr, "0") == 0); 139 | 140 | TEST_CHECK(lex(f) == IDENTIFIER); 141 | TEST_CHECK(strcmp(f->lval.str, "metric2") == 0); 142 | cfl_sds_destroy(f->lval.str); 143 | 144 | TEST_CHECK(lex(f) == '{'); 145 | 146 | TEST_CHECK(lex(f) == IDENTIFIER); 147 | TEST_CHECK(strcmp(f->lval.str, "host") == 0); 148 | cfl_sds_destroy(f->lval.str); 149 | 150 | TEST_CHECK(lex(f) == '='); 151 | 152 | TEST_CHECK(lex(f) == QUOTED); 153 | TEST_CHECK(strcmp(f->lval.str, "calyptia.com") == 0); 154 | cfl_sds_destroy(f->lval.str); 155 | 156 | TEST_CHECK(lex(f) == ','); 157 | 158 | TEST_CHECK(lex(f) == IDENTIFIER); 159 | TEST_CHECK(strcmp(f->lval.str, "app") == 0); 160 | cfl_sds_destroy(f->lval.str); 161 | 162 | TEST_CHECK(lex(f) == '='); 163 | 164 | TEST_CHECK(lex(f) == QUOTED); 165 | TEST_CHECK(strcmp(f->lval.str, "cmetrics \n \\ \"") == 0); 166 | cfl_sds_destroy(f->lval.str); 167 | 168 | TEST_CHECK(lex(f) == '}'); 169 | 170 | TEST_CHECK(lex(f) == NUMSTR); 171 | TEST_CHECK(strcmp(f->lval.numstr, "2.5") == 0); 172 | 173 | TEST_CHECK(lex(f) == NUMSTR); 174 | TEST_CHECK(strcmp(f->lval.numstr, "0") == 0); 175 | 176 | TEST_CHECK(lex(f) == HELP); 177 | TEST_CHECK(strcmp(f->lval.str, "metric1") == 0); 178 | cfl_sds_destroy(f->lval.str); 179 | 180 | TEST_CHECK(lex(f) == METRIC_DOC); 181 | TEST_CHECK(strcmp(f->lval.str, "Second HELP tag") == 0); 182 | cfl_sds_destroy(f->lval.str); 183 | 184 | TEST_CHECK(lex(f) == IDENTIFIER); 185 | TEST_CHECK(strcmp(f->lval.str, "metric1") == 0); 186 | cfl_sds_destroy(f->lval.str); 187 | 188 | TEST_CHECK(lex(f) == '{'); 189 | 190 | TEST_CHECK(lex(f) == IDENTIFIER); 191 | TEST_CHECK(strcmp(f->lval.str, "escapes") == 0); 192 | cfl_sds_destroy(f->lval.str); 193 | 194 | TEST_CHECK(lex(f) == '='); 195 | 196 | TEST_CHECK(lex(f) == QUOTED); 197 | TEST_CHECK(strcmp(f->lval.str, "\n \\ \"") == 0); 198 | cfl_sds_destroy(f->lval.str); 199 | 200 | TEST_CHECK(lex(f) == '}'); 201 | 202 | TEST_CHECK(lex(f) == NUMSTR); 203 | TEST_CHECK(strcmp(f->lval.numstr, "4.12") == 0); 204 | 205 | TEST_CHECK(lex(f) == NUMSTR); 206 | TEST_CHECK(strcmp(f->lval.numstr, "5") == 0); 207 | 208 | destroy(f); 209 | } 210 | 211 | 212 | TEST_LIST = { 213 | {"test_comment", test_comment}, 214 | {"test_help", test_help}, 215 | {"test_type", test_type}, 216 | {"test_simple", test_simple}, 217 | { 0 } 218 | }; 219 | -------------------------------------------------------------------------------- /tests/histogram.c: -------------------------------------------------------------------------------- 1 | /* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ 2 | 3 | /* CMetrics 4 | * ======== 5 | * Copyright 2021-2022 The CMetrics Authors 6 | * 7 | * Licensed under the Apache License, Version 2.0 (the "License"); 8 | * you may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | */ 19 | 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include "cmt_tests.h" 25 | 26 | #include 27 | #include 28 | #include 29 | 30 | /* values to observe in a histogram */ 31 | double hist_observe_values[10] = { 32 | 0.0 , 1.02, 2.04, 3.06, 33 | 4.08, 5.10, 6.12, 7.14, 34 | 8.16, 9.18 35 | }; 36 | 37 | /* 38 | * histogram bucket values: the values computed in the buckets, 39 | * all of them are uint64_t. 40 | * 41 | * Note that on all examples we use the default buckets values, created manually 42 | * and through the API: 43 | * 44 | * - 11 bucket values 45 | * - 1 +Inf bucket value 46 | */ 47 | uint64_t hist_buckets_values[12] = {1, 1, 1, 1, 1, 1, 1, 1, 48 | 3, 5, 10, 10}; 49 | 50 | /* histogram _count value */ 51 | uint64_t hist_count = 10; 52 | 53 | /* histogram _sum value */ 54 | double hist_sum = 45.9; 55 | 56 | bool fequal(double a, double b) 57 | { 58 | return (fabs(a - b) < (DBL_EPSILON * fabs(a + b))); 59 | } 60 | 61 | static void histogram_check(struct cmt_histogram *h, 62 | int labels_count, char **labels_vals) 63 | { 64 | int i; 65 | int ret; 66 | uint64_t val; 67 | struct cmt_metric *metric; 68 | 69 | /* retrieve the metric context */ 70 | metric = cmt_map_metric_get(&h->opts, h->map, 71 | labels_count, labels_vals, CMT_TRUE); 72 | TEST_CHECK(metric != NULL); 73 | 74 | /* check bucket values */ 75 | for (i = 0; i < (sizeof(hist_buckets_values)/sizeof(uint64_t)); i++) { 76 | val = cmt_metric_hist_get_value(metric, i); 77 | TEST_CHECK(val == hist_buckets_values[i]); 78 | } 79 | 80 | /* check _count */ 81 | TEST_CHECK(hist_count == cmt_metric_hist_get_count_value(metric)); 82 | 83 | /* check _sum */ 84 | ret = fequal(hist_sum, cmt_metric_hist_get_sum_value(metric)); 85 | TEST_CHECK(ret != 0); 86 | } 87 | 88 | static int histogram_observe_all(struct cmt_histogram *h, 89 | uint64_t timestamp, 90 | int labels_count, char **labels_vals) 91 | { 92 | int i; 93 | double val; 94 | 95 | for (i = 0; i < sizeof(hist_observe_values)/(sizeof(double)); i++) { 96 | val = hist_observe_values[i]; 97 | cmt_histogram_observe(h, timestamp, val, labels_count, labels_vals); 98 | } 99 | 100 | return i; 101 | } 102 | 103 | static void prometheus_encode_test(struct cmt *cmt) 104 | { 105 | cfl_sds_t buf; 106 | 107 | buf = cmt_encode_prometheus_create(cmt, CMT_FALSE); 108 | printf("\n%s\n", buf); 109 | cmt_encode_prometheus_destroy(buf); 110 | } 111 | 112 | 113 | void test_histogram() 114 | { 115 | uint64_t ts; 116 | struct cmt *cmt; 117 | struct cmt_histogram *h; 118 | struct cmt_histogram_buckets *buckets; 119 | 120 | cmt_initialize(); 121 | 122 | /* Timestamp */ 123 | ts = cfl_time_now(); 124 | 125 | /* CMetrics context */ 126 | cmt = cmt_create(); 127 | TEST_CHECK(cmt != NULL); 128 | 129 | /* Create buckets */ 130 | buckets = cmt_histogram_buckets_create(11, 131 | 0.005, 0.01, 0.025, 0.05, 132 | 0.1, 0.25, 0.5, 1.0, 2.5, 133 | 5.0, 10.0); 134 | TEST_CHECK(buckets != NULL); 135 | 136 | /* Create a gauge metric type */ 137 | h = cmt_histogram_create(cmt, 138 | "k8s", "network", "load", "Network load", 139 | buckets, 140 | 1, (char *[]) {"my_label"}); 141 | TEST_CHECK(h != NULL); 142 | 143 | /* no labels */ 144 | histogram_observe_all(h, ts, 0, NULL); 145 | histogram_check(h, 0, NULL); 146 | prometheus_encode_test(cmt); 147 | 148 | /* static label: register static label for the context */ 149 | cmt_label_add(cmt, "static", "test"); 150 | histogram_check(h, 0, NULL); 151 | prometheus_encode_test(cmt); 152 | 153 | /* defined labels: add a custom label value */ 154 | histogram_observe_all(h, ts, 1, (char *[]) {"val"}); 155 | histogram_check(h, 1, (char *[]) {"val"}); 156 | prometheus_encode_test(cmt); 157 | 158 | cmt_destroy(cmt); 159 | } 160 | 161 | void test_set_defaults() 162 | { 163 | uint64_t ts; 164 | struct cmt *cmt; 165 | struct cmt_histogram *h; 166 | struct cmt_histogram_buckets *buckets; 167 | 168 | cmt_initialize(); 169 | 170 | /* Timestamp */ 171 | ts = cfl_time_now(); 172 | 173 | /* CMetrics context */ 174 | cmt = cmt_create(); 175 | TEST_CHECK(cmt != NULL); 176 | 177 | /* Create buckets */ 178 | buckets = cmt_histogram_buckets_default_create(); 179 | TEST_CHECK(buckets != NULL); 180 | 181 | /* Create a gauge metric type */ 182 | h = cmt_histogram_create(cmt, 183 | "k8s", "network", "load", "Network load", 184 | buckets, 185 | 1, (char *[]) {"my_label"}); 186 | TEST_CHECK(h != NULL); 187 | 188 | /* set default buckets values / no labels */ 189 | cmt_histogram_set_default(h, ts, 190 | hist_buckets_values, 191 | hist_sum, hist_count, 0, NULL); 192 | histogram_check(h, 0, NULL); 193 | prometheus_encode_test(cmt); 194 | 195 | /* static label: register static label for the context */ 196 | cmt_label_add(cmt, "static", "test"); 197 | histogram_check(h, 0, NULL); 198 | prometheus_encode_test(cmt); 199 | 200 | /* perform observation with labels */ 201 | histogram_observe_all(h, ts, 1, (char *[]) {"val"}); 202 | histogram_check(h, 1, (char *[]) {"val"}); 203 | prometheus_encode_test(cmt); 204 | 205 | cmt_destroy(cmt); 206 | } 207 | 208 | TEST_LIST = { 209 | {"histogram" , test_histogram}, 210 | {"set_defaults", test_set_defaults}, 211 | { 0 } 212 | }; 213 | -------------------------------------------------------------------------------- /tests/counter.c: -------------------------------------------------------------------------------- 1 | /* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ 2 | 3 | /* CMetrics 4 | * ======== 5 | * Copyright 2021-2022 The CMetrics Authors 6 | * 7 | * Licensed under the Apache License, Version 2.0 (the "License"); 8 | * you may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | */ 19 | 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | 27 | #include "cmt_tests.h" 28 | 29 | static struct cmt *generate_encoder_test_data() 30 | { 31 | double val; 32 | uint64_t ts; 33 | struct cmt *cmt; 34 | struct cmt_counter *c; 35 | 36 | printf("version: %s", cmt_version()); 37 | cmt = cmt_create(); 38 | 39 | c = cmt_counter_create(cmt, "kubernetes", "network", "load", "Network load", 40 | 2, (char *[]) {"hostname", "app"}); 41 | 42 | ts = cfl_time_now(); 43 | 44 | cmt_counter_get_val(c, 0, NULL, &val); 45 | cmt_counter_inc(c, ts, 0, NULL); 46 | cmt_counter_add(c, ts, 2, 0, NULL); 47 | cmt_counter_get_val(c, 0, NULL, &val); 48 | 49 | cmt_counter_inc(c, ts, 2, (char *[]) {"localhost", "cmetrics"}); 50 | cmt_counter_get_val(c, 2, (char *[]) {"localhost", "cmetrics"}, &val); 51 | cmt_counter_add(c, ts, 10.55, 2, (char *[]) {"localhost", "test"}); 52 | cmt_counter_get_val(c, 2, (char *[]) {"localhost", "test"}, &val); 53 | cmt_counter_set(c, ts, 12.15, 2, (char *[]) {"localhost", "test"}); 54 | cmt_counter_set(c, ts, 1, 2, (char *[]) {"localhost", "test"}); 55 | 56 | return cmt; 57 | } 58 | 59 | void test_msgpack() 60 | { 61 | struct cmt *cmt = NULL; 62 | struct cmt *cmt2 = NULL; 63 | int result = 0; 64 | size_t offset = 0; 65 | char *msgpack_buffer_a = NULL; 66 | char *msgpack_buffer_b = NULL; 67 | size_t msgpack_buffer_size_a = 0; 68 | size_t msgpack_buffer_size_b = 0; 69 | 70 | cmt_initialize(); 71 | 72 | cmt = generate_encoder_test_data(); 73 | TEST_CHECK(NULL != cmt); 74 | 75 | result = cmt_encode_msgpack_create(cmt, &msgpack_buffer_a, &msgpack_buffer_size_a); 76 | TEST_CHECK(0 == result); 77 | 78 | result = cmt_decode_msgpack_create(&cmt2, msgpack_buffer_a, msgpack_buffer_size_a, 79 | &offset); 80 | TEST_CHECK(0 == result); 81 | 82 | result = cmt_encode_msgpack_create(cmt, &msgpack_buffer_b, &msgpack_buffer_size_b); 83 | TEST_CHECK(0 == result); 84 | 85 | TEST_CHECK(msgpack_buffer_size_a == msgpack_buffer_size_b); 86 | 87 | result = memcmp(msgpack_buffer_a, msgpack_buffer_b, msgpack_buffer_size_a); 88 | 89 | cmt_destroy(cmt); 90 | cmt_decode_msgpack_destroy(cmt2); 91 | cmt_encode_msgpack_destroy(msgpack_buffer_a); 92 | cmt_encode_msgpack_destroy(msgpack_buffer_b); 93 | } 94 | 95 | void test_prometheus() 96 | { 97 | struct cmt *cmt = NULL; 98 | cfl_sds_t prom = NULL; 99 | 100 | cmt_initialize(); 101 | 102 | cmt = generate_encoder_test_data(); 103 | TEST_CHECK(NULL != cmt); 104 | 105 | prom = cmt_encode_prometheus_create(cmt, CMT_TRUE); 106 | TEST_CHECK(NULL != prom); 107 | printf("%s\n", prom); 108 | 109 | cmt_destroy(cmt); 110 | cmt_encode_prometheus_destroy(prom); 111 | } 112 | 113 | void test_text() 114 | { 115 | struct cmt *cmt = NULL; 116 | cfl_sds_t text = NULL; 117 | 118 | cmt_initialize(); 119 | 120 | cmt = generate_encoder_test_data(); 121 | TEST_CHECK(cmt != NULL); 122 | 123 | text = cmt_encode_text_create(cmt); 124 | TEST_CHECK(text != NULL); 125 | 126 | cmt_destroy(cmt); 127 | cmt_encode_text_destroy(text); 128 | } 129 | 130 | 131 | void test_counter() 132 | { 133 | int ret; 134 | double val = 1; 135 | uint64_t ts; 136 | struct cmt *cmt; 137 | struct cmt_counter *c; 138 | 139 | cmt_initialize(); 140 | 141 | cmt = cmt_create(); 142 | TEST_CHECK(cmt != NULL); 143 | 144 | /* Create a counter metric type */ 145 | c = cmt_counter_create(cmt, "kubernetes", "network", "load", "Network load", 146 | 0, NULL); 147 | TEST_CHECK(c != NULL); 148 | 149 | /* Timestamp */ 150 | ts = cfl_time_now(); 151 | 152 | /* Default value */ 153 | ret = cmt_counter_get_val(c, 0, NULL, &val); 154 | TEST_CHECK(ret == 0); 155 | TEST_CHECK(val == 0.0); 156 | 157 | /* Increment by one */ 158 | cmt_counter_inc(c, ts, 0, NULL); 159 | ret = cmt_counter_get_val(c, 0, NULL, &val); 160 | TEST_CHECK(val == 1.0); 161 | 162 | /* Add two */ 163 | cmt_counter_add(c, ts, 2, 0, NULL); 164 | ret = cmt_counter_get_val(c, 0, NULL, &val); 165 | 166 | TEST_CHECK(ret == 0); 167 | TEST_CHECK(val == 3.0); 168 | 169 | cmt_destroy(cmt); 170 | } 171 | 172 | void test_labels() 173 | { 174 | int ret; 175 | double val; 176 | uint64_t ts; 177 | struct cmt *cmt; 178 | struct cmt_counter *c; 179 | 180 | cmt_initialize(); 181 | 182 | cmt = cmt_create(); 183 | TEST_CHECK(cmt != NULL); 184 | 185 | /* Create a counter metric type */ 186 | c = cmt_counter_create(cmt, "kubernetes", "network", "load", "Network load", 187 | 2, (char *[]) {"hostname", "app"}); 188 | TEST_CHECK(c != NULL); 189 | 190 | /* Timestamp */ 191 | ts = cfl_time_now(); 192 | 193 | /* 194 | * Test 1: hash zero (no labels) 195 | * ----------------------------- 196 | */ 197 | 198 | /* 199 | * Default value: this call should fail since the metric has not been 200 | * initialized. 201 | */ 202 | ret = cmt_counter_get_val(c, 0, NULL, &val); 203 | TEST_CHECK(ret == -1); 204 | 205 | /* Increment hash zero by 1 */ 206 | ret = cmt_counter_inc(c, ts, 0, NULL); 207 | TEST_CHECK(ret == 0); 208 | 209 | /* validate value */ 210 | ret = cmt_counter_get_val(c, 0, NULL, &val); 211 | TEST_CHECK(ret == 0); 212 | TEST_CHECK(val == 1.0); 213 | 214 | /* Add two */ 215 | ret = cmt_counter_add(c, ts, 2, 0, NULL); 216 | TEST_CHECK(ret == 0); 217 | 218 | /* Check that hash zero val is 3.0 */ 219 | ret = cmt_counter_get_val(c, 0, NULL, &val); 220 | TEST_CHECK(ret == 0); 221 | TEST_CHECK(val == 3.0); 222 | 223 | /* 224 | * Test 2: custom labels 225 | * --------------------- 226 | */ 227 | 228 | /* Increment custom metric */ 229 | ret = cmt_counter_inc(c, ts, 2, (char *[]) {"localhost", "cmetrics"}); 230 | TEST_CHECK(ret == 0); 231 | 232 | /* Check val = 1 */ 233 | ret = cmt_counter_get_val(c, 2, (char *[]) {"localhost", "cmetrics"}, &val); 234 | TEST_CHECK(ret == 0); 235 | TEST_CHECK(val == 1.000); 236 | 237 | /* Add 10 to another metric using a different second label */ 238 | ret = cmt_counter_add(c, ts, 10.55, 2, (char *[]) {"localhost", "test"}); 239 | TEST_CHECK(ret == 0); 240 | 241 | /* Validate the value */ 242 | ret = cmt_counter_get_val(c, 2, (char *[]) {"localhost", "test"}, &val); 243 | TEST_CHECK(ret == 0); 244 | TEST_CHECK(val == 10.55); 245 | 246 | /* Valid counter set */ 247 | ret = cmt_counter_set(c, ts, 12.15, 2, (char *[]) {"localhost", "test"}); 248 | TEST_CHECK(ret == 0); 249 | 250 | /* Invalid counter set */ 251 | ret = cmt_counter_set(c, ts, 1, 2, (char *[]) {"localhost", "test"}); 252 | TEST_CHECK(ret == -1); 253 | 254 | cmt_destroy(cmt); 255 | } 256 | 257 | TEST_LIST = { 258 | {"basic", test_counter}, 259 | {"labels", test_labels}, 260 | {"msgpack", test_msgpack}, 261 | {"prometheus", test_prometheus}, 262 | {"text", test_text}, 263 | { 0 } 264 | }; 265 | --------------------------------------------------------------------------------