feat(plugin): expose app metadata (#38179)
This commit is contained in:
parent
2ed8fe5960
commit
8de40be6ea
71 changed files with 477 additions and 286 deletions
|
|
@ -1,14 +0,0 @@
|
|||
export * as Client from "./client.js"
|
||||
|
||||
import { Context, Layer } from "effect"
|
||||
import { makeGlobalNode } from "./effect/app-node.js"
|
||||
|
||||
export const Name = Context.Reference<string>("@opencode/Client/Name", {
|
||||
defaultValue: () => "cli",
|
||||
})
|
||||
|
||||
export const layer = (name = "cli") => Layer.succeed(Name, name)
|
||||
|
||||
export const configured = (name?: string) => makeGlobalNode({ service: Name, layer: layer(name), deps: [] })
|
||||
|
||||
export const node = configured()
|
||||
|
|
@ -1,6 +0,0 @@
|
|||
declare const OPENCODE_VERSION: string
|
||||
declare const OPENCODE_CHANNEL: string
|
||||
|
||||
export const InstallationVersion = typeof OPENCODE_VERSION === "string" ? OPENCODE_VERSION : "local"
|
||||
export const InstallationChannel = typeof OPENCODE_CHANNEL === "string" ? OPENCODE_CHANNEL : "local"
|
||||
export const InstallationLocal = InstallationChannel === "local"
|
||||
|
|
@ -7,11 +7,13 @@ import { FetchHttpClient } from "effect/unstable/http"
|
|||
import { OtlpSerialization } from "effect/unstable/observability"
|
||||
import { Logging } from "./observability/logging.js"
|
||||
import { Otlp } from "./observability/otlp.js"
|
||||
import { Client } from "./client.js"
|
||||
|
||||
export const Options = Schema.Struct({
|
||||
endpoint: Schema.optional(Schema.String),
|
||||
headers: Schema.optional(Schema.String),
|
||||
client: Schema.optional(Schema.String),
|
||||
version: Schema.optional(Schema.String),
|
||||
channel: Schema.optional(Schema.String),
|
||||
})
|
||||
export type Options = typeof Options.Type
|
||||
|
||||
|
|
@ -21,24 +23,29 @@ export function layer(
|
|||
headers: process.env.OTEL_EXPORTER_OTLP_HEADERS,
|
||||
},
|
||||
) {
|
||||
const local = Logger.layer(Logging.loggers(), { mergeWithExisting: false }).pipe(
|
||||
const app = {
|
||||
client: options.client ?? "opencode",
|
||||
version: options.version ?? "unknown",
|
||||
channel: options.channel ?? "local",
|
||||
}
|
||||
const local = Logger.layer(Logging.loggers(app.channel === "local", app.channel), { mergeWithExisting: false }).pipe(
|
||||
Layer.provide(NodeFileSystem.layer),
|
||||
Layer.orDie,
|
||||
Layer.merge(Layer.succeed(References.MinimumLogLevel, Logging.minimumLogLevel())),
|
||||
)
|
||||
return Layer.unwrap(
|
||||
Effect.gen(function* () {
|
||||
const client = yield* Client.Name
|
||||
const logs = Logger.layer([...Logging.loggers(), ...Otlp.loggers(options, client)], {
|
||||
mergeWithExisting: false,
|
||||
}).pipe(
|
||||
const logs = Logger.layer(
|
||||
[...Logging.loggers(app.channel === "local", app.channel), ...Otlp.loggers(options, app)],
|
||||
{ mergeWithExisting: false },
|
||||
).pipe(
|
||||
Layer.provide(NodeFileSystem.layer),
|
||||
Layer.provide(OtlpSerialization.layerJson),
|
||||
Layer.provide(FetchHttpClient.layer),
|
||||
Layer.orDie,
|
||||
Layer.merge(Layer.succeed(References.MinimumLogLevel, Logging.minimumLogLevel())),
|
||||
)
|
||||
return Layer.merge(logs, yield* Effect.promise(() => Otlp.tracingLayer(options, client)))
|
||||
return Layer.merge(logs, yield* Effect.promise(() => Otlp.tracingLayer(options, app)))
|
||||
}),
|
||||
).pipe(Layer.catchCause(() => local))
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
import { Formatter, Logger, type LogLevel } from "effect"
|
||||
import path from "path"
|
||||
import { Global } from "../global.js"
|
||||
import { InstallationChannel, InstallationLocal } from "../installation/version.js"
|
||||
import { runID } from "./shared.js"
|
||||
|
||||
function formatter(id: string = runID) {
|
||||
|
|
@ -47,7 +46,7 @@ function format(input: unknown) {
|
|||
return /^[^\s="\\]+$/.test(value) ? value : JSON.stringify(value)
|
||||
}
|
||||
|
||||
export function file(local = InstallationLocal, channel = InstallationChannel) {
|
||||
export function file(local = true, channel = "local") {
|
||||
if (!local) return path.join(Global.Path.log, "opencode.log")
|
||||
return path.join(Global.Path.log, `opencode-${channel.replace(/[^a-zA-Z0-9._-]/g, "-")}.log`)
|
||||
}
|
||||
|
|
@ -70,8 +69,9 @@ export function minimumLogLevel() {
|
|||
return value && value in levels ? levels[value as keyof typeof levels] : levels.INFO
|
||||
}
|
||||
|
||||
export function loggers() {
|
||||
return process.env.OPENCODE_PRINT_LOGS === "1" ? [fileLogger(), stderrLogger] : [fileLogger()]
|
||||
export function loggers(local = true, channel = "local") {
|
||||
const logger = fileLogger(file(local, channel))
|
||||
return process.env.OPENCODE_PRINT_LOGS === "1" ? [logger, stderrLogger] : [logger]
|
||||
}
|
||||
|
||||
export * as Logging from "./logging.js"
|
||||
|
|
|
|||
|
|
@ -1,6 +1,5 @@
|
|||
import { Layer } from "effect"
|
||||
import { OtlpLogger } from "effect/unstable/observability"
|
||||
import { InstallationChannel, InstallationVersion } from "../installation/version.js"
|
||||
import { runID } from "./shared.js"
|
||||
|
||||
export interface Options {
|
||||
|
|
@ -8,6 +7,12 @@ export interface Options {
|
|||
readonly headers?: string
|
||||
}
|
||||
|
||||
export interface App {
|
||||
readonly client: string
|
||||
readonly version: string
|
||||
readonly channel: string
|
||||
}
|
||||
|
||||
function parseHeaders(value?: string) {
|
||||
return value
|
||||
? value.split(",").reduce(
|
||||
|
|
@ -37,36 +42,36 @@ function resourceAttributes() {
|
|||
}
|
||||
}
|
||||
|
||||
export function resource(client = "cli"): {
|
||||
export function resource(app: App = { client: "opencode", version: "unknown", channel: "local" }): {
|
||||
serviceName: string
|
||||
serviceVersion: string
|
||||
attributes: Record<string, string>
|
||||
} {
|
||||
return {
|
||||
serviceName: "opencode",
|
||||
serviceVersion: InstallationVersion,
|
||||
serviceVersion: app.version,
|
||||
attributes: {
|
||||
...resourceAttributes(),
|
||||
"deployment.environment.name": InstallationChannel,
|
||||
"opencode.client": client,
|
||||
"deployment.environment.name": app.channel,
|
||||
"opencode.client": app.client,
|
||||
"opencode.run": runID,
|
||||
"service.instance.id": runID,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
export function loggers(options: Options | undefined, client: string) {
|
||||
export function loggers(options: Options | undefined, app: App) {
|
||||
if (!options?.endpoint) return []
|
||||
return [
|
||||
OtlpLogger.make({
|
||||
url: `${options.endpoint}/v1/logs`,
|
||||
resource: resource(client),
|
||||
resource: resource(app),
|
||||
headers: parseHeaders(options.headers),
|
||||
}),
|
||||
]
|
||||
}
|
||||
|
||||
export async function tracingLayer(options: Options | undefined, client: string) {
|
||||
export async function tracingLayer(options: Options | undefined, app: App) {
|
||||
if (!options?.endpoint) return Layer.empty
|
||||
const NodeSdk = await import("@effect/opentelemetry/NodeSdk")
|
||||
const OTLP = await import("@opentelemetry/exporter-trace-otlp-http")
|
||||
|
|
@ -80,7 +85,7 @@ export async function tracingLayer(options: Options | undefined, client: string)
|
|||
context.setGlobalContextManager(manager)
|
||||
|
||||
return NodeSdk.layer(() => ({
|
||||
resource: resource(client),
|
||||
resource: resource(app),
|
||||
spanProcessor: new SdkBase.BatchSpanProcessor(
|
||||
new OTLP.OTLPTraceExporter({
|
||||
url: `${options.endpoint}/v1/traces`,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue