Add OTel distributed tracing to backend, ui, and runner
Some checks failed
CI / Check ui (pull_request) Failing after 44s
CI / Docker / ui (pull_request) Has been skipped
CI / Test backend (pull_request) Successful in 3m30s
CI / Docker / backend (pull_request) Successful in 2m28s
CI / Docker / caddy (pull_request) Successful in 5m22s
CI / Docker / runner (pull_request) Successful in 1m52s

Go backend:
- Add OTel SDK + otelhttp middleware deps (go.mod)
- New internal/otelsetup package: init OTLP/HTTP TracerProvider from env vars
- cmd/backend/main.go: call otelsetup.Init() after logger + ctx setup
- internal/backend/server.go: wrap mux with otelhttp.NewHandler() before
  sentryhttp, so all HTTP spans are recorded

SvelteKit UI:
- Add @opentelemetry/sdk-node, exporter-trace-otlp-http, resources,
  semantic-conventions
- hooks.server.ts: init NodeSDK when OTEL_EXPORTER_OTLP_ENDPOINT is set;
  graceful shutdown on SIGTERM/SIGINT

Config:
- docker-compose.yml: pass OTEL_EXPORTER_OTLP_ENDPOINT + OTEL_SERVICE_NAME
  to backend, runner, and ui services
- homelab/docker-compose.yml: fix runner OTel endpoint to HTTP port 4318
- Doppler prd: OTEL_EXPORTER_OTLP_ENDPOINT=https://otel.libnovel.cc
- Doppler prd_homelab: OTEL_EXPORTER_OTLP_ENDPOINT=http://otel-collector:4318

All services no-op gracefully when the env var is unset (local dev).
This commit is contained in:
Admin
2026-03-26 23:00:52 +05:00
parent a39f660a37
commit ee3ed29316
11 changed files with 1354 additions and 18 deletions

1183
ui/package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -30,6 +30,10 @@
"dependencies": {
"@aws-sdk/client-s3": "^3.1005.0",
"@aws-sdk/s3-request-presigner": "^3.1005.0",
"@opentelemetry/exporter-trace-otlp-http": "^0.214.0",
"@opentelemetry/resources": "^2.6.1",
"@opentelemetry/sdk-node": "^0.214.0",
"@opentelemetry/semantic-conventions": "^1.40.0",
"@sentry/sveltekit": "^10.45.0",
"cropperjs": "^1.6.2",
"ioredis": "^5.3.2",

View File

@@ -7,6 +7,26 @@ import { env as pubEnv } from '$env/dynamic/public';
import { log } from '$lib/server/logger';
import { createUserSession, touchUserSession, isSessionRevoked } from '$lib/server/pocketbase';
import { drain as drainPresignCache } from '$lib/server/presignCache';
import { NodeSDK } from '@opentelemetry/sdk-node';
import { OTLPTraceExporter } from '@opentelemetry/exporter-trace-otlp-http';
import { Resource } from '@opentelemetry/resources';
import { ATTR_SERVICE_NAME, ATTR_SERVICE_VERSION } from '@opentelemetry/semantic-conventions';
// ─── OpenTelemetry server-side tracing ────────────────────────────────────────
// No-op when OTEL_EXPORTER_OTLP_ENDPOINT is unset (e.g. local dev).
const otlpEndpoint = process.env.OTEL_EXPORTER_OTLP_ENDPOINT;
if (otlpEndpoint) {
const sdk = new NodeSDK({
resource: new Resource({
[ATTR_SERVICE_NAME]: process.env.OTEL_SERVICE_NAME ?? 'ui',
[ATTR_SERVICE_VERSION]: pubEnv.PUBLIC_BUILD_VERSION ?? 'dev'
}),
traceExporter: new OTLPTraceExporter({ url: `${otlpEndpoint}/v1/traces` })
});
sdk.start();
process.once('SIGTERM', () => sdk.shutdown().catch(() => {}));
process.once('SIGINT', () => sdk.shutdown().catch(() => {}));
}
// ─── Sentry / GlitchTip server-side error tracking ────────────────────────────
// No-op when PUBLIC_GLITCHTIP_DSN is unset (e.g. local dev).