- Notifications
You must be signed in to change notification settings - Fork33
Go package for abstracting stats collection
License
segmentio/stats
Folders and files
| Name | Name | Last commit message | Last commit date | |
|---|---|---|---|---|
Repository files navigation
A Go package for abstracting stats collection.
go get github.com/segmentio/stats/v5Version 4 of the stats package introduced a new way of producing metrics basedon defining struct types with tags on certain fields that define how to interpretthe values. This approach allows for much more efficient metric production as itallows the program to do quick assignments and increments of the struct fields toset the values to be reported, and submit them all with one call to the statsengine, resulting in orders of magnitude faster metrics production. Here's anexample:
typefuncMetricsstruct {callsstruct {countint`metric:"count" type:"counter"`time time.Duration`metric:"time" type:"histogram"` }`metric:"func.calls"`}
t:=time.Now()f()callTime:=time.Since(t)m:=&funcMetrics{}m.calls.count=1m.calls.time=callTime// Equivalent to://// stats.Incr("func.calls.count")// stats.Observe("func.calls.time", callTime)//stats.Report(m)
To avoid greatly increasing the complexity of the codebase some old APIs wereremoved in favor of this new approach, other were transformed to provide moreflexibility and leverage new features.
The stats package used to only support float values. Metrics can now be ofvarious numeric types (see stats.MakeMeasure for a detailed description),therefore functions likestats.Add now accept aninterface{} value insteadoffloat64.stats.ObserveDuration was also removed since this new approachmakes it obsolete (durations can be passed tostats.Observe directly).
Thestats.Engine type used to be configured through a configuration objectpassed to its constructor function, and a few methods (likeRegister) wereexposed to mutate engine instances. This required synchronization in order tobe safe to modify an engine from multiple goroutines. We haven't had a use casefor modifying an engine after creating it so the constraint on being thread-safewere lifted and the fields exposed on thestats.Engine struct type directly tocommunicate that they are unsafe to modify concurrently. The helper methodsremain tho to make migration of existing code smoother.
Histogram buckets (mostly used for the prometheus client) are now defined bydefault on thestats.Buckets global variable instead of within the engine.This decoupling was made to avoid paying the cost of doing histogram bucketlookups when producing metrics to backends that don't use them (like datadogor influxdb for example).
The data model also changed a little. Handlers for metrics produced by an enginenow accept a list of measures instead of single metrics, each measure being madeof a name, a set of fields, and tags to apply to each of those fields. Thisallows a more generic and more efficient approach to metric production, betterfits the influxdb data model, while still being compatible with other clients(datadog, prometheus, ...). A single timeseries is usually identified by thecombination of the measure name, a field name and value, and the set of tags seton that measure. Refer to each client for a details about how measures aretranslated to individual metrics.
Note that no changes were made to the end metrics being produced by eachsub-package (httpstats, procstats, ...). This was important as we must keepthe behavior backward compatible since making changes here would implicitlybreak dashboards or monitors set on the various metric collection systems thatthis package supports, potentially causing production issues.
If you find a bug or an API is not available anymore but deserves to be ported feel free to open an issue.
A core concept of thestats package is theEngine. Every program importingthe package gets a default engine where all metrics produced are aggregated.The program then has to instantiate clients that will consume from the engineat regular time intervals and report the state of the engine to metricscollection platforms.
package mainimport ("github.com/segmentio/stats/v5""github.com/segmentio/stats/v5/datadog")funcmain() {// Creates a new datadog client publishing metrics to localhost:8125dd:=datadog.NewClient("localhost:8125")// Register the client so it receives metrics from the default engine.stats.Register(dd)// Flush the default stats engine on return to ensure all buffered// metrics are sent to the dogstatsd server.deferstats.Flush()// That's it! Metrics produced by the application will now be reported!// ...}
package mainimport ("github.com/segmentio/stats/v5""github.com/segmentio/stats/v5/datadog")funcmain() {stats.Register(datadog.NewClient("localhost:8125"))deferstats.Flush()// Increment counters.stats.Incr("user.login")deferstats.Incr("user.logout")// Set a tag on a counter increment.stats.Incr("user.login", stats.Tag{"user","luke"})// ...}
Metrics are stored in a buffer, which will be flushed when it reaches itscapacity.For most use-cases, you do not need to explicitly send out metrics.
If you're producing metrics only very infrequently, you may have metrics thatstay in the buffer and never get sent out. In that case, you can manuallytrigger stats flushes like so:
funcmain() {stats.Register(datadog.NewClient("localhost:8125"))deferstats.Flush()// Force a metrics flush every secondgofunc() {forrangetime.Tick(time.Second) {stats.Flush() } }()// ...}
Use thedebugstats package to print all stats to the console.
handler:=&debugstats.Client{Dst:os.Stdout}// to use as a standalone engine:engine:=stats.NewEngine("engine-name",handler)engine.Incr("server.start")// or, register on the default stats engine:stats.Register(handler)// Sample output:// server.start:1|c
You can use theGrep property to filter the printed metrics for only ones youcare about:
handler:= debugstats.Client{Dst:os.Stdout,Grep:regexp.MustCompile("server.start")}
🚧 Go metrics reported with the
procstatspackage were previously tagged with aversionlabel that reported the Go runtime version. This label was renamed togo_versionin v4.6.0.
Thegithub.com/segmentio/stats/v5/procstatspackage exposes an API for creating a statistics collector on local processes.Statistics are collected for the current process and metrics including Goroutinecount and memory usage are reported.
Here's an example of how to use the collector:
package mainimport ("github.com/segmentio/stats/v5/datadog""github.com/segmentio/stats/v5/procstats")funcmain() {stats.Register(datadog.NewClient("localhost:8125"))deferstats.Flush()// Start a new collector for the current process, reporting Go metrics.c:=procstats.StartCollector(procstats.NewGoMetrics())// Gracefully stops stats collection.deferc.Close()// ...}
One can also collect additional statistics on resource delays, such asCPU delays, block I/O delays, and paging/swapping delays. This capabilityis currently only available on Linux, and can be optionally enabled as follows:
func main() { // As above... // Start a new collector for the current process, reporting Go metrics. c := procstats.StartCollector(procstats.NewDelayMetrics()) defer c.Close()}Thegithub.com/segmentio/stats/v5/httpstatspackage exposes a decorator ofhttp.Handler that automatically adds metriccollection to a HTTP handler, reporting things like request processing time,error counters, header and body sizes...
Here's an example of how to use the decorator:
package mainimport ("net/http""github.com/segmentio/stats/v5/datadog""github.com/segmentio/stats/v5/httpstats")funcmain() {stats.Register(datadog.NewClient("localhost:8125"))deferstats.Flush()// ...http.ListenAndServe(":8080",httpstats.NewHandler(http.HandlerFunc(func(res http.ResponseWriter,req*http.Request) {// This HTTP handler is automatically reporting metrics for all// requests it handles.// ... }), ))}
Thegithub.com/segmentio/stats/v5/httpstatspackage exposes a decorator ofhttp.RoundTripper which collects and reportsmetrics for client requests the same way it's done on the server side.
Here's an example of how to use the decorator:
package mainimport ("net/http""github.com/segmentio/stats/v5/datadog""github.com/segmentio/stats/v5/httpstats")funcmain() {stats.Register(datadog.NewClient("localhost:8125"))deferstats.Flush()// Make a new HTTP client with a transport that will report HTTP metrics,// set the engine to nil to use the default.httpc:=&http.Client{Transport:httpstats.NewTransport(&http.Transport{}, ), }// ...}
You can also modify the default HTTP client to automatically get metrics for allpackages using it, this is very convenient to get insights into dependencies.
package mainimport ("net/http""github.com/segmentio/stats/v5/datadog""github.com/segmentio/stats/v5/httpstats")funcmain() {stats.Register(datadog.NewClient("localhost:8125"))deferstats.Flush()// Wraps the default HTTP client's transport.http.DefaultClient.Transport=httpstats.NewTransport(http.DefaultClient.Transport)// ...}
By default, the stats library will report the running go version when youinvoke NewEngine() as a metric:
go_versionwith value 1 and atagset to the current version.stats_versionwith valueand atag` set to the tag value ofsegmentio/stats.
SetSTATS_DISABLE_GO_VERSION_REPORTING totrue in your environment, or setstats.GoVersionReportingEnabled tofalse before collecting any metrics, todisable this behavior.
About
Go package for abstracting stats collection
Topics
Resources
License
Uh oh!
There was an error while loading.Please reload this page.
Stars
Watchers
Forks
Packages0
Uh oh!
There was an error while loading.Please reload this page.