Metrics¶
Publish custom CloudWatch metrics by writing Embedded Metric Format (EMF) JSON to your Lambda logs.
Install¶
Use Go 1.27 or newer:
CGO_ENABLED=0 go get github.com/rambow-cloud/powertools-lambda-go/metrics@v1.2.0
CGO_ENABLED=0 go get github.com/rambow-cloud/powertools-lambda-go/logger@v1.2.0
Record an order count¶
AddMetric buffers a value. Flush writes the EMF document below to stdout. The timestamp varies.
Input
Code
package main
import (
"os"
"github.com/rambow-cloud/powertools-lambda-go/logger"
"github.com/rambow-cloud/powertools-lambda-go/metrics"
)
func main() {
appLog := logger.New(logger.WithServiceName("orders"))
if err := run(appLog); err != nil {
if logErr := appLog.Error("Application failed", err); logErr != nil {
panic(logErr)
}
os.Exit(1)
}
}
func run(appLog *logger.Logger) error {
appMetrics, err := metrics.New(
metrics.WithNamespace("Orders"),
metrics.WithServiceName("checkout"),
)
if err != nil {
return err
}
if err := appMetrics.AddMetric("OrdersReceived", metrics.Count, 1); err != nil {
return err
}
if err := appMetrics.Flush(); err != nil {
return err
}
return nil
}
Output
{
"_aws": {
"Timestamp": 1790812800000,
"CloudWatchMetrics": [
{
"Namespace": "Orders",
"Dimensions": [
[
"service"
]
],
"Metrics": [
{
"Name": "OrdersReceived",
"Unit": "Count"
}
]
}
]
},
"service": "checkout",
"OrdersReceived": 1
}
Add a dimension¶
Dimensions identify the time series in CloudWatch. Add them before recording a metric:
if err := appMetrics.AddDimension("environment", "production"); err != nil {
return err
}
if err := appMetrics.AddMetric("OrdersReceived", metrics.Count, 1); err != nil {
return err
}
return appMetrics.Flush()
The emitted document contains "environment":"production"; its dimension set includes service and environment. Put request IDs in metadata instead of dimensions to avoid creating a time series per request.
Flush automatically in Lambda¶
handler := func(ctx context.Context, event map[string]any) (map[string]any, error) {
if err := appMetrics.WithContext(ctx).AddMetric("OrdersReceived", metrics.Count, 1); err != nil {
return nil, err
}
return map[string]any{"status": "accepted"}, nil
}
lambda.Start(metrics.WrapHandler(appMetrics, handler,
metrics.HandlerOptions{CaptureColdStart: true}))
The handler returns {"status":"accepted"}, and the wrapper flushes the metric at invocation completion. On the first on-demand invocation it can also emit a separate ColdStart metric.
Configure metrics¶
| Setting | Example | Purpose |
|---|---|---|
| Namespace | metrics.WithNamespace("Orders") |
Groups related metrics |
| Service | metrics.WithServiceName("checkout") |
Adds the default service dimension |
| Environment defaults | POWERTOOLS_METRICS_NAMESPACE, POWERTOOLS_SERVICE_NAME |
Configure without code changes |
| Disable emission | POWERTOOLS_METRICS_DISABLED=true |
Suppresses output |
| Flush diagnostics | metrics.WithErrorHandler(callback) |
Observes wrapper publication errors |
Things to know¶
- CloudWatch must receive the EMF log document to extract the metric. The package does not make CloudWatch API calls.
- Reuse the root Metrics instance; call
WithContext(ctx)inside the wrapper for request-local dimensions and values. - Metrics are automatically flushed at capacity. A flush clears request state.
POWERTOOLS_DEV=truedisables metric output unless explicitly overridden.
Next steps¶
See the API and behavior notes for advanced options, and module installation for dependencies.