# hashicorp/go-metrics: Go metric sinks, labels, and runtime instrumentation

> hashicorp/go-metrics is a Go library for instrumenting applications, collecting counters, gauges, samples, and timings, then sending them to StatsD, Statsite, Prometheus, Datadog, Circonus, or in-memory sinks. It is most useful when one application-facing metrics API must support multiple backends.

**hashicorp/go-metrics** — A Golang library for exporting performance and runtime metrics to external metrics systems (i.e. statsite, statsd)

- Repository: https://github.com/hashicorp/go-metrics
- Stars: 1,581 · Forks: 189
- Language: Go
- License: MIT
- Published: 2026-10-16 · Updated: 2026-10-16 · Language: en
- Canonical page: https://hysenlabs.com/projects/hashicorp-go-metrics

## What go-metrics solves inside a Go service

hashicorp/go-metrics solves the problem of collecting application measurements in Go code without binding that code to one reporting system. A service can emit named counters, gauges, key values, samples, and timing observations through the `metrics` package. The same instrumentation can then be connected to a Statsite server, a StatsD server, a Prometheus endpoint, an in-memory store, several sinks at once, or no destination at all.

The intended users are Go developers who want instrumentation inside an existing service and need different delivery options for development, testing, and production. The README explicitly describes instrumenting code, exposing application metrics, and profiling runtime performance. It does not present go-metrics as a complete observability platform. It does not document tracing, log correlation, alert evaluation, metric retention, or dashboards. Those concerns would need other systems.

The library also gives runtime profiling a direct expression. `metrics.MeasureSince` records elapsed time for a named operation when the function returns, which is useful for a service method or handler. That convenience is narrow by design. It records a measurement, but the README does not claim distributed tracing, request spans, sampling controls, or automatic instrumentation.

## MetricSink and the path from EmitKey to a backend

The central extension point is the `MetricSink` interface. Application code uses package-level metrics functions, while a sink receives the resulting measurements. The README names the supplied sinks and their transport differences:

- `StatsiteSink` sends to a Statsite instance over TCP.
- `StatsdSink` sends to StatsD or Statsite over UDP.
- `PrometheusSink` exposes metrics through HTTP for Prometheus scrapes.
- `InmemSink` aggregates data in memory for export.
- `FanoutSink` writes to multiple sinks.
- `BlackholeSink` discards metrics.

This separation means instrumentation does not need to contain StatsD packet formatting or Prometheus endpoint logic. It also means backend-specific delivery is handled outside the call site. `FanoutSink` is particularly relevant when a process needs to feed more than one metrics destination, although the README gives no retry, buffering, ordering, or backpressure details for these sinks.

`InmemSink` is more than a null test double. It retains recent metrics, aggregates counters and samples, and can be paired with `InmemSignal`. When a signal such as `SIGUSR1` arrives, the default signal handler can write a formatted summary to stderr. That makes it useful for local debugging without changing the process's reporting destination.

## Counter, gauge, sample, and timing instrumentation

The API covers several measurement types, which keeps the example code small and makes the intended semantics visible. The README shows a counter created through `IncrCounter`, a gauge assigned through `SetGauge`, a key/value measurement through `EmitKey`, and repeated samples through `AddSample`. The in-memory output demonstrates that counters are summarized by count, minimum, mean, maximum, and standard deviation. Samples receive the same kind of aggregate treatment.

The timing example uses `MeasureSince` with the operation name and a start time:

```go
func SlowMethod() {
    // Profiling the runtime of a method
    defer metrics.MeasureSince([]string{"SlowMethod"}, time.Now())
}
```

Because `MeasureSince` is deferred, the measurement is emitted after the function body exits. The name is represented as a path of string segments. That representation supports names such as `method.wow` in the in-memory output and gives callers a consistent way to build hierarchical metric names.

