Application metrics
Metrics are the numbers your app produces that aren't errors: orders placed, queue depth, checkout latency, unique visitors. Errora accepts both wire formats Sentry SDKs emit.
Metric types
| Type | Use it for | Aggregates |
|---|---|---|
counter (c) | Things that happen | sum, count |
distribution (d) | Measured values (latency, size) | avg, min, max, p50–p99 |
gauge (g) | A level at a point in time | last, min, max, avg |
set (s) | Distinct things | count_unique |
Setup — SDK
Sentry.metrics.increment("checkout.attempt", 1, { tags: { plan: "pro" } });
Sentry.metrics.distribution("checkout.latency", 421, { unit: "millisecond", tags: { route: "/pay" } });
Sentry.metrics.gauge("queue.depth", 128, { tags: { queue: "ingest" } });
Sentry.metrics.set("visitors", userId);
sentry_sdk.metrics.incr("orders.created", 1, tags={"plan": "pro"})
sentry_sdk.metrics.distribution("orders.total", order.total, unit="none")
sentry_sdk.metrics.gauge("queue.depth", depth, tags={"queue": "ingest"})
sentry_sdk.metrics.set("visitors", user_id)
SDKs pre-aggregate before sending: what arrives is a bucket per metric per time window, not one message per call. Distributions keep a sample of the raw values, so percentiles stay answerable, and sets count distinct members as a union across buckets rather than a sum.
Setup — raw wire formats
1. trace_metric items (current SDKs) — the same batch container as logs:
{"items":[{"timestamp":1767225600.0,"name":"checkout.latency","type":"distribution",
"value":42.0,"unit":"millisecond","trace_id":"7b3f…",
"attributes":{"route":{"value":"/pay","type":"string"}}}]}
2. statsd text (the original protocol), newline-delimited:
<name>[@<unit>]:<v1>[:<v2>…]|<type>|#<tag>:<value>,…|T<unix_seconds>
endpoint.response_time@millisecond:57:92|d|#route:/pay,method:POST|T1615889449
button_click@none:1|c|#browser:firefox
A statsd gauge with exactly five values is the pre-aggregated
last:min:max:sum:count form, not five readings.
Limits per batch: 1000 items, 30 tags per metric, 200 characters per name or tag value.
Querying
Metrics in the sidebar lists the metric names a project has sent. Pick one and choose:
- an aggregate —
sum,avg,min,max,p50,p75,p90,p95,p99,count_unique - a group-by tag, to split the series
- an environment and a time period
avg is always the true sum / count over the window, never the average of per-bucket
averages.
GET /api/v1/projects/{project_id}/metrics?q=&stats_period=24h
GET /api/v1/projects/{project_id}/metrics/series?name=&op=&group_by=&environment=&stats_period=24h
GET /api/v1/projects/{project_id}/metrics/summary?name=&environment=&stats_period=24h
GET /api/v1/projects/{project_id}/metrics/tags?name=&stats_period=24h
Naming that stays useful
domain.thing.measure—checkout.latency,queue.depth,sms.sent.- Put varying values in tags, never in the name.
orders.createdtaggedplan:probeatsorders.created.pro. - Keep tag cardinality low:
routeyes,user_idno. Every distinct tag combination is its own bucket, and you are billed per metric bucket.
Dashboards
Metrics are a dashboard dataset — put a metric series next to your error counts and transaction latency on the same board.
Troubleshooting
| Symptom | Cause / fix |
|---|---|
| Metric name missing from the list | Nothing has arrived in the selected period — widen it |
| Percentiles look approximate | A bucket kept a bounded sample (100 values); that is by design |
count_unique lower than expected | Set members are hashed and bounded per bucket (500) |
| Tag missing | It exceeded the 30-tag or 200-character limit and was dropped |
| Costs climbing | Tag cardinality — one high-cardinality tag multiplies your bucket count |