# Record application metrics

> Choose the right metric type, emit low-cardinality measurements, and verify that Anectico can query them.

Canonical page: https://anectico.com/docs/instrument/metrics/


Metrics show how a system changes over time. Use them for service-wide state such as request volume,
queue depth, latency, saturation, and completed work. Use traces, logs, errors, and events when you
need the story of one request or customer.

Use a project-scoped API key with `ingest:write`. Metrics are sent through OTLP and normally export
on an interval, so they may appear later than an immediately flushed span or error. Anectico preserves
the OTLP temporality and point start timestamp. Delta points are aggregated directly; cumulative
monotonic sums and histograms are converted to reset-safe increments before a query aggregates them.
This keeps periodic cumulative exports from counting the same work or observations repeatedly.

## Choose the measurement type

| Type | Use it for | Example | Useful views |
| --- | --- | --- | --- |
| Counter | A total that only increases | Completed orders, bytes sent | Change over time, totals |
| Gauge | The latest level can rise or fall | Queue depth, memory in use | `avg`, `min`, `max`, latest value |
| Histogram | A distribution of observations | Request duration, payload size | Native histogram or heatmap |
| Summary | Pre-aggregated count, sum, and quantiles | An existing OTLP summary | Scalar trend; prefer histograms for new instrumentation |

Choose the type when you create the OpenTelemetry instrument. Do not turn a current level into a
counter or record a duration as a gauge merely because the helper is convenient.

Anectico's SDK convenience methods deliberately stay small, but their instrument types differ:

- JavaScript `recordMetric` records one histogram observation.
- Python `record_metric` and Go `RecordMetric` record a gauge value.
- Python's `client.meter` and Go's `client.Meter()` expose the OpenTelemetry Meter when you need an
  explicit counter, histogram, or other instrument.
- For JavaScript instrument types beyond the histogram helper, keep or add an OpenTelemetry metrics
  pipeline and export it to Anectico.

## Record one recognizable metric

The following examples use stable labels and avoid customer or request identifiers.

<div data-language-tabs="record-metric" data-language-tabs-label="Choose an SDK"></div>

**JavaScript / TypeScript**

```typescript
const startedAt = performance.now();
await processCheckout();

anectico.recordMetric('checkout.duration_ms', performance.now() - startedAt, {
  route: '/checkout',
  result: 'success',
});
```

This records a histogram observation. The client must already be started.

**Python**

```python
client.record_metric(
    'checkout.queue_depth',
    queue.qsize(),
    labels={'region': 'eu-west', 'worker_pool': 'payments'},
)
```

This records a gauge value. The client must already be started.

**Go**

```go
client.RecordMetric("checkout.queue_depth", float64(queueDepth), map[string]string{
	"region":      "eu-west",
	"worker_pool": "payments",
})
```

This records a gauge value. The client must already be started.

<div data-language-tabs-end="record-metric"></div>

For example, create an explicit Go counter when a gauge would have the wrong meaning:

```go
counter, err := client.Meter().Int64Counter(
	"checkout.orders",
	metric.WithUnit("{order}"),
)
if err != nil {
	return err
}
counter.Add(ctx, 1, metric.WithAttributes(
	attribute.String("result", "success"),
))
```

Reuse instruments instead of creating them inside a high-frequency request loop. The JavaScript and
Go convenience methods cache instruments by name. Python's convenience method creates the gauge
through its Meter on each call, so create and retain an explicit `client.meter` instrument for a hot
path. Instruments you create through an OpenTelemetry Meter are your application's responsibility.

## Send an existing OpenTelemetry pipeline

Anectico accepts OTLP gauges, monotonic and non-monotonic sums, explicit-bucket histograms, and
summaries at `/v1/metrics`. Point your exporter or Collector at `https://api.anectico.com`, set the
`X-Anectico-API-Key` header, and keep these resource attributes consistent:

| Resource attribute | Why it matters |
| --- | --- |
| `service.name` | Identifies the emitting service and powers service grouping |
| `deployment.environment` | Keeps production, staging, and development distinct |

Use the normal OpenTelemetry SDK lifecycle for your language. A short-lived process must force a
metric collection and shut down its Meter Provider or Anectico client before exiting; waiting only for a
trace flush does not guarantee that a periodic metric reader has exported.

See [Configure OpenTelemetry](/docs/instrument/opentelemetry) for the endpoint and authentication
configuration.

## Keep names, units, and labels stable

- Label maps are unordered: the same key/value pairs identify the same Anectico metric series regardless
  of the order in which an SDK or exporter sends them.
- Give the metric one durable dotted or semantic-convention name. Put dimensions in labels, not in
  generated metric names.
- Keep the OpenTelemetry unit correct for pipeline portability. Anectico dashboard widgets currently set
  their display unit separately; if a convenience helper has no unit argument, make the unit
  unambiguous in the name, such as `checkout.duration_ms`.
- Prefer labels such as route template, result, region, queue, provider, or worker pool.
- Never use email, customer ID, order ID, request ID, trace ID, session ID, raw URL, or another
  effectively unique value as a metric label.
- Keep label keys and their meaning consistent across services. `environment=prod` and
  `deployment=production` create different series and make comparison harder.

Every distinct combination of metric name, service, environment, and labels is an active metric
series. A label with unbounded values can create thousands of series, raise usage, and make grouped
queries unusable. Customer identity belongs on traces, logs, errors, and events; use those signals to
explain which people a metric change affected.

**Signals → Metrics** shows the organization-wide active-series count and limit. It is not scoped to
the selected project, and the background usage snapshot may lag by a few minutes. At the limit,
Anectico continues to ingest datapoints for existing series but rejects unseen metric names or label
combinations. That rejection is non-retryable; reduce cardinality or raise the limit before sending
the new series.

## Verify the complete path

1. Record a metric named `anectico.verification.value` with value `1` and label `check=setup`.
2. Wait for one metric export interval, then flush or stop the client or Meter Provider cleanly.
3. Select the expected project and environment in Anectico.
4. Open **Signals → Metrics**, choose `anectico.verification.value`, use **Last 1 hour**, and refresh.
5. Confirm the CLI sees the same name and a recent point:

```bash
anectico metrics list
anectico metrics query anectico.verification.value --agg avg
```

After verification, stop emitting the test metric. Historical points remain until retention removes
them; deleting a metric is an administrative, destructive operation that removes every datapoint in
the credential's effective scope.

## If the metric does not appear

- Confirm metrics are enabled in the SDK or OpenTelemetry pipeline.
- Confirm the exporter uses `/v1/metrics` and a key with `ingest:write`.
- Allow for the metric export interval and flush short-lived processes.
- Check the selected project, environment, and time range.
- Look at SDK or Collector diagnostics for `401`, `403`, `413`, `429`, or export failures.
- Query the metric name with the CLI to separate ingestion from a dashboard filter problem.
- Remove customer or request identifiers from labels before sending more data.

- [Explore and compare metrics](/docs/investigate/metrics)
- [JavaScript SDK API](/docs/reference/javascript-sdk)
- [Python SDK API](/docs/reference/python-sdk)
- [Go SDK API](/docs/reference/go-sdk)