The distinction between a gauge and a counter matters. The README's `SetGauge([]string{"foo"}, 42)` sets a current value, while repeated `IncrCounter` calls aggregate changes over time. A gauge is therefore the natural fit for a value such as a queue depth, while a counter records occurrences or increments. The README does not define persistence semantics or whether values survive process restarts, so neither should be inferred from the type names.

## Global configuration and label filtering

A service configures a global sink with `metrics.NewGlobal` and passes a `Config` created by `DefaultConfig`. The README's example uses a Statsite sink:

```go
// Configure a statsite sink as the global metrics sink
sink, _ := metrics.NewStatsiteSink("statsite:8125")
metrics.NewGlobal(metrics.DefaultConfig("service-name"), sink)

// Emit a Key/Value pair
metrics.EmitKey([]string{"questions", "meaning of life"}, 42)
```

This establishes a process-wide destination after the sink has been constructed. The ignored error in the example is a documentation shortcut, not evidence that connection failures are always harmless. The source snippet does not explain error handling, reconnect behavior, or what happens when the Statsite endpoint is unavailable.

Most metrics also have a `WithLabels` form. Labels can be passed to a sink and, for example, translated into Prometheus labels. The library offers global controls in `Config`: if `Config.AllowedLabels` is not nil, only listed labels are sent; if `Config.BlockedLabels` is not nil, listed labels are omitted. By default both values are nil, so no tags are filtered.

This is a direct response to label cardinality problems. An accidental label containing a request ID or other unbounded value can create many series in a metrics backend. The filtering mechanism limits that risk, but it does not explain whether blocked labels affect every sink identically or how conflicting allow and block lists are resolved. Those details require checking the implementation.

## Installation, dependency management, and a first use

The README does not provide an installation command or a standalone import example. It identifies the package as `github.com/hashicorp/go-metrics` through the module file and points to the package API through GoDoc. The repository's `go.mod` declares the module path:

```toml
module github.com/hashicorp/go-metrics
```

Because the repository does not state how an application should add the dependency, this review does not invent a `go get` command or an import block. The first concrete project-level operation documented by the repository is running the test suite. The `Makefile` defines this command:

```bash
go test -count=1 ./...
```

That command should execute the repository's Go tests. It is a repository development check, not an application installation procedure. The Makefile also defines race testing, coverage, linting, dependency tidying, and copyright-header checks, so project contributors have several documented maintenance targets.

For an application, the README's first real use is to construct a sink, install it globally with a service name, and emit a measurement. Start with a non-production sink such as `InmemSink` if local inspection is desired, because the README documents its aggregation and signal output. Before adopting a network sink, verify the exact endpoint format and error handling in the relevant source files.

## Prometheus exposure, fanout, and backend trade-offs

The backend choices differ in delivery model rather than merely in naming. PrometheusSink is intended for an HTTP endpoint scraped by Prometheus. StatsiteSink uses TCP, while StatsdSink uses UDP. This makes go-metrics useful as an abstraction when a service supports several environments, but it does not make the sinks equivalent. A UDP StatsD path and an HTTP Prometheus scrape path have different failure and configuration models.

`FanoutSink` addresses the case where several sinks need the same measurements. It can send to multiple Statsite instances, as the README notes, and the same abstraction should be evaluated for other combinations. The documentation does not state whether one failing sink prevents delivery to another, whether writes are synchronous, or whether duplicate delivery is possible. A service that requires delivery guarantees should not infer those properties from the existence of fanout.

Prometheus labels are one reason to use `WithLabels` carefully. The global allow and block lists can reduce cardinality, but they also make behavior application-specific. A label useful for debugging may be undesirable in a production Prometheus endpoint. The project leaves that policy to the caller. Review the selected sink and the final label set before adding dynamic dimensions.

## Maintenance, release cadence, and MIT licensing

The repository is not archived, and the last push was on 2026-10-12. Recent releases include `v0.7.0` on 2026-09-16, `v0.6.1` on 2026-07-29, and `v0.6.0` on 2026-06-24. This indicates recent repository activity and published versions, but the README does not promise a support policy, compatibility matrix, or long-term maintenance commitment.

