mirror of
https://github.com/anomalyco/opencode.git
synced 2026-07-23 10:45:33 -04:00
80 lines
2.5 KiB
TypeScript
80 lines
2.5 KiB
TypeScript
import { Layer } from "effect"
|
|
import { OtlpLogger } from "effect/unstable/observability"
|
|
import { Flag } from "../flag/flag"
|
|
import { InstallationChannel, InstallationVersion } from "../installation/version"
|
|
import { runID } from "./shared"
|
|
|
|
const endpoint = Flag.OTEL_EXPORTER_OTLP_ENDPOINT
|
|
|
|
const headers = Flag.OTEL_EXPORTER_OTLP_HEADERS
|
|
? Flag.OTEL_EXPORTER_OTLP_HEADERS.split(",").reduce(
|
|
(acc, entry) => {
|
|
const [key, ...value] = entry.split("=")
|
|
acc[key] = value.join("=")
|
|
return acc
|
|
},
|
|
{} as Record<string, string>,
|
|
)
|
|
: undefined
|
|
|
|
function resourceAttributes() {
|
|
const value = process.env.OTEL_RESOURCE_ATTRIBUTES
|
|
if (!value) return {}
|
|
try {
|
|
return Object.fromEntries(
|
|
value.split(",").map((entry) => {
|
|
const index = entry.indexOf("=")
|
|
if (index < 1) throw new Error("Invalid OTEL_RESOURCE_ATTRIBUTES entry")
|
|
return [decodeURIComponent(entry.slice(0, index)), decodeURIComponent(entry.slice(index + 1))]
|
|
}),
|
|
)
|
|
} catch {
|
|
return {}
|
|
}
|
|
}
|
|
|
|
export function resource(): { serviceName: string; serviceVersion: string; attributes: Record<string, string> } {
|
|
return {
|
|
serviceName: "opencode",
|
|
serviceVersion: InstallationVersion,
|
|
attributes: {
|
|
...resourceAttributes(),
|
|
"deployment.environment.name": InstallationChannel,
|
|
"opencode.client": Flag.OPENCODE_CLIENT,
|
|
"opencode.run": runID,
|
|
"service.instance.id": runID,
|
|
},
|
|
}
|
|
}
|
|
|
|
export function loggers() {
|
|
if (!endpoint) return []
|
|
return [OtlpLogger.make({ url: `${endpoint}/v1/logs`, resource: resource(), headers })]
|
|
}
|
|
|
|
export async function tracingLayer() {
|
|
if (!endpoint) return Layer.empty
|
|
const NodeSdk = await import("@effect/opentelemetry/NodeSdk")
|
|
const OTLP = await import("@opentelemetry/exporter-trace-otlp-http")
|
|
const SdkBase = await import("@opentelemetry/sdk-trace-base")
|
|
const { AsyncLocalStorageContextManager } = await import("@opentelemetry/context-async-hooks")
|
|
const { context } = await import("@opentelemetry/api")
|
|
|
|
// The Effect Node SDK does not register a global context manager, but the AI SDK uses it to parent spans.
|
|
const manager = new AsyncLocalStorageContextManager()
|
|
manager.enable()
|
|
context.setGlobalContextManager(manager)
|
|
|
|
return NodeSdk.layer(() => ({
|
|
resource: resource(),
|
|
spanProcessor: new SdkBase.BatchSpanProcessor(
|
|
new OTLP.OTLPTraceExporter({
|
|
url: `${endpoint}/v1/traces`,
|
|
headers,
|
|
}),
|
|
),
|
|
}))
|
|
}
|
|
|
|
export * as Otlp from "./otlp"
|