Skip to content

Commit 2892b4f

Browse files
improvement(observability): switch Grafana telemetry vars to OTLP-shaped trio
1 parent a05317d commit 2892b4f

2 files changed

Lines changed: 36 additions & 15 deletions

File tree

apps/sim/lib/core/config/env.ts

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -158,9 +158,8 @@ export const env = createEnv({
158158
PROFOUND_API_KEY: z.string().min(1).optional(), // Profound analytics API key
159159
PROFOUND_ENDPOINT: z.string().url().optional(), // Profound analytics endpoint
160160
GRAFANA_OTLP_ENDPOINT: z.string().url().optional(), // Grafana Cloud OTLP HTTP gateway base URL (e.g., https://otlp-gateway-prod-us-east-0.grafana.net/otlp). Trigger.dev exporters append /v1/traces, /v1/logs, /v1/metrics.
161-
GRAFANA_INSTANCE_ID: z.string().min(1).optional(), // Grafana Cloud instance ID (Basic auth username for OTLP)
162-
GRAFANA_API_TOKEN: z.string().min(1).optional(), // Grafana Cloud API token (Basic auth password for OTLP)
163-
SIM_DEPLOYMENT_ENVIRONMENT: z.string().min(1).optional(), // Deployment tier label (e.g., "production", "staging", "development"). Emitted as the stable `deployment.environment.name` resource attribute on Trigger.dev telemetry to match the rest of the Sim OTEL stack.
161+
GRAFANA_OTLP_HEADERS: z.string().min(1).optional(), // Comma-separated key=value headers for OTLP requests (e.g., "Authorization=Basic <base64(instanceId:token)>"). Same format as the OTEL_EXPORTER_OTLP_HEADERS spec.
162+
GRAFANA_DEPLOYMENT_ENVIRONMENT: z.string().min(1).optional(), // Deployment tier label (e.g., "production", "staging", "development"). Emitted as the stable `deployment.environment.name` resource attribute on Trigger.dev telemetry to match the rest of the Sim OTEL stack.
164163

165164
// External Services
166165
BROWSERBASE_API_KEY: z.string().min(1).optional(), // Browserbase API key for browser automation

apps/sim/trigger.config.ts

Lines changed: 34 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -7,32 +7,54 @@ import { defineConfig } from '@trigger.dev/sdk'
77
import { env } from './lib/core/config/env'
88

99
const grafanaEndpoint = env.GRAFANA_OTLP_ENDPOINT
10-
const grafanaInstanceId = env.GRAFANA_INSTANCE_ID
11-
const grafanaToken = env.GRAFANA_API_TOKEN
12-
const grafanaConfigured = Boolean(grafanaEndpoint || grafanaInstanceId || grafanaToken)
13-
const grafanaFullyConfigured = Boolean(grafanaEndpoint && grafanaInstanceId && grafanaToken)
10+
const grafanaHeaders = env.GRAFANA_OTLP_HEADERS
11+
const grafanaDeploymentEnvironment = env.GRAFANA_DEPLOYMENT_ENVIRONMENT
12+
const grafanaConfigured = Boolean(grafanaEndpoint || grafanaHeaders || grafanaDeploymentEnvironment)
13+
const grafanaFullyConfigured = Boolean(
14+
grafanaEndpoint && grafanaHeaders && grafanaDeploymentEnvironment
15+
)
1416

1517
if (grafanaConfigured && !grafanaFullyConfigured) {
1618
throw new Error(
17-
'Grafana OTLP telemetry is partially configured. Set GRAFANA_OTLP_ENDPOINT, GRAFANA_INSTANCE_ID, and GRAFANA_API_TOKEN together, or leave all three unset.'
19+
'Grafana OTLP telemetry is partially configured. Set GRAFANA_OTLP_ENDPOINT, GRAFANA_OTLP_HEADERS, and GRAFANA_DEPLOYMENT_ENVIRONMENT together, or leave all three unset.'
1820
)
1921
}
2022

23+
/**
24+
* Parse OTLP headers per the OTEL spec format `key1=value1,key2=value2`.
25+
* Values are URL-decoded; keys/values are trimmed; empty entries are skipped.
26+
* @see https://opentelemetry.io/docs/specs/otel/protocol/exporter/
27+
*/
28+
function parseOtlpHeaders(raw: string): Record<string, string> {
29+
const out: Record<string, string> = {}
30+
for (const pair of raw.split(',')) {
31+
const eq = pair.indexOf('=')
32+
if (eq === -1) continue
33+
const key = pair.slice(0, eq).trim()
34+
const value = pair.slice(eq + 1).trim()
35+
if (!key) continue
36+
out[key] = decodeURIComponent(value)
37+
}
38+
return out
39+
}
40+
2141
const grafanaTelemetry = grafanaFullyConfigured
2242
? (() => {
2343
const baseUrl = grafanaEndpoint!.replace(/\/+$/, '')
24-
const headers = {
25-
Authorization: `Basic ${Buffer.from(`${grafanaInstanceId}:${grafanaToken}`).toString('base64')}`,
44+
const headers = parseOtlpHeaders(grafanaHeaders!)
45+
if (Object.keys(headers).length === 0) {
46+
throw new Error(
47+
'GRAFANA_OTLP_HEADERS is set but yielded no valid key=value pairs. Expected format: "key1=value1,key2=value2".'
48+
)
2649
}
27-
const deploymentEnvironment = env.SIM_DEPLOYMENT_ENVIRONMENT
28-
const resource = deploymentEnvironment
29-
? resourceFromAttributes({ 'deployment.environment.name': deploymentEnvironment })
30-
: undefined
50+
const resource = resourceFromAttributes({
51+
'deployment.environment.name': grafanaDeploymentEnvironment!,
52+
})
3153
return {
3254
exporters: [new OTLPTraceExporter({ url: `${baseUrl}/v1/traces`, headers })],
3355
logExporters: [new OTLPLogExporter({ url: `${baseUrl}/v1/logs`, headers })],
3456
metricExporters: [new OTLPMetricExporter({ url: `${baseUrl}/v1/metrics`, headers })],
35-
...(resource ? { resource } : {}),
57+
resource,
3658
}
3759
})()
3860
: undefined

0 commit comments

Comments
 (0)