{"id":13743340,"url":"https://github.com/segmentio/stats","last_synced_at":"2025-08-07T10:09:48.336Z","repository":{"id":10221209,"uuid":"64709069","full_name":"segmentio/stats","owner":"segmentio","description":"Go package for abstracting stats collection","archived":false,"fork":false,"pushed_at":"2025-03-13T00:57:41.000Z","size":856,"stargazers_count":215,"open_issues_count":12,"forks_count":32,"subscribers_count":8,"default_branch":"main","last_synced_at":"2025-03-25T05:35:23.910Z","etag":null,"topics":["datadog","dogstatsd","go","golang","metrics","prometheus","segment","stats"],"latest_commit_sha":null,"homepage":"https://godoc.org/github.com/segmentio/stats/v5","language":"Go","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/segmentio.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":"2016-08-01T23:45:21.000Z","updated_at":"2025-03-19T05:16:22.000Z","dependencies_parsed_at":"2023-11-28T18:26:25.641Z","dependency_job_id":"654067dc-ccf6-43ed-b07b-256c1ef3d64b","html_url":"https://github.com/segmentio/stats","commit_stats":null,"previous_names":[],"tags_count":30,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/segmentio%2Fstats","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/segmentio%2Fstats/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/segmentio%2Fstats/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/segmentio%2Fstats/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/segmentio","download_url":"https://codeload.github.com/segmentio/stats/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":253174149,"owners_count":21865818,"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":["datadog","dogstatsd","go","golang","metrics","prometheus","segment","stats"],"created_at":"2024-08-03T05:00:44.870Z","updated_at":"2025-08-07T10:09:48.323Z","avatar_url":"https://github.com/segmentio.png","language":"Go","readme":"# stats [![CircleCI](https://circleci.com/gh/segmentio/stats.svg?style=shield)](https://circleci.com/gh/segmentio/stats) [![Go Report Card](https://goreportcard.com/badge/github.com/segmentio/stats)](https://goreportcard.com/report/github.com/segmentio/stats) [![GoDoc](https://godoc.org/github.com/segmentio/stats?status.svg)](https://godoc.org/github.com/segmentio/stats)\n\nA Go package for abstracting stats collection.\n\nInstallation\n------------\n\n```\ngo get github.com/segmentio/stats/v5\n```\n\nMigration to v4/v5\n---------------\n\nVersion 4 of the stats package introduced a new way of producing metrics based\non defining struct types with tags on certain fields that define how to interpret\nthe values. This approach allows for much more efficient metric production as it\nallows the program to do quick assignments and increments of the struct fields to\nset the values to be reported, and submit them all with one call to the stats\nengine, resulting in orders of magnitude faster metrics production. Here's an\nexample:\n```go\ntype funcMetrics struct {\n    calls struct {\n        count int           `metric:\"count\" type:\"counter\"`\n        time  time.Duration `metric:\"time\"  type:\"histogram\"`\n    } `metric:\"func.calls\"`\n}\n```\n```go\nt := time.Now()\nf()\ncallTime := time.Since(t)\n\nm := \u0026funcMetrics{}\nm.calls.count = 1\nm.calls.time = callTime\n\n// Equivalent to:\n//\n//   stats.Incr(\"func.calls.count\")\n//   stats.Observe(\"func.calls.time\", callTime)\n//\nstats.Report(m)\n```\nTo avoid greatly increasing the complexity of the codebase some old APIs were\nremoved in favor of this new approach, other were transformed to provide more\nflexibility and leverage new features.\n\nThe stats package used to only support float values. Metrics can now be of\nvarious numeric types (see stats.MakeMeasure for a detailed description),\ntherefore functions like `stats.Add` now accept an `interface{}` value instead\nof `float64`. `stats.ObserveDuration` was also removed since this new approach\nmakes it obsolete (durations can be passed to `stats.Observe` directly).\n\nThe `stats.Engine` type used to be configured through a configuration object\npassed to its constructor function, and a few methods (like `Register`) were\nexposed to mutate engine instances. This required synchronization in order to\nbe safe to modify an engine from multiple goroutines. We haven't had a use case\nfor modifying an engine after creating it so the constraint on being thread-safe\nwere lifted and the fields exposed on the `stats.Engine` struct type directly to\ncommunicate that they are unsafe to modify concurrently. The helper methods\nremain tho to make migration of existing code smoother.\n\nHistogram buckets (mostly used for the prometheus client) are now defined by\ndefault on the `stats.Buckets` global variable instead of within the engine.\nThis decoupling was made to avoid paying the cost of doing histogram bucket\nlookups when producing metrics to backends that don't use them (like datadog\nor influxdb for example).\n\nThe data model also changed a little. Handlers for metrics produced by an engine\nnow accept a list of measures instead of single metrics, each measure being made\nof a name, a set of fields, and tags to apply to each of those fields. This\nallows a more generic and more efficient approach to metric production, better\nfits the influxdb data model, while still being compatible with other clients\n(datadog, prometheus, ...). A single timeseries is usually identified by the\ncombination of the measure name, a field name and value, and the set of tags set\non that measure. Refer to each client for a details about how measures are\ntranslated to individual metrics.\n\nNote that no changes were made to the end metrics being produced by each\nsub-package (httpstats, procstats, ...). This was important as we must keep\nthe behavior backward compatible since making changes here would implicitly\nbreak dashboards or monitors set on the various metric collection systems that\nthis package supports, potentially causing production issues.\n\n_If you find a bug or an API is not available anymore but deserves to be ported feel free to open an issue._\n\nQuick Start\n-----------\n\n### Engine\n\nA core concept of the `stats` package is the `Engine`. Every program importing\nthe package gets a default engine where all metrics produced are aggregated.\nThe program then has to instantiate clients that will consume from the engine\nat regular time intervals and report the state of the engine to metrics\ncollection platforms.\n\n```go\npackage main\n\nimport (\n    \"github.com/segmentio/stats/v5\"\n    \"github.com/segmentio/stats/v5/datadog\"\n)\n\nfunc main() {\n    // Creates a new datadog client publishing metrics to localhost:8125\n    dd := datadog.NewClient(\"localhost:8125\")\n\n    // Register the client so it receives metrics from the default engine.\n    stats.Register(dd)\n\n    // Flush the default stats engine on return to ensure all buffered\n    // metrics are sent to the dogstatsd server.\n    defer stats.Flush()\n\n    // That's it! Metrics produced by the application will now be reported!\n    // ...\n}\n```\n\n### Metrics\n\n- [Gauges](https://godoc.org/github.com/segmentio/stats#Gauge)\n- [Counters](https://godoc.org/github.com/segmentio/stats#Counter)\n- [Histograms](https://godoc.org/github.com/segmentio/stats#Histogram)\n- [Timers](https://godoc.org/github.com/segmentio/stats#Timer)\n\n```go\npackage main\n\nimport (\n    \"github.com/segmentio/stats/v5\"\n    \"github.com/segmentio/stats/v5/datadog\"\n)\n\nfunc main() {\n    stats.Register(datadog.NewClient(\"localhost:8125\"))\n    defer stats.Flush()\n\n    // Increment counters.\n    stats.Incr(\"user.login\")\n    defer stats.Incr(\"user.logout\")\n\n    // Set a tag on a counter increment.\n    stats.Incr(\"user.login\", stats.Tag{\"user\", \"luke\"})\n\n    // ...\n}\n```\n\n### Flushing Metrics\n\nMetrics are stored in a buffer, which will be flushed when it reaches its\ncapacity. _For most use-cases, you do not need to explicitly send out metrics._\n\nIf you're producing metrics only very infrequently, you may have metrics that\nstay in the buffer and never get sent out. In that case, you can manually\ntrigger stats flushes like so:\n\n```go\nfunc main() {\n    stats.Register(datadog.NewClient(\"localhost:8125\"))\n    defer stats.Flush()\n\n    // Force a metrics flush every second\n    go func() {\n      for range time.Tick(time.Second) {\n        stats.Flush()\n      }\n    }()\n\n    // ...\n}\n```\n\n### Troubleshooting\n\nUse the `debugstats` package to print all stats to the console.\n\n```go\nhandler := \u0026debugstats.Client{Dst: os.Stdout}\n// to use as a standalone engine:\nengine := stats.NewEngine(\"engine-name\", handler)\nengine.Incr(\"server.start\")\n// or, register on the default stats engine:\nstats.Register(handler)\n\n// Sample output:\n// server.start:1|c\n```\n\nYou can use the `Grep` property to filter the printed metrics for only ones you\ncare about:\n\n```go\nhandler := debugstats.Client{Dst: os.Stdout, Grep: regexp.MustCompile(\"server.start\")}\n```\n\nMonitoring\n----------\n\n### Processes\n\n\u003e 🚧 Go metrics reported with the `procstats` package were previously tagged with a\n\u003e `version` label that reported the Go runtime version. This label was renamed to\n\u003e `go_version` in v4.6.0.\n\nThe\n[github.com/segmentio/stats/v5/procstats](https://godoc.org/github.com/segmentio/stats/v5/procstats)\npackage exposes an API for creating a statistics collector on local processes.\nStatistics are collected for the current process and metrics including Goroutine\ncount and memory usage are reported.\n\nHere's an example of how to use the collector:\n\n```go\npackage main\n\nimport (\n    \"github.com/segmentio/stats/v5/datadog\"\n    \"github.com/segmentio/stats/v5/procstats\"\n)\n\n\nfunc main() {\n     stats.Register(datadog.NewClient(\"localhost:8125\"))\n     defer stats.Flush()\n\n    // Start a new collector for the current process, reporting Go metrics.\n    c := procstats.StartCollector(procstats.NewGoMetrics())\n\n    // Gracefully stops stats collection.\n    defer c.Close()\n\n    // ...\n}\n```\n\nOne can also collect additional statistics on resource delays, such as\nCPU delays, block I/O delays, and paging/swapping delays.  This capability\nis currently only available on Linux, and can be optionally enabled as follows:\n\n```\nfunc main() {\n    // As above...\n\n    // Start a new collector for the current process, reporting Go metrics.\n    c := procstats.StartCollector(procstats.NewDelayMetrics())\n    defer c.Close()\n}\n```\n\n### HTTP Servers\n\nThe [github.com/segmentio/stats/v5/httpstats](https://godoc.org/github.com/segmentio/stats/v5/httpstats)\npackage exposes a decorator of `http.Handler` that automatically adds metric\ncollection to a HTTP handler, reporting things like request processing time,\nerror counters, header and body sizes...\n\nHere's an example of how to use the decorator:\n\n```go\npackage main\n\nimport (\n    \"net/http\"\n\n    \"github.com/segmentio/stats/v5/datadog\"\n    \"github.com/segmentio/stats/v5/httpstats\"\n)\n\nfunc main() {\n     stats.Register(datadog.NewClient(\"localhost:8125\"))\n     defer stats.Flush()\n\n    // ...\n\n    http.ListenAndServe(\":8080\", httpstats.NewHandler(\n        http.HandlerFunc(func(res http.ResponseWriter, req *http.Request) {\n            // This HTTP handler is automatically reporting metrics for all\n            // requests it handles.\n            // ...\n        }),\n    ))\n}\n```\n\n### HTTP Clients\n\nThe [github.com/segmentio/stats/v5/httpstats](https://godoc.org/github.com/segmentio/stats/v5/httpstats)\npackage exposes a decorator of `http.RoundTripper` which collects and reports\nmetrics for client requests the same way it's done on the server side.\n\nHere's an example of how to use the decorator:\n\n```go\npackage main\n\nimport (\n    \"net/http\"\n\n    \"github.com/segmentio/stats/v5/datadog\"\n    \"github.com/segmentio/stats/v5/httpstats\"\n)\n\nfunc main() {\n     stats.Register(datadog.NewClient(\"localhost:8125\"))\n     defer stats.Flush()\n\n    // Make a new HTTP client with a transport that will report HTTP metrics,\n    // set the engine to nil to use the default.\n    httpc := \u0026http.Client{\n        Transport: httpstats.NewTransport(\n            \u0026http.Transport{},\n        ),\n    }\n\n    // ...\n}\n```\n\nYou can also modify the default HTTP client to automatically get metrics for all\npackages using it, this is very convenient to get insights into dependencies.\n\n```go\npackage main\n\nimport (\n    \"net/http\"\n\n    \"github.com/segmentio/stats/v5/datadog\"\n    \"github.com/segmentio/stats/v5/httpstats\"\n)\n\nfunc main() {\n     stats.Register(datadog.NewClient(\"localhost:8125\"))\n     defer stats.Flush()\n\n    // Wraps the default HTTP client's transport.\n    http.DefaultClient.Transport = httpstats.NewTransport(http.DefaultClient.Transport)\n\n    // ...\n}\n```\n\n### Addendum\n\nBy default, the stats library will report the running go version when you\ninvoke NewEngine() as a metric:\n\n- `go_version` with value 1 and a `tag` set to the current version.\n- `stats_version` with value ` and a `tag` set to the tag value of\n  segmentio/stats.\n\nSet `STATS_DISABLE_GO_VERSION_REPORTING` to `true` in your environment, or set\n`stats.GoVersionReportingEnabled` to `false` before collecting any metrics, to\ndisable this behavior.\n","funding_links":[],"categories":["Golang"],"sub_categories":["Statistics"],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsegmentio%2Fstats","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fsegmentio%2Fstats","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsegmentio%2Fstats/lists"}