{"id":42136464,"url":"https://github.com/trafficstars/metrics","last_synced_at":"2026-01-26T16:14:05.308Z","repository":{"id":52499322,"uuid":"170334477","full_name":"trafficstars/metrics","owner":"trafficstars","description":"An implementation of fast metrics for high-load-ed services on Golang","archived":false,"fork":false,"pushed_at":"2021-04-27T15:10:06.000Z","size":7806,"stargazers_count":5,"open_issues_count":1,"forks_count":4,"subscribers_count":7,"default_branch":"master","last_synced_at":"2024-11-16T14:11:36.426Z","etag":null,"topics":["fast","golang","grafana","metrics","prometheus","registry","statsd"],"latest_commit_sha":null,"homepage":"","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"other","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/trafficstars.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}},"created_at":"2019-02-12T14:44:00.000Z","updated_at":"2023-10-22T06:43:33.000Z","dependencies_parsed_at":"2022-09-01T21:02:24.180Z","dependency_job_id":null,"html_url":"https://github.com/trafficstars/metrics","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/trafficstars/metrics","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/trafficstars%2Fmetrics","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/trafficstars%2Fmetrics/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/trafficstars%2Fmetrics/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/trafficstars%2Fmetrics/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/trafficstars","download_url":"https://codeload.github.com/trafficstars/metrics/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/trafficstars%2Fmetrics/sbom","scorecard":{"id":896593,"data":{"date":"2025-08-11","repo":{"name":"github.com/trafficstars/metrics","commit":"0250d8a27518636f3c7ac48ec726b84fefd7c4e8"},"scorecard":{"version":"v5.2.1-40-gf6ed084d","commit":"f6ed084d17c9236477efd66e5b258b9d4cc7b389"},"score":3,"checks":[{"name":"Dangerous-Workflow","score":-1,"reason":"no workflows found","details":null,"documentation":{"short":"Determines if the project's GitHub Action workflows avoid dangerous patterns.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#dangerous-workflow"}},{"name":"Maintained","score":0,"reason":"0 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project is \"actively maintained\".","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#maintained"}},{"name":"Packaging","score":-1,"reason":"packaging workflow not detected","details":["Warn: no GitHub/GitLab publishing workflow detected."],"documentation":{"short":"Determines if the project is published as a package that others can easily download, install, easily update, and uninstall.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#packaging"}},{"name":"Code-Review","score":0,"reason":"Found 0/21 approved changesets -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project requires human code review before pull requests (aka merge requests) are merged.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#code-review"}},{"name":"Token-Permissions","score":-1,"reason":"No tokens found","details":null,"documentation":{"short":"Determines if the project's workflows follow the principle of least privilege.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#token-permissions"}},{"name":"Binary-Artifacts","score":10,"reason":"no binaries found in the repo","details":null,"documentation":{"short":"Determines if the project has generated executable (binary) artifacts in the source repository.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#binary-artifacts"}},{"name":"CII-Best-Practices","score":0,"reason":"no effort to earn an OpenSSF best practices badge detected","details":null,"documentation":{"short":"Determines if the project has an OpenSSF (formerly CII) Best Practices Badge.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#cii-best-practices"}},{"name":"Pinned-Dependencies","score":-1,"reason":"no dependencies found","details":null,"documentation":{"short":"Determines if the project has declared and pinned the dependencies of its build process.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#pinned-dependencies"}},{"name":"Security-Policy","score":0,"reason":"security policy file not detected","details":["Warn: no security policy file detected","Warn: no security file to analyze","Warn: no security file to analyze","Warn: no security file to analyze"],"documentation":{"short":"Determines if the project has published a security policy.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#security-policy"}},{"name":"Fuzzing","score":0,"reason":"project is not fuzzed","details":["Warn: no fuzzer integrations found"],"documentation":{"short":"Determines if the project uses fuzzing.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#fuzzing"}},{"name":"Signed-Releases","score":-1,"reason":"no releases found","details":null,"documentation":{"short":"Determines if the project cryptographically signs release artifacts.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#signed-releases"}},{"name":"License","score":9,"reason":"license file detected","details":["Info: project has a license file: LICENSE:0","Warn: project license file does not contain an FSF or OSI license."],"documentation":{"short":"Determines if the project has defined a license.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#license"}},{"name":"Branch-Protection","score":0,"reason":"branch protection not enabled on development/release branches","details":["Warn: branch protection not enabled for branch 'master'"],"documentation":{"short":"Determines if the default and release branches are protected with GitHub's branch protection settings.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#branch-protection"}},{"name":"SAST","score":0,"reason":"SAST tool is not run on all commits -- score normalized to 0","details":["Warn: 0 commits out of 14 are checked with a SAST tool"],"documentation":{"short":"Determines if the project uses static code analysis.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#sast"}},{"name":"Vulnerabilities","score":10,"reason":"0 existing vulnerabilities detected","details":null,"documentation":{"short":"Determines if the project has open, known unfixed vulnerabilities.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#vulnerabilities"}}]},"last_synced_at":"2025-08-24T13:57:02.045Z","repository_id":52499322,"created_at":"2025-08-24T13:57:02.045Z","updated_at":"2025-08-24T13:57:02.045Z"},"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28782164,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-26T13:55:28.044Z","status":"ssl_error","status_checked_at":"2026-01-26T13:55:26.068Z","response_time":59,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"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":["fast","golang","grafana","metrics","prometheus","registry","statsd"],"created_at":"2026-01-26T16:14:02.616Z","updated_at":"2026-01-26T16:14:05.302Z","avatar_url":"https://github.com/trafficstars.png","language":"Go","funding_links":[],"categories":[],"sub_categories":[],"readme":"[![Build Status](https://travis-ci.org/trafficstars/metrics.svg?branch=master)](https://travis-ci.org/trafficstars/metrics)\n[![go report](https://goreportcard.com/badge/github.com/trafficstars/metrics)](https://goreportcard.com/report/github.com/trafficstars/metrics)\n[![GoDoc](https://godoc.org/github.com/trafficstars/metrics?status.svg)](https://godoc.org/github.com/trafficstars/metrics)\n\nDescription\n===========\n\nThis is a implementation of handy metrics library for high loaded Golang application with export\nto prometheus (passive export) and/or to StatsD (active export). But the primary method is\nthe passive export (a [special page](https://github.com/trafficstars/statuspage) where somebody get fetch all the metrics).\n\nHow to use\n==========\n\n#### Count the number of HTTP requests of every method\n(and request rate by measuring the rate of the count):\n```go\nmetrics.Count(`requests`, metrics.Tags{\n    `method`: request.Method,\n}).Increment()\n```\n\n#### Measure the latency\n```go\nstartTime := time.Now()\n\n[... do your routines here ...]\n\nmetrics.TimingBuffered(`latency`, nil).ConsiderValue(time.Since(startTime))\n```\n\n#### Export the metrics for prometheus\n```go\nimport \"github.com/trafficstars/statuspage\"\n\nfunc sendMetrics(w http.ResponseWriter, r *http.Request) {\n    statuspage.WriteMetricsPrometheus(w)\n}\n\nfunc main() {\n[...]\n    http.HandleFunc(\"/metrics.prometheus\", sendMetrics)\n[...]\n}\n```\n\n#### Export the metrics to StatsD\n```go\n\nimport (\n\t\"github.com/trafficstars/metrics\"\n)\n\nfunc newStatsdSender(address string) (*statsdSender, error) {\n[... init ...]\n}\n\nfunc (sender *statsdSender) SendInt64(metric metrics.Metric, key string, int64) error {\n[... send the metric to statsd ...]\n}\n\nfunc (sender *statsdSender) SendUint64(metric metrics.Metric, key string, uint64) error {\n[... send the metric to statsd ...]\n}\n\nfunc (sender *statsdSender) SendFloat64(metric metrics.Metric, key string, float64) error {\n[... send the metric to statsd ...]\n}\n\nfunc main() {\n[...]\n    metricsSender, err := newStatsdSender(`localhost:8125`)\n    if err != nil {\n\t\tlog.Fatal(err)\n    }\n    metrics.SetSender(metricsSender)\n[...]\n}\n```\n\n(the buffer should be implemented on the sender side if it's required)\n\nHello world\n-----------\n\n```go\npackage main\n\nimport (\n        \"fmt\"\n        \"math/rand\"\n        \"net/http\"\n        \"time\"\n\n        \"github.com/trafficstars/metrics\"\n        \"github.com/trafficstars/statuspage\"\n)\n\nfunc hello(w http.ResponseWriter, r *http.Request) {\n    answerInt := rand.Intn(10)\n\n    startTime := time.Now()\n\n    // just a metric\n    tags := metrics.Tags{`answer_int`: answerInt}\n    metrics.Count(`hello`, tags).Increment()\n\n    time.Sleep(time.Millisecond)\n    fmt.Fprintf(w, \"Hello world! The answerInt == %v\\n\", answerInt)\n\n    // just a one more metric\n    tags[\"endpoint\"] = \"hello\"\n    metrics.TimingBuffered(`latency`, tags).ConsiderValue(time.Since(startTime))\n}\n\nfunc sendMetrics(w http.ResponseWriter, r *http.Request) {\n\tstartTime := time.Now()\n\n    statuspage.WriteMetricsPrometheus(w)\n\n    metrics.TimingBuffered(`latency`, metrics.Tags{\n\t\t\"endpoint\": \"sendMetrics\",\n    }).ConsiderValue(time.Since(startTime))\n}\n\nfunc main() {\n    http.HandleFunc(\"/\", hello)\n    http.HandleFunc(\"/metrics.prometheus\", sendMetrics) // here we export metrics for prometheus\n    http.ListenAndServe(\":8000\", nil)\n}\n```\n\nFramework \"echo\"\n----------------\n\nThe same as above, but just use our handler:\n```go\n// import \"github.com/trafficstars/statuspage/handler/echostatuspage\"\n\nr := echo.New()\nr.GET(\"/status.prometheus\", echostatuspage.StatusPrometheus)\n```\n\nAggregative metrics\n===================\n\nAggregative metrics are similar to prometheus' [summary](https://prometheus.io/docs/concepts/metric_types/#summary).\nThere're available three methods of summarizing/aggregation of observed values:\n* Simple.\n* Flow.\n* Buffered.\n\nThere's two types of Aggregative metrics:\n* Timing (receives `time.Duration` as the argument to method `ConsiderValue`).\n* Gauge (receives `float64` as the argument to method `ConsiderValue`).\n\n`ConsiderValue` is analog of prometheus' [Observe](https://godoc.org/github.com/prometheus/client_golang/prometheus#Summary)\n\nSo there're available next aggregative metrics:\n* TimingFlow\n* TimingBuffered\n* TimingSimple\n* GaugeFlow\n* GaugeBuffered\n* GaugeSimple\n\n### Slicing\n\nAn aggregative metric has aggregative/summarized statistics for a few periods at the same time:\n* `Last` -- is the very last value ever received via `ConsiderValue`.\n* `Current` -- is the statistics for the current second (which is not complete, yet)\n* `1S` -- is the statistics for the previous second\n* `5S` -- is the statistics for the previous 5 seconds\n* `1M` -- is the statistics for the previous minute \n* ...\n* `6H` -- is the statistics for the last 6 hours\n* `1D` -- is the statistics for the last day\n* `Total` -- is the total statistics \n\nOnce per second the `Current` became `1S` and an new empty `Current` appears instead. And there's a history of the last\n5 statistics for `1S` which is used to recalculate statistics for `5S`. There's in turn a history of the last\n12 statistics for `5S` which is used to recalculate statistics for `1M`. And so on.\n\nThis process is called \"slicing\" (which is done once per second by default).\n\nTo change aggregation periods and slicing interval you can use methods `SetAggregationPeriods` and `SetSlicerInterval`\naccordingly.\n\nA note: So if you have one aggregative metric it will export every value (max, count, ...) for every aggregation period\n(`Total`, `Last`, `Current`, `1S`, `5S`, ...).\n\n### Aggregation types\n\nIf you have no time to read how every aggregation type works then just read \"Use case\"\nof every type.\n\n#### Simple\n\n\"Simple\" just calculates only min, max, avg and count. It's works quite simple and stupid,\ndoesn't require extra CPU and/or RAM.\n\n###### Use case\n\nAny case where it's not required to get percentile values.\n\n#### Flow\n\n\"Flow\" calculates min, max, avg, count, per1, per10, per50, per90 and per99 (\"per\" is a shorthand for \"percentile\").\nIt doesn't store observed values (only summarized/aggregated ones)\n\n###### Use case\n\n* It's required to get percentile values, but they could be inaccurate.\n* There's a lot of values per second.\n* There will be a lot of such metrics.\n\n###### How the calculation of percentile values works\n\nIt just increases/decreases the value (let it call \"P\") to reach required ratio of [values lower than the value \"P\"] to [values\nhigher than the value \"P\"].\n\nLet's image `ConsiderValue` was called. We do not store previous values so we:\n\n1. Pick a random number `[0..1)`. If it's less than the required percentile then we think that this value should be\n   lower than the current value (and vice versa).\n2. Correct the current value if the prediction in the first stage was wrong.\n\nThe function (that implements the above algorithm) is called `guessPercentileValue` (see `common_aggregative_flow.go`).\n\nThere's a constant `iterationsRequiredPerSecond` to tune accuracy of the algorithm. The more this constant value is the\nmore accurate is the algorithm, but more values is required (to be passed through `ConsiderValue`) per second to\napproach the real value. It's set to `20`, so this kind of aggregative metrics shouldn't be used if the next condition\nis not satisfied: `VPS \u003e\u003e 20` (`VPS` means \"values per second\", `\u003e\u003e` means \"much more than\").\n\n![flow](https://raw.githubusercontent.com/trafficstars/metrics/master/internal/docs/demonstration/flow/flow.png)\n(400 events)\n\n![flow](https://raw.githubusercontent.com/trafficstars/metrics/master/internal/docs/demonstration/flow/flow_long.png)\n(4000 events)\n\nThe more values are passed the more inert is the value and the more accurate it is.\nSo, again, the \"Flow\" method should be used only on high `VPS`.\n\n*Attention!* There's an unsolved problem of correct merging percentile-related statistics:\nFor example, to calculate percentile statistics for interval \"5 seconds\" it's required to merge statistics\nfor 5 different seconds (with their-own percentile values), so the resulting\npercentile value is calculated as just the weighted average of percentile values. It's correct only if the load\nis monotone. Otherwise it will be inaccurate, but *usually* good enough.\n\n#### Buffered\n\n\"Buffered\" calculates min, max, avg, count and stores values samples to be able to\ncalculate any percentile values at any time. This method more precise than the \"Flow\", but requires much more RAM. The\nsize of the buffer with the sample values is regulated via method `SetAggregativeBufferSize`\n(the default value is \"1000\"); the more buffer size is the more accuracy of percentile values is,\nbut more RAM is required.\n\nBuffered method is much faster than the Flow method:\n```\nBenchmarkConsiderValueFlow-8            20000000               120 ns/op               0 B/op          0 allocs/op\nBenchmarkConsiderValueBuffered-8        20000000                75.6 ns/op             0 B/op          0 allocs/op\nBenchmarkConsiderValueSimple-8          30000000                54.3 ns/op             0 B/op          0 allocs/op\n```\n\n###### Use case\n\n* It's required to get precise percentile values.\n* It's required to use really fast metrics.\n* There won't be a lot of such metrics (otherwise it will utilize a lot of RAM).\n\n###### Buffer handling\n\nThere're two buffer-related specifics:\n* The buffer is limited, so how do we handle the rest events (if there're more events per second\nthan the buffer size)?\n* How are two buffers get merged to the new one of the same size (see \"slicing\")?\n\nBoth problems are solved using the same initial idea:\nLet's imagine we received a 1001-th value (via `ConsiderValue`), while our buffer\nis only 1000 elements long. Then:\n* We just skip it with probability 1/1001.\n* If it's not skipped then override a random element of the buffer by it.\n\nIf we receive a 1002-th event, then we skip it with probability 2/1002... And so on.\n\nIt's proven that it's any event value will have an equal probability to get into the buffer.\nAnd 1000 elements is enough to calculate value of percentile 99 (there will be 10 element with a higher value). \n\n![buffered](https://raw.githubusercontent.com/trafficstars/metrics/master/internal/docs/demonstration/buffered/buffered.png)\n(on this graph the percentile values are absolutely correct, because there's less than 1000 events)\n\n![buffered long](https://raw.githubusercontent.com/trafficstars/metrics/master/internal/docs/demonstration/buffered/buffered_long.png)\n(4000 events)\n\nFunc metrics\n============\n\nThere're also metrics with the \"Func\" ending:\n* GaugeFloat64Func.\n* GaugeInt64Func.\n\nThis metrics accepts a function as an argument so they call the function\nto update their value by themselves.\n\nAn example:\n\n```go\nserver := echo.New()\n    \n[...]\n    \nengineInstance := fasthttp.WithConfig(engine.Config{\n     Address:      srv.Address,\n})\n\nmetrics.GaugeInt64Func(\n    \"concurrent_incoming_connections\",\n    nil,\n    func() int64 { return int64(engineInstance.GetOpenConnectionsCount()) },\n).SetGCEnabled(false)\n\nserver.Run(engineInstance)\n```\n\nPerformance\n===========\n\n```\nBenchmarkRegistry-8                                     20000000                75.1 ns/op             0 B/op          0 allocs/op\nBenchmarkRegistryReal-8                                  5000000               299 ns/op               0 B/op          0 allocs/op\nBenchmarkAddToRegistryReal-8                             5000000               351 ns/op               0 B/op          0 allocs/op\nBenchmarkRegistryRealReal_lazy-8                         5000000               390 ns/op             352 B/op          3 allocs/op\nBenchmarkRegistryRealReal_normal-8                       5000000               317 ns/op              16 B/op          1 allocs/op\nBenchmarkRegistryRealReal_FastTags_withHiddenTag-8       5000000               254 ns/op               0 B/op          0 allocs/op\nBenchmarkRegistryRealReal_FastTags-8                    10000000               233 ns/op               0 B/op          0 allocs/op\n```\n\nFor comparison `mutex.Lock`/`mutex.Unlock` takes\n```go\nBenchmarkMutexLockUnlock-8              30000000                57.7 ns/op\n```\n\nAlso you can bypass any metric retrieval, for example:\n```go\nmetric := metrics.GaugeInt64(`concurrent_requests`)\nmetric.SetGCEnabled(false)\nhttp.HandleFunc(\"/\", func (w http.ResponseWriter, r *http.Request) {\n\tmetric.Increment()\n\t[...]\n\tmetric.Decrement()\n})\n```\n\nThe incremental and decremental are done in an atomic way and it's safe to use in a concurrent way:\n```go\nBenchmarkIncrementDecrement-8           100000000               14.0 ns/op             0 B/op          0 allocs/op\n```\n\nAlso there's another approach to metrics retrieval -- metric families. It's when a family is retrieved beforehand (like\nthe metric in the example above), but the specific metric is searched through the family using tags. It's a faster\nretrieval method, but less handy. We do not support such approach, yet; but I hope we will. IIRC, such approach\nis used in the official prometheus metrics library for Golang.\n\n### Tags\n\nThere're two implementations of tags:\n* `Tags` -- just a `map[string]interface{}`. It's just handy (syntax sugar).\n* `FastTags` -- faster tags. They prevents unnecessary memory allocations and just works a little faster (usually).\n\nExamples:\n```go\n// Tags\nmetrics.Count(`requests`, metrics.Tags{\n\t`method`: request.Method,\n}).Increment()\n```\n(see `BenchmarkRegistryRealReal_lazy`)\n\n```go\n// FastTags\ntags := metrics.NewFastTags().\n\tSet(`method`, request.Method)\nmetrics.Count(`requests`, tags).Increment()\ntags.Release()\n```\n(see `BenchmarkRegistryRealReal_FastTags`)\n\nIt's also possible to use memory reuse for `Tags`, too. It reduces memory allocations,\nbut doesn't eliminate them and takes away the syntax sugar:\n```go\ntags := metrics.NewTags()\ntags[`method`] = request.Method\nmetrics.Count(`requests`, tags).Increment()\ntags.Release()\n```\n(see `BenchmarkRegistryRealReal_normal`)\n\nSo for a very high-loaded application I'd recommend to use `FastTags`, while for the rest\ncases you may just use syntax-sugared `Tags`.\n\nThe case without tags at all is the case `BenchmarkRegistry` (the fastest one):\n```go\nmetrics.Count(`requests`, nil).Increment()\n```\n\nGarbage collection\n==================\n\nIn our use cases it appeared we have a lot of short-term metrics (which appears for a few seconds/hours in disappears),\nso if we keep all the metrics in RAM then our application reaches the RAM limit and dies. Therefore\na \"garbage collection\" (GC) was implemented. The GC just checks which metrics haven't change\ntheir values for a long time and removes them.\n\nSo every metric has `uselessCounter` which may reach `gcUselessLimit` (currently `5`). If\nthe threshold is reached, then the metrics is `Stop`-ped and the registry's GC will\nremoved it from the internal storage.\n\nThe check if the metric value have changes is done by an Iterator (see \"Iterators\"). Default\ninterval is 1 minute (so the metrics should be \"useless\" for at least 5 minutes\nto be removed).\n\nTo disable the GC for a metric you can call bethod `SetGCEnabled(false)` \n\nAn example:\n```go\nmetric := metrics.GaugeInt64(`concurrent_requests`, nil)\nmetric.SetGCEnabled(false)\n\n[...]\nmetric.Increase()\n[...]\nmetric.Decrease()\n[...]\n```\n\nDeveloper notes\n===============\n\nThe structure of a metric object\n--------------------------------\n\nTo deduplicate code it's used an approach similar to C++'s inheritance, but using Golang's composition. Here's the scheme:\n![composition/inheritance](https://raw.githubusercontent.com/trafficstars/metrics/master/internal/docs/scheme/implementation_composition.png)\n\n* `registryItem` makes possible to register the metric into the registry\n* `common` handles the common (for all metric types) routines like GC or `Sender`.\n* `commonAggregative` handles the common routines for all aggregative metrics (like statistics slicing, see \"slicing\")\n\nIterators\n---------\n\nThere're 3 different background routines for every metric:\n* GC (recheck if the metric wasn't changed long time ago and could be removed)\n* Sender (see \"Sender\")\n* Slicer (see \"Slicing\")\n\nIf I just run a separate goroutine for every routine and metric then the goroutines start\nto consumer a lot of CPU, so to deduplicate goroutines there were implemented \"iterators\".\n\nAn iterator just runs every callback function from a slice with specified time interval.\n\n*Note:* I was too lazy (and there actually was no need) to separate GC and Sender,\nso it's the same routine.\n\nBugs\n====\n\nGoDoc doesn't show public methods of some embedded private structures, sorry for that :(\n\n[May be related to https://github.com/golang/go/issues/6127](https://github.com/golang/go/issues/6127) or may be\nI did something wrong. \n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftrafficstars%2Fmetrics","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ftrafficstars%2Fmetrics","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftrafficstars%2Fmetrics/lists"}