From bad732c90e076114a4ab5d530ba76a07f8c0e781 Mon Sep 17 00:00:00 2001 From: Dax Raad Date: Tue, 7 Apr 2026 17:01:42 -0400 Subject: [PATCH] feat(opencode): add OTLP observability support - Add Observability layer with OTLP tracer provider - Integrate observability layer into service runtime - Add OTEL_EXPORTER_OTLP_ENDPOINT and OTEL_EXPORTER_OTLP_HEADERS env flags --- packages/opencode/src/effect/oltp.ts | 34 +++++++++++++++++++++ packages/opencode/src/effect/run-service.ts | 3 +- packages/opencode/src/flag/flag.ts | 3 ++ 3 files changed, 39 insertions(+), 1 deletion(-) create mode 100644 packages/opencode/src/effect/oltp.ts diff --git a/packages/opencode/src/effect/oltp.ts b/packages/opencode/src/effect/oltp.ts new file mode 100644 index 000000000000..1fa697fb6eb4 --- /dev/null +++ b/packages/opencode/src/effect/oltp.ts @@ -0,0 +1,34 @@ +import { Layer } from "effect" +import { FetchHttpClient } from "effect/unstable/http" +import { Otlp } from "effect/unstable/observability" +import { Flag } from "@/flag/flag" +import { CHANNEL, VERSION } from "@/installation/meta" + +export namespace Observability { + export const enabled = !!Flag.OTEL_EXPORTER_OTLP_ENDPOINT + + export const layer = !Flag.OTEL_EXPORTER_OTLP_ENDPOINT + ? Layer.empty + : Otlp.layerJson({ + baseUrl: Flag.OTEL_EXPORTER_OTLP_ENDPOINT, + loggerMergeWithExisting: false, + resource: { + serviceName: "opencode", + serviceVersion: VERSION, + attributes: { + "deployment.environment.name": CHANNEL === "local" ? "local" : CHANNEL, + "opencode.client": Flag.OPENCODE_CLIENT, + }, + }, + headers: Flag.OTEL_EXPORTER_OTLP_HEADERS + ? Flag.OTEL_EXPORTER_OTLP_HEADERS.split(",").reduce( + (acc, x) => { + const [key, value] = x.split("=") + acc[key] = value + return acc + }, + {} as Record, + ) + : undefined, + }).pipe(Layer.provide(FetchHttpClient.layer)) +} diff --git a/packages/opencode/src/effect/run-service.ts b/packages/opencode/src/effect/run-service.ts index 619d5be6b5d7..f609986b5837 100644 --- a/packages/opencode/src/effect/run-service.ts +++ b/packages/opencode/src/effect/run-service.ts @@ -3,6 +3,7 @@ import * as ServiceMap from "effect/ServiceMap" import { Instance } from "@/project/instance" import { Context } from "@/util/context" import { InstanceRef } from "./instance-ref" +import { Observability } from "./oltp" export const memoMap = Layer.makeMemoMapUnsafe() @@ -18,7 +19,7 @@ function attach(effect: Effect.Effect): Effect.Effect export function makeRuntime(service: ServiceMap.Service, layer: Layer.Layer) { let rt: ManagedRuntime.ManagedRuntime | undefined - const getRuntime = () => (rt ??= ManagedRuntime.make(layer, { memoMap })) + const getRuntime = () => (rt ??= ManagedRuntime.make(Layer.merge(layer, Observability.layer), { memoMap })) return { runSync: (fn: (svc: S) => Effect.Effect) => getRuntime().runSync(attach(service.use(fn))), diff --git a/packages/opencode/src/flag/flag.ts b/packages/opencode/src/flag/flag.ts index 739009502b17..f091fa02a987 100644 --- a/packages/opencode/src/flag/flag.ts +++ b/packages/opencode/src/flag/flag.ts @@ -11,6 +11,9 @@ function falsy(key: string) { } export namespace Flag { + export const OTEL_EXPORTER_OTLP_ENDPOINT = process.env["OTEL_EXPORTER_OTLP_ENDPOINT"] + export const OTEL_EXPORTER_OTLP_HEADERS = process.env["OTEL_EXPORTER_OTLP_HEADERS"] + export const OPENCODE_AUTO_SHARE = truthy("OPENCODE_AUTO_SHARE") export const OPENCODE_AUTO_HEAP_SNAPSHOT = truthy("OPENCODE_AUTO_HEAP_SNAPSHOT") export const OPENCODE_GIT_BASH_PATH = process.env["OPENCODE_GIT_BASH_PATH"]