diff options
| author | Kit Langton <[email protected]> | 2026-04-15 17:32:56 -0400 |
|---|---|---|
| committer | GitHub <[email protected]> | 2026-04-15 17:32:56 -0400 |
| commit | 6bed7d469d8f6a18d5543cc668d951d0d1e09776 (patch) | |
| tree | dae49a53db93eb4db06b0a0b2148d999a67c745f /packages | |
| parent | 3b75f16119b914fa6eb7dd451a0f3fb20d22d69f (diff) | |
| download | opencode-6bed7d469d8f6a18d5543cc668d951d0d1e09776.tar.gz opencode-6bed7d469d8f6a18d5543cc668d951d0d1e09776.zip | |
feat(opencode): improve telemetry tracing and request spans (#22653)
Diffstat (limited to 'packages')
| -rw-r--r-- | packages/opencode/src/effect/app-runtime.ts | 3 | ||||
| -rw-r--r-- | packages/opencode/src/effect/run-service.ts | 2 | ||||
| -rw-r--r-- | packages/opencode/src/server/instance/config.ts | 34 | ||||
| -rw-r--r-- | packages/opencode/src/server/instance/session.ts | 28 | ||||
| -rw-r--r-- | packages/opencode/src/server/instance/trace.ts | 33 |
5 files changed, 68 insertions, 32 deletions
diff --git a/packages/opencode/src/effect/app-runtime.ts b/packages/opencode/src/effect/app-runtime.ts index 5948bd25e..257922daf 100644 --- a/packages/opencode/src/effect/app-runtime.ts +++ b/packages/opencode/src/effect/app-runtime.ts @@ -49,7 +49,6 @@ import { ShareNext } from "@/share/share-next" import { SessionShare } from "@/share/session" export const AppLayer = Layer.mergeAll( - Observability.layer, AppFileSystem.defaultLayer, Bus.defaultLayer, Auth.defaultLayer, @@ -95,7 +94,7 @@ export const AppLayer = Layer.mergeAll( Installation.defaultLayer, ShareNext.defaultLayer, SessionShare.defaultLayer, -) +).pipe(Layer.provideMerge(Observability.layer)) const rt = ManagedRuntime.make(AppLayer, { memoMap }) type Runtime = Pick<typeof rt, "runSync" | "runPromise" | "runPromiseExit" | "runFork" | "runCallback" | "dispose"> diff --git a/packages/opencode/src/effect/run-service.ts b/packages/opencode/src/effect/run-service.ts index 13104c88b..3de82e0d1 100644 --- a/packages/opencode/src/effect/run-service.ts +++ b/packages/opencode/src/effect/run-service.ts @@ -38,7 +38,7 @@ export function attach<A, E, R>(effect: Effect.Effect<A, E, R>): Effect.Effect<A export function makeRuntime<I, S, E>(service: Context.Service<I, S>, layer: Layer.Layer<I, E>) { let rt: ManagedRuntime.ManagedRuntime<I, E> | undefined - const getRuntime = () => (rt ??= ManagedRuntime.make(Layer.merge(layer, Observability.layer), { memoMap })) + const getRuntime = () => (rt ??= ManagedRuntime.make(Layer.provideMerge(layer, Observability.layer), { memoMap })) return { runSync: <A, Err>(fn: (svc: S) => Effect.Effect<A, Err, I>) => getRuntime().runSync(attach(service.use(fn))), diff --git a/packages/opencode/src/server/instance/config.ts b/packages/opencode/src/server/instance/config.ts index 41d5872c9..aa770726d 100644 --- a/packages/opencode/src/server/instance/config.ts +++ b/packages/opencode/src/server/instance/config.ts @@ -5,12 +5,10 @@ import { Config } from "../../config/config" import { Provider } from "../../provider/provider" import { mapValues } from "remeda" import { errors } from "../error" -import { Log } from "../../util/log" import { lazy } from "../../util/lazy" import { AppRuntime } from "../../effect/app-runtime" import { Effect } from "effect" - -const log = Log.create({ service: "server" }) +import { jsonRequest } from "./trace" export const ConfigRoutes = lazy(() => new Hono() @@ -31,9 +29,11 @@ export const ConfigRoutes = lazy(() => }, }, }), - async (c) => { - return c.json(await AppRuntime.runPromise(Config.Service.use((cfg) => cfg.get()))) - }, + async (c) => + jsonRequest("ConfigRoutes.get", c, function* () { + const cfg = yield* Config.Service + return yield* cfg.get() + }), ) .patch( "/", @@ -82,18 +82,14 @@ export const ConfigRoutes = lazy(() => }, }, }), - async (c) => { - using _ = log.time("providers") - const providers = await AppRuntime.runPromise( - Effect.gen(function* () { - const svc = yield* Provider.Service - return mapValues(yield* svc.list(), (item) => item) - }), - ) - return c.json({ - providers: Object.values(providers), - default: mapValues(providers, (item) => Provider.sort(Object.values(item.models))[0].id), - }) - }, + async (c) => + jsonRequest("ConfigRoutes.providers", c, function* () { + const svc = yield* Provider.Service + const providers = mapValues(yield* svc.list(), (item) => item) + return { + providers: Object.values(providers), + default: mapValues(providers, (item) => Provider.sort(Object.values(item.models))[0].id), + } + }), ), ) diff --git a/packages/opencode/src/server/instance/session.ts b/packages/opencode/src/server/instance/session.ts index 4f02e35fa..0bce3085e 100644 --- a/packages/opencode/src/server/instance/session.ts +++ b/packages/opencode/src/server/instance/session.ts @@ -26,6 +26,7 @@ import { errors } from "../error" import { lazy } from "../../util/lazy" import { Bus } from "../../bus" import { NamedError } from "@opencode-ai/shared/util/error" +import { jsonRequest } from "./trace" const log = Log.create({ service: "server" }) @@ -94,10 +95,11 @@ export const SessionRoutes = lazy(() => ...errors(400), }, }), - async (c) => { - const result = await AppRuntime.runPromise(SessionStatus.Service.use((svc) => svc.list())) - return c.json(Object.fromEntries(result)) - }, + async (c) => + jsonRequest("SessionRoutes.status", c, function* () { + const svc = yield* SessionStatus.Service + return Object.fromEntries(yield* svc.list()) + }), ) .get( "/:sessionID", @@ -126,8 +128,10 @@ export const SessionRoutes = lazy(() => ), async (c) => { const sessionID = c.req.valid("param").sessionID - const session = await AppRuntime.runPromise(Session.Service.use((svc) => svc.get(sessionID))) - return c.json(session) + return jsonRequest("SessionRoutes.get", c, function* () { + const session = yield* Session.Service + return yield* session.get(sessionID) + }) }, ) .get( @@ -157,8 +161,10 @@ export const SessionRoutes = lazy(() => ), async (c) => { const sessionID = c.req.valid("param").sessionID - const session = await AppRuntime.runPromise(Session.Service.use((svc) => svc.children(sessionID))) - return c.json(session) + return jsonRequest("SessionRoutes.children", c, function* () { + const session = yield* Session.Service + return yield* session.children(sessionID) + }) }, ) .get( @@ -187,8 +193,10 @@ export const SessionRoutes = lazy(() => ), async (c) => { const sessionID = c.req.valid("param").sessionID - const todos = await AppRuntime.runPromise(Todo.Service.use((svc) => svc.get(sessionID))) - return c.json(todos) + return jsonRequest("SessionRoutes.todo", c, function* () { + const todo = yield* Todo.Service + return yield* todo.get(sessionID) + }) }, ) .post( diff --git a/packages/opencode/src/server/instance/trace.ts b/packages/opencode/src/server/instance/trace.ts new file mode 100644 index 000000000..b3adbb4c8 --- /dev/null +++ b/packages/opencode/src/server/instance/trace.ts @@ -0,0 +1,33 @@ +import type { Context } from "hono" +import { Effect } from "effect" +import { AppRuntime } from "../../effect/app-runtime" + +type AppEnv = Parameters<typeof AppRuntime.runPromise>[0] extends Effect.Effect<any, any, infer R> ? R : never + +export function runRequest<A, E>(name: string, c: Context, effect: Effect.Effect<A, E, AppEnv>) { + const url = new URL(c.req.url) + return AppRuntime.runPromise( + effect.pipe( + Effect.withSpan(name, { + attributes: { + "http.method": c.req.method, + "http.path": url.pathname, + }, + }), + ), + ) +} + +export async function jsonRequest<C extends Context, A, E>( + name: string, + c: C, + effect: (c: C) => Effect.gen.Return<A, E, AppEnv>, +) { + return c.json( + await runRequest( + name, + c, + Effect.gen(() => effect(c)), + ), + ) +} |
