{"id":13677678,"url":"https://github.com/DarkWanderer/metrics-cpp","last_synced_at":"2025-04-29T11:31:35.160Z","repository":{"id":91423886,"uuid":"589559756","full_name":"DarkWanderer/metrics-cpp","owner":"DarkWanderer","description":"High-performance metrics library","archived":false,"fork":false,"pushed_at":"2024-07-28T13:25:10.000Z","size":211,"stargazers_count":3,"open_issues_count":2,"forks_count":1,"subscribers_count":3,"default_branch":"main","last_synced_at":"2024-08-02T13:19:03.821Z","etag":null,"topics":["cpp","metrics","performance","statsd"],"latest_commit_sha":null,"homepage":"","language":"C++","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/DarkWanderer.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2023-01-16T12:07:37.000Z","updated_at":"2024-07-28T13:25:12.000Z","dependencies_parsed_at":"2023-12-18T11:46:30.491Z","dependency_job_id":"83346f4c-51f2-41e6-acbf-80b35b250b8e","html_url":"https://github.com/DarkWanderer/metrics-cpp","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/DarkWanderer%2Fmetrics-cpp","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/DarkWanderer%2Fmetrics-cpp/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/DarkWanderer%2Fmetrics-cpp/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/DarkWanderer%2Fmetrics-cpp/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/DarkWanderer","download_url":"https://codeload.github.com/DarkWanderer/metrics-cpp/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":224163716,"owners_count":17266557,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["cpp","metrics","performance","statsd"],"created_at":"2024-08-02T13:00:45.706Z","updated_at":"2025-04-29T11:31:35.151Z","avatar_url":"https://github.com/DarkWanderer.png","language":"C++","readme":"﻿# metrics-cpp\n\n[![Build](https://github.com/DarkWanderer/metrics-cpp/actions/workflows/build.yml/badge.svg)](https://github.com/DarkWanderer/metrics-cpp/actions/workflows/build.yml)\n![Readiness](https://img.shields.io/badge/readiness-beta-yellow)\n\nA low-footprint, high-performance C++ metrics library implementing commonly used metric classes - Counter, Gauge, Histogram, Summary - in idiomatic and thread-safe faction\n\n## Design goals\n\nThe design goals of this library are the following:\n\n* Be as lightweight as possible - all operations on Counter, Gauge, Histogram are lock-free using atomic operations\n* Allow to think of instrumenting first and exposition later\n* Provide easy to use API\n\n## Key features\n\n* Provides commonly used metric classes\n* A number of out-the-box optimizations\n  * all metrics except Summary are lock-free\n  * Labels are optimized for cache locality (vector instead of std::map; make sure to use a compiler which takes advantage of [SSO](https://pvs-studio.com/en/blog/terms/6658/))\n  * Minimized locking for operations in Registry\n* Various methods of serialization\n  * Prometheus\n  * JSON/JSONL\n  * statsd\n* Cross-platform (built for Windows, Ubuntu, MacOS)\n\n## Limitations \u0026 compromises\n\n* Due to limited number of locks employed, there is no strong consistency guarantee between different metrics\n* If a particular thread changes two counters and serialization happens in the middle, you may see a value for one counter increasing but not for the other - until the next time metrics are collected. Hence, care must be taken when creating alerts based on metrics differential\n* For same reason, histogram 'sum' may be out of sync with total count - skewing the average value with ⅟n asymptotic upper bound\n* It's not possible to _remove_ metrics from a `Registry` - conceptually shared with Prometheus\n* Boost::accumulators do not correctly work under MacOS, which prevents Summary class from working there - more throrough investigation pending\n\n## Readiness\n\n|Feature|Readiness|\n|----|----|\n|Core API|![GA](https://img.shields.io/badge/GA-green)|\n|Serialization: JSON|![icon](https://img.shields.io/badge/GA-green)|\n|Serialization: Prometheus|![icon](https://img.shields.io/badge/GA-green)|\n|Sink: Statsd UDP|![icon](https://img.shields.io/badge/beta-yellow)|\n|Sink: Statsd TCP|![icon](https://img.shields.io/badge/beta-yellow)|\n|Sink: PushGateway|![icon](https://img.shields.io/badge/disabled-red)|\n|Sink: Prometheus HTTP|![icon](https://img.shields.io/badge/beta-yellow)|\n\n## Performance\n\nPerformance of metrics is comparable to `atomic` primitives - even with pointer indirection\n\n```\nRun on (24 X 3700 MHz CPU s)\nCPU Caches:\n  L1 Data 32 KiB (x12)\n  L1 Instruction 32 KiB (x12)\n  L2 Unified 512 KiB (x12)\n  L3 Unified 32768 KiB (x2)\n-----------------------------------------------------------------------\nBenchmark                             Time             CPU   Iterations\n-----------------------------------------------------------------------\nBM_Reference_AtomicIncrement       1.50 ns         1.51 ns    497777778\nBM_CounterIncrement                1.34 ns         1.34 ns    560000000\nBM_GaugeSet                        1.84 ns         1.84 ns    407272727\nBM_Histogram2Observe               4.24 ns         4.20 ns    160000000\nBM_Histogram5Observe               4.70 ns         4.60 ns    149333333\nBM_Histogram10Observe              5.37 ns         5.47 ns    100000000\nBM_SummaryObserve                  9.13 ns         9.21 ns     74666667\nBM_RegistryGet                     39.2 ns         39.2 ns     17920000\nBM_RegistryGetLabels                138 ns          138 ns      4977778\n```\n\n## Usage examples\n\n### Quickstart\n\nThe library API was designed to provide a low barrier for entry:\n\n```cpp\n    auto metrics = createRegistry();\n    metrics-\u003egetCounter( \"birds\", {{ \"kind\", \"pigeon\" }} )++;\n    metrics-\u003egetCounter( \"birds\", {{ \"kind\", \"sparrow\" }} )+=10;\n    metrics-\u003egetGauge( \"tiredness\" ) += 1.5;\n    \n    cout \u003c\u003c \"The library supports outputting metrics in Prometheus format:\" \u003c\u003c endl \u003c\u003c serializePrometheus(*metrics) \u003c\u003c endl;\n    cout \u003c\u003c \"And in JSON format:\" \u003c\u003c endl \u003c\u003c serializeJsonl(*metrics) \u003c\u003c endl;\n```\n\nFor further information on using library via CMake, see [this sample](https://github.com/DarkWanderer/metrics-cpp/tree/main/samples/cmake)\n\n### Standalone metrics\n\n```cpp\nCounter c1;\nauto c2 = c1; // Another object shares same underlying metric\nc2++;\ncout \u003c\u003c c1.value(); // 1\n```\n\n### Working with registry\n\n`Registry` is a class representing grouping of metrics within the application. Usually you would have a single `registry` per application or application domain. You can create metrics from within the registry:\n\n```cpp\nauto registry = createRegistry();\nauto gauge = registry-\u003egetGauge(\"my_gauge\", {{\"some\", \"label\"}});\ngauge = 10.0;\n```\n\nOr add existing metrics with a key:\n\n```cpp\nGauge gauge;\ngauge = 5;\nauto registry = createRegistry();\nregistry-\u003eadd(\"my_gauge\", {{\"some\", \"label\"}}, gauge);\ncout \u003c\u003c registry-\u003egetGauge(\"my_gauge\", {{\"some\", \"label\"}}).value(); // 5\n```\n\nThe recommended pattern is to instrument low-level code using standalone metrics and then add the needed metrics to a `registry` instance - this way, you can track same metrics under different names in different contexts\n\n### Serialization\n\n```cpp\nauto registry = createRegistry();\nauto gauge = registry-\u003egetGauge(\"my_gauge\", {{\"some\", \"label\"}});\nauto p = serializePrometheus(registry);\nauto j = serializeJson(registry);\nauto s = serializeStatsd(registry);\n```\n\n### Timers\n\n```cpp\nHistogram histogram({1., 2., 5., 10.});\nfor (auto file: files)\n{\n    Timer\u003cstd::chrono::seconds\u003e timer(histogram); // Adds an observation to the histogram on scope exit\n    process_file(file);\n}\n```\n\n### Sinks\n\nSinks can be created explicitly by type or from a URL. In latter case, specific sink type is derived from URL schema, e.g. `statsd+udp` or `pushgateway+http`\n\n```cpp\n// Set this value in config\nstd::string url = \"statsd+udp://localhost:1234\"; \n\nauto registry = createRegistry();\nauto gauge = registry-\u003egetGauge(\"my_gauge\", {{\"some\", \"label\"}});\ngauge = 5.0;\nauto sink = createOnDemandSink(url);\nif (sink)\n    sink-\u003esend(registry);\n```\n","funding_links":[],"categories":["C++"],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FDarkWanderer%2Fmetrics-cpp","html_url":"https://awesome.ecosyste.ms/projects/github.com%2FDarkWanderer%2Fmetrics-cpp","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FDarkWanderer%2Fmetrics-cpp/lists"}