Skip to content

Commit f467f2f

Browse files
fix(otel): respect OTEL_EXPORTER_OTLP_METRICS_TEMPORALITY_PREFERENCE for delta temporality
1 parent 92c9583 commit f467f2f

3 files changed

Lines changed: 55 additions & 2 deletions

File tree

README.md

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -150,10 +150,18 @@ export OPENCODE_DISABLE_METRICS="cache.count,session.duration,session.token.tota
150150

151151
```bash
152152
export OPENCODE_ENABLE_TELEMETRY=1
153-
export OPENCODE_OTLP_ENDPOINT=https://api.datadoghq.com
153+
export OPENCODE_OTLP_ENDPOINT=https://otlp.datadoghq.com
154154
export OPENCODE_OTLP_PROTOCOL=http/protobuf
155+
export OPENCODE_OTLP_HEADERS="dd-api-key=YOUR_DATADOG_API_KEY"
156+
157+
# Required — Datadog's OTLP intake only accepts delta temporality
158+
export OTEL_EXPORTER_OTLP_METRICS_TEMPORALITY_PREFERENCE=delta
155159
```
156160

161+
> **Note:** The endpoint is `otlp.datadoghq.com` (not `api.datadoghq.com`).
162+
> Use `otlp.datadoghq.eu` for EU, `otlp.us3.datadoghq.com` for US3, etc.
163+
> See [Datadog OTLP docs](https://docs.datadoghq.com/opentelemetry/interoperability/otlp_ingest_in_the_agent/) for all regions.
164+
157165
### Honeycomb example
158166

159167
```bash

src/otel.ts

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { logs } from "@opentelemetry/api-logs"
22
import { metrics, trace } from "@opentelemetry/api"
33
import { LoggerProvider, BatchLogRecordProcessor } from "@opentelemetry/sdk-logs"
4-
import { MeterProvider, PeriodicExportingMetricReader } from "@opentelemetry/sdk-metrics"
4+
import { AggregationTemporality, MeterProvider, PeriodicExportingMetricReader } from "@opentelemetry/sdk-metrics"
55
import { BasicTracerProvider, BatchSpanProcessor } from "@opentelemetry/sdk-trace-base"
66
import { OTLPLogExporter } from "@opentelemetry/exporter-logs-otlp-grpc"
77
import { OTLPMetricExporter } from "@opentelemetry/exporter-metrics-otlp-grpc"
@@ -77,12 +77,18 @@ export function setupOtel(
7777
? new OTLPHttpTraceExporter({ url: buildHttpSignalUrl(endpoint, "traces") })
7878
: new OTLPTraceExporter({ url: endpoint })
7979

80+
const temporalityPref = process.env["OTEL_EXPORTER_OTLP_METRICS_TEMPORALITY_PREFERENCE"]?.toLowerCase()
81+
const preferDelta = temporalityPref === "delta" || temporalityPref === "lowmemory"
82+
8083
const meterProvider = new MeterProvider({
8184
resource,
8285
readers: [
8386
new PeriodicExportingMetricReader({
8487
exporter: metricExporter,
8588
exportIntervalMillis: metricsInterval,
89+
...(preferDelta && {
90+
temporalitySelector: () => AggregationTemporality.DELTA,
91+
}),
8692
}),
8793
],
8894
})

tests/otel.test.ts

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,3 +41,42 @@ describe("buildResource", () => {
4141
expect(resource.attributes["service.name"]).toBe("my-override")
4242
})
4343
})
44+
45+
describe("setupOtel temporality", () => {
46+
const originalEnv = process.env["OTEL_EXPORTER_OTLP_METRICS_TEMPORALITY_PREFERENCE"]
47+
afterEach(() => {
48+
if (originalEnv === undefined) {
49+
delete process.env["OTEL_EXPORTER_OTLP_METRICS_TEMPORALITY_PREFERENCE"]
50+
} else {
51+
process.env["OTEL_EXPORTER_OTLP_METRICS_TEMPORALITY_PREFERENCE"] = originalEnv
52+
}
53+
})
54+
55+
test("defaults to cumulative when env var is unset", () => {
56+
delete process.env["OTEL_EXPORTER_OTLP_METRICS_TEMPORALITY_PREFERENCE"]
57+
const pref = process.env["OTEL_EXPORTER_OTLP_METRICS_TEMPORALITY_PREFERENCE"]?.toLowerCase()
58+
const preferDelta = pref === "delta" || pref === "lowmemory"
59+
expect(preferDelta).toBe(false)
60+
})
61+
62+
test("selects delta when env var is 'delta'", () => {
63+
process.env["OTEL_EXPORTER_OTLP_METRICS_TEMPORALITY_PREFERENCE"] = "delta"
64+
const pref = process.env["OTEL_EXPORTER_OTLP_METRICS_TEMPORALITY_PREFERENCE"]?.toLowerCase()
65+
const preferDelta = pref === "delta" || pref === "lowmemory"
66+
expect(preferDelta).toBe(true)
67+
})
68+
69+
test("selects delta when env var is 'lowmemory'", () => {
70+
process.env["OTEL_EXPORTER_OTLP_METRICS_TEMPORALITY_PREFERENCE"] = "lowmemory"
71+
const pref = process.env["OTEL_EXPORTER_OTLP_METRICS_TEMPORALITY_PREFERENCE"]?.toLowerCase()
72+
const preferDelta = pref === "delta" || pref === "lowmemory"
73+
expect(preferDelta).toBe(true)
74+
})
75+
76+
test("is case-insensitive", () => {
77+
process.env["OTEL_EXPORTER_OTLP_METRICS_TEMPORALITY_PREFERENCE"] = "Delta"
78+
const pref = process.env["OTEL_EXPORTER_OTLP_METRICS_TEMPORALITY_PREFERENCE"]?.toLowerCase()
79+
const preferDelta = pref === "delta" || pref === "lowmemory"
80+
expect(preferDelta).toBe(true)
81+
})
82+
})

0 commit comments

Comments
 (0)