The module file requires Go `1.26.0` and lists dependencies for Prometheus, Datadog, Circonus, immutable radix data, HTTP retry, and related libraries. That dependency surface matters when assessing upgrades. The Makefile provides `go mod tidy` as part of its `check` target and fails if `go.mod` or `go.sum` changes. It also provides `go test -count=1 -race ./...` for race checking.

The repository identifies its license as MIT. This is a permissive license identifier, but the repository is the source that should be consulted for the exact terms and notice obligations. The documentation does not say which versions carry different obligations or whether optional sink dependencies introduce separate licensing questions. A review of `LICENSE` and the dependencies used by the selected sink is appropriate before redistribution.

## Limits of go-metrics as a monitoring system

The clearest limitation is scope. go-metrics collects and exports measurements, but the README does not document storage, querying, alerting, dashboards, retention, or tracing. Adopting the library does not make a service observable by itself. It still needs a backend such as StatsD, Statsite, or Prometheus and operational configuration for that backend.

There is also a design trade-off around global state. The README's setup calls `NewGlobal`, which is convenient for small services but can make multiple independent metric configurations harder to manage within one process. The documentation does not explain namespace isolation between components, test cleanup after replacing the global sink, or behavior when several packages initialize metrics concurrently.

Finally, label filtering is a policy mechanism, not automatic cardinality protection. By default, no labels are filtered. Applications must identify unbounded label values and configure `AllowedLabels` or `BlockedLabels` deliberately. The library cannot tell the application whether a particular label is safe for every backend. For teams needing automatic instrumentation, per-request context, or richer telemetry semantics, go-metrics may be too small unless those concerns are handled elsewhere.

## Conclusion

Adopt go-metrics when a Go service needs a small in-process metrics API with interchangeable sinks, controlled labels, and runtime timing helpers. Do not choose it as a replacement for a full telemetry platform, a tracing system, or an application-specific monitoring service without first checking its sink behavior, label policy, delivery guarantees, and license. The first verification should be a minimal service build that installs the module, emits a labeled metric, and confirms how the selected sink handles it.

## FAQ

### What is hashicorp/go-metrics used for?

It provides a Go `metrics` package for instrumenting code, exposing application metrics, and recording runtime performance. Measurements can be sent to Statsite, StatsD, Prometheus, in-memory storage, multiple sinks, or no sink.

### How do I configure a Statsite sink in hashicorp/go-metrics?

The README creates a Statsite sink with `NewStatsiteSink("statsite:8125")`, installs it with `NewGlobal`, and then emits metrics through package functions such as `EmitKey`. The example uses TCP and does not document error handling or reconnection behavior.

### Does hashicorp/go-metrics support Prometheus labels?

Yes. Most metrics have a `WithLabels` form, and the README says those labels can be translated into Prometheus labels. `Config.AllowedLabels` and `Config.BlockedLabels` can globally filter labels to control cardinality.

### Can hashicorp/go-metrics collect metrics in memory?

Yes. `InmemSink` provides in-memory aggregation and can be used to export stats. The README also documents `DefaultInmemSignal`, which can print a formatted summary of recent metrics to stderr when a process receives a signal such as `SIGUSR1`.

### What Go version does hashicorp/go-metrics require?

The repository's `go.mod` declares `go 1.26.0`. The README does not provide an application installation command, so dependency setup should follow the consuming module's Go dependency workflow.

## Sources

- [hashicorp/go-metrics on GitHub](https://github.com/hashicorp/go-metrics)
- [Issues](https://github.com/hashicorp/go-metrics/issues)
- [License: MIT](https://github.com/hashicorp/go-metrics/blob/master/LICENSE)
- [README](https://github.com/hashicorp/go-metrics/blob/master/README.md)
- [Releases](https://github.com/hashicorp/go-metrics/releases)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/hashicorp-go-metrics
