Skip to content

Commit 6765252

Browse files
authored
docs: otel metrics (#3096)
1 parent 79f8cde commit 6765252

File tree

4 files changed

+199
-12
lines changed

4 files changed

+199
-12
lines changed

docs/config/config-file.mdx

Lines changed: 35 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -154,21 +154,30 @@ Some ones we recommend:
154154

155155
### Telemetry Exporters
156156

157-
You can also configure custom telemetry exporters to send your traces and logs to other external services. For example, you can send your logs to [Axiom](https://axiom.co/docs/guides/opentelemetry-nodejs#exporter-instrumentation-ts). First, add the opentelemetry exporter packages to your package.json file:
157+
You can also configure custom telemetry exporters to send your traces, logs, and metrics to other external services. For example, you can send your logs to [Axiom](https://axiom.co/docs/guides/opentelemetry-nodejs#exporter-instrumentation-ts). First, add the opentelemetry exporter packages to your package.json file:
158158

159159
```json package.json
160160
"dependencies": {
161161
"@opentelemetry/exporter-logs-otlp-http": "0.52.1",
162-
"@opentelemetry/exporter-trace-otlp-http": "0.52.1"
162+
"@opentelemetry/exporter-trace-otlp-http": "0.52.1",
163+
"@opentelemetry/exporter-metrics-otlp-proto": "0.52.1"
163164
}
164165
```
165166

167+
<Note>
168+
Axiom's `/v1/metrics` endpoint only supports protobuf (`application/x-protobuf`), not JSON. Use
169+
`@opentelemetry/exporter-metrics-otlp-proto` instead of
170+
`@opentelemetry/exporter-metrics-otlp-http` for metrics. Traces and logs work fine with the
171+
`-http` (JSON) exporters.
172+
</Note>
173+
166174
Then, configure the exporters in your `trigger.config.ts` file:
167175

168176
```ts trigger.config.ts
169177
import { defineConfig } from "@trigger.dev/sdk";
170178
import { OTLPTraceExporter } from "@opentelemetry/exporter-trace-otlp-http";
171179
import { OTLPLogExporter } from "@opentelemetry/exporter-logs-otlp-http";
180+
import { OTLPMetricExporter } from "@opentelemetry/exporter-metrics-otlp-proto";
172181

173182
// Initialize OTLP trace exporter with the endpoint URL and headers;
174183
export default defineConfig({
@@ -196,18 +205,28 @@ export default defineConfig({
196205
},
197206
}),
198207
],
208+
metricExporters: [
209+
new OTLPMetricExporter({
210+
url: "https://api.axiom.co/v1/metrics",
211+
headers: {
212+
Authorization: `Bearer ${process.env.AXIOM_API_TOKEN}`,
213+
"x-axiom-metrics-dataset": process.env.AXIOM_METRICS_DATASET,
214+
},
215+
}),
216+
],
199217
},
200218
});
201219
```
202220

203-
Make sure to set the `AXIOM_API_TOKEN` and `AXIOM_DATASET` environment variables in your project.
221+
Make sure to set the `AXIOM_API_TOKEN`, `AXIOM_DATASET`, and `AXIOM_METRICS_DATASET` environment variables in your project. Axiom requires a separate, dedicated dataset for metrics — you cannot reuse the same dataset for traces/logs and metrics.
204222

205-
It's important to note that you cannot configure exporters using `OTEL_*` environment variables, as they would conflict with our internal telemetry. Instead you should configure the exporters via passing in arguments to the `OTLPTraceExporter` and `OTLPLogExporter` constructors. For example, here is how you can configure exporting to Honeycomb:
223+
It's important to note that you cannot configure exporters using `OTEL_*` environment variables, as they would conflict with our internal telemetry. Instead you should configure the exporters via passing in arguments to the `OTLPTraceExporter`, `OTLPLogExporter`, and `OTLPMetricExporter` constructors. For example, here is how you can configure exporting to Honeycomb:
206224

207225
```ts trigger.config.ts
208226
import { defineConfig } from "@trigger.dev/sdk";
209227
import { OTLPTraceExporter } from "@opentelemetry/exporter-trace-otlp-http";
210228
import { OTLPLogExporter } from "@opentelemetry/exporter-logs-otlp-http";
229+
import { OTLPMetricExporter } from "@opentelemetry/exporter-metrics-otlp-http";
211230

212231
// Initialize OTLP trace exporter with the endpoint URL and headers;
213232
export default defineConfig({
@@ -235,6 +254,15 @@ export default defineConfig({
235254
},
236255
}),
237256
],
257+
metricExporters: [
258+
new OTLPMetricExporter({
259+
url: "https://api.honeycomb.io/v1/metrics",
260+
headers: {
261+
"x-honeycomb-team": process.env.HONEYCOMB_API_KEY,
262+
"x-honeycomb-dataset": process.env.HONEYCOMB_DATASET,
263+
},
264+
}),
265+
],
238266
},
239267
});
240268
```
@@ -465,8 +493,9 @@ export default defineConfig({
465493
```
466494

467495
<Note>
468-
Any packages that install or build a native binary or use WebAssembly (WASM) should be added to external, as they
469-
cannot be bundled. For example, `re2`, `sharp`, `sqlite3`, and WASM packages should be added to external.
496+
Any packages that install or build a native binary or use WebAssembly (WASM) should be added to
497+
external, as they cannot be bundled. For example, `re2`, `sharp`, `sqlite3`, and WASM packages
498+
should be added to external.
470499
</Note>
471500

472501
### JSX

docs/insights/metrics.mdx

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,12 @@ In the Trigger.dev dashboard we have built-in dashboards and you can create your
99

1010
Metrics dashboards are powered by [TRQL queries](/insights/query) with widgets that can be displayed as charts, tables, or single values. They automatically refresh to show the latest data.
1111

12+
### Available metrics data
13+
14+
Trigger.dev automatically collects process metrics (CPU, memory) and Node.js runtime metrics (event loop, heap) for all deployed tasks -- no configuration needed. Requires SDK version **4.4.1 or later**. You can also create custom metrics using the `otel.metrics` API from the SDK.
15+
16+
All of this data is available in the `metrics` table for use in dashboard widgets. See [Logging, tracing & metrics](/logging#metrics) for the full list of automatic metrics and how to create custom ones, or the [Query page](/insights/query#metrics-table-columns) for the `metrics` table schema.
17+
1218
![The built-in Metrics dashboard](/images/metrics-built-in.png)
1319

1420
### Visualization types

docs/insights/query.mdx

Lines changed: 40 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,43 @@ description: "Query allows you to write custom queries against your data using T
66
### Available tables
77

88
- `runs`: contains all task run data including status, timing, costs, and metadata
9-
- `metrics`: contains metrics data for your runs including CPU, memory, and your custom metrics.
9+
- `metrics`: contains metrics data for your runs including CPU, memory, and your custom metrics
10+
11+
### `metrics` table columns
12+
13+
| Column | Type | Description |
14+
| :--- | :--- | :--- |
15+
| `metric_name` | string | Metric identifier (e.g., `process.cpu.utilization`) |
16+
| `metric_type` | string | `gauge`, `sum`, or `histogram` |
17+
| `value` | number | The observed value |
18+
| `bucket_start` | datetime | 10-second aggregation bucket start time |
19+
| `run_id` | string | Associated run ID |
20+
| `task_identifier` | string | Task slug |
21+
| `attempt_number` | number | Attempt number |
22+
| `machine_id` | string | Machine that produced the metric |
23+
| `machine_name` | string | Machine preset (e.g., `small-1x`) |
24+
| `worker_version` | string | Worker version |
25+
| `environment_type` | string | `PRODUCTION`, `STAGING`, `DEVELOPMENT`, `PREVIEW` |
26+
| `attributes` | json | Raw JSON attributes for custom data |
27+
28+
See [Logging, tracing & metrics](/logging#automatic-system-and-runtime-metrics) for the full list of automatically collected metrics and how to create custom metrics.
29+
30+
### `prettyFormat()`
31+
32+
Use `prettyFormat()` to format metric values for display:
33+
34+
```sql
35+
SELECT
36+
timeBucket(),
37+
prettyFormat(avg(value), 'bytes') AS avg_memory
38+
FROM metrics
39+
WHERE metric_name = 'process.memory.usage'
40+
GROUP BY timeBucket
41+
ORDER BY timeBucket
42+
LIMIT 1000
43+
```
44+
45+
Available format types: `bytes`, `percent`, `duration`, `durationSeconds`, `quantity`, `costInDollars`.
1046

1147
## Using the Query dashboard
1248

@@ -191,7 +227,7 @@ SELECT
191227
task_identifier,
192228
avg(value) AS avg_memory
193229
FROM metrics
194-
WHERE metric_name = 'system.memory.usage'
230+
WHERE metric_name = 'process.memory.usage'
195231
GROUP BY task_identifier
196232
ORDER BY avg_memory DESC
197233
LIMIT 20
@@ -500,14 +536,14 @@ LIMIT 1000
500536

501537
### Memory usage by task (past 7d)
502538

503-
Average memory usage per task identifier over the last 7 days.
539+
Average process memory usage per task identifier over the last 7 days.
504540

505541
```sql
506542
SELECT
507543
task_identifier,
508544
avg(value) AS avg_memory
509545
FROM metrics
510-
WHERE metric_name = 'system.memory.usage'
546+
WHERE metric_name = 'process.memory.usage'
511547
GROUP BY task_identifier
512548
ORDER BY avg_memory DESC
513549
LIMIT 20

docs/logging.mdx

Lines changed: 118 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
---
2-
title: "Logging and tracing"
3-
description: "How to use the built-in logging and tracing system."
2+
title: "Logging, tracing & metrics"
3+
description: "How to use the built-in logging, tracing, and metrics system."
44
---
55

66
![The run log](/images/run-log.png)
@@ -77,3 +77,119 @@ export const customTrace = task({
7777
},
7878
});
7979
```
80+
81+
## Metrics
82+
83+
Trigger.dev collects system and runtime metrics automatically for deployed tasks, and provides an API for recording custom metrics using OpenTelemetry.
84+
85+
You can view metrics in the [Metrics dashboards](/insights/metrics), query them with [TRQL](/insights/query), and export them to external services via [telemetry exporters](/config/config-file#telemetry-exporters).
86+
87+
### Custom metrics API
88+
89+
Import `otel` from `@trigger.dev/sdk` and use the standard OpenTelemetry Metrics API to create custom instruments.
90+
91+
Create instruments **at module level** (outside the task `run` function) so they are reused across runs:
92+
93+
```ts /trigger/metrics.ts
94+
import { task, logger, otel } from "@trigger.dev/sdk";
95+
96+
// Create a meter — instruments are created once at module level
97+
const meter = otel.metrics.getMeter("my-app");
98+
99+
const itemsProcessed = meter.createCounter("items.processed", {
100+
description: "Total number of items processed",
101+
unit: "items",
102+
});
103+
104+
const itemDuration = meter.createHistogram("item.duration", {
105+
description: "Time spent processing each item",
106+
unit: "ms",
107+
});
108+
109+
const queueDepth = meter.createUpDownCounter("queue.depth", {
110+
description: "Current queue depth",
111+
unit: "items",
112+
});
113+
114+
export const processQueue = task({
115+
id: "process-queue",
116+
run: async (payload: { items: string[] }) => {
117+
queueDepth.add(payload.items.length);
118+
119+
for (const item of payload.items) {
120+
const start = performance.now();
121+
122+
// ... process item ...
123+
124+
const elapsed = performance.now() - start;
125+
126+
itemsProcessed.add(1, { "item.type": "order" });
127+
itemDuration.record(elapsed, { "item.type": "order" });
128+
queueDepth.add(-1);
129+
}
130+
131+
logger.info("Queue processed", { count: payload.items.length });
132+
},
133+
});
134+
```
135+
136+
#### Available instrument types
137+
138+
| Instrument | Method | Use case |
139+
| :--- | :--- | :--- |
140+
| Counter | `meter.createCounter()` | Monotonically increasing values (items processed, requests sent) |
141+
| Histogram | `meter.createHistogram()` | Distributions of values (durations, sizes) |
142+
| UpDownCounter | `meter.createUpDownCounter()` | Values that go up and down (queue depth, active connections) |
143+
144+
All instruments accept optional attributes when recording values. Attributes let you break down metrics by dimension (e.g., by item type, status, or region).
145+
146+
### Automatic system and runtime metrics
147+
148+
Trigger.dev automatically collects the following metrics for deployed tasks. No configuration is needed. Requires SDK version **4.4.1 or later**.
149+
150+
| Metric name | Type | Unit | Description |
151+
| :--- | :--- | :--- | :--- |
152+
| `process.cpu.utilization` | gauge | ratio | Process CPU usage (0-1) |
153+
| `process.cpu.time` | counter | seconds | CPU time consumed |
154+
| `process.memory.usage` | gauge | bytes | Process memory usage |
155+
| `nodejs.event_loop.utilization` | gauge | ratio | Event loop utilization (0-1) |
156+
| `nodejs.event_loop.delay.p95` | gauge | seconds | Event loop delay p95 |
157+
| `nodejs.event_loop.delay.max` | gauge | seconds | Event loop delay max |
158+
| `nodejs.heap.used` | gauge | bytes | V8 heap used |
159+
| `nodejs.heap.total` | gauge | bytes | V8 heap total |
160+
161+
<Note>
162+
In dev mode (`trigger dev`), only `process.*` and custom metrics are available.
163+
</Note>
164+
165+
### Context attributes
166+
167+
All metrics (both automatic and custom) are tagged with run context so you can filter and group them:
168+
169+
- `run_id` — the run that produced the metric
170+
- `task_identifier` — the task slug
171+
- `attempt_number` — the attempt number
172+
- `machine_name` — the machine preset (e.g., `small-1x`)
173+
- `worker_version` — the deployed worker version
174+
- `environment_type``PRODUCTION`, `STAGING`, `DEVELOPMENT`, or `PREVIEW`
175+
176+
### Querying metrics
177+
178+
Use [TRQL](/insights/query) to query metrics data. For example, to see average CPU utilization over time:
179+
180+
```sql
181+
SELECT
182+
timeBucket(),
183+
avg(value) AS avg_cpu
184+
FROM metrics
185+
WHERE metric_name = 'process.cpu.utilization'
186+
GROUP BY timeBucket
187+
ORDER BY timeBucket
188+
LIMIT 1000
189+
```
190+
191+
See the [Query page](/insights/query#metrics-table-columns) for the full `metrics` table schema.
192+
193+
### Exporting metrics
194+
195+
You can send metrics to external observability services (Axiom, Honeycomb, Datadog, etc.) by configuring [telemetry exporters](/config/config-file#telemetry-exporters) in your `trigger.config.ts`.

0 commit comments

Comments
 (0)