Metrics
Track custom metrics in your Go application
Encore provides built-in support for defining custom metrics in your Go applications. Once defined, metrics are automatically collected and displayed in the Encore Cloud Dashboard, and can be exported to third-party observability services.
See the Platform metrics documentation for information about integrations with third-party services like Grafana Cloud and Datadog.
Defining custom metrics
Define custom metrics by importing the encore.dev/metrics package and
creating a new metric using one of the metrics.NewCounter or metrics.NewGauge functions.
For example, to count the number of orders processed:
import "encore.dev/metrics"
var OrdersProcessed = metrics.NewCounter[uint64]("orders_processed", metrics.CounterConfig{})
func process(order *Order) {
// ...
OrdersProcessed.Increment()
}
Metric types
Encore currently supports two metric types: counters and gauges.
Counters measure the count of something. A counter's value must always increase, never decrease. (Note that the value gets reset to 0 when the application restarts.) Typical use cases include counting the number of requests, the amount of data processed, and so on.
Gauges measure the current value of something. Unlike counters, a gauge's value can fluctuate up and down. Typical use cases include measuring CPU usage, the number of active instances running of a process, and so on.
For information about their respective APIs, see the API documentation for Counter and Gauge.
Counter example
import "encore.dev/metrics"
var RequestsReceived = metrics.NewCounter[uint64]("requests_received", metrics.CounterConfig{})
func handleRequest() {
RequestsReceived.Increment()
// ... handle request
}
Gauge example
import "encore.dev/metrics"
var ActiveConnections = metrics.NewGauge[int64]("active_connections", metrics.GaugeConfig{})
func onConnect() {
ActiveConnections.Add(1)
}
func onDisconnect() {
ActiveConnections.Add(-1)
}
Defining labels
Encore's metrics package provides a type-safe way of attaching labels to metrics. To define labels, create a struct type representing the labels and then use metrics.NewCounterGroup or metrics.NewGaugeGroup.
The Labels type must be a named struct, where each field corresponds to a single label. Each field must be of type string, int, or bool.
Counter with labels
import "encore.dev/metrics"
type Labels struct {
Success bool
}
var OrdersProcessed = metrics.NewCounterGroup[Labels, uint64]("orders_processed", metrics.CounterConfig{})
func process(order *Order) {
var success bool
// ... populate success with true/false ...
OrdersProcessed.With(Labels{Success: success}).Increment()
}
Gauge with labels
import "encore.dev/metrics"
type ConnectionLabels struct {
Region string
}
var ActiveConnections = metrics.NewGaugeGroup[ConnectionLabels, int64]("active_connections", metrics.GaugeConfig{})
func onConnect(region string) {
ActiveConnections.With(ConnectionLabels{Region: region}).Add(1)
}
Take care
Each combination of label values creates a unique time series tracked in memory and stored by the monitoring system. Using numerous labels can lead to a combinatorial explosion, causing high cloud expenses and degraded performance.
As a general rule, limit the unique time series to tens or hundreds at most, rather than thousands.