feat(opencode): improve telemetry tracing and request spans (#22653)

This commit is contained in:
Kit Langton
2026-04-15 17:32:56 -04:00
committed by GitHub
parent 3b75f16119
commit 6bed7d469d
5 changed files with 68 additions and 32 deletions
+1 -2
View File
@@ -49,7 +49,6 @@ import { ShareNext } from "@/share/share-next"
import { SessionShare } from "@/share/session" import { SessionShare } from "@/share/session"
export const AppLayer = Layer.mergeAll( export const AppLayer = Layer.mergeAll(
Observability.layer,
AppFileSystem.defaultLayer, AppFileSystem.defaultLayer,
Bus.defaultLayer, Bus.defaultLayer,
Auth.defaultLayer, Auth.defaultLayer,
@@ -95,7 +94,7 @@ export const AppLayer = Layer.mergeAll(
Installation.defaultLayer, Installation.defaultLayer,
ShareNext.defaultLayer, ShareNext.defaultLayer,
SessionShare.defaultLayer, SessionShare.defaultLayer,
) ).pipe(Layer.provideMerge(Observability.layer))
const rt = ManagedRuntime.make(AppLayer, { memoMap }) const rt = ManagedRuntime.make(AppLayer, { memoMap })
type Runtime = Pick<typeof rt, "runSync" | "runPromise" | "runPromiseExit" | "runFork" | "runCallback" | "dispose"> type Runtime = Pick<typeof rt, "runSync" | "runPromise" | "runPromiseExit" | "runFork" | "runCallback" | "dispose">
+1 -1
View File
@@ -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>) { export function makeRuntime<I, S, E>(service: Context.Service<I, S>, layer: Layer.Layer<I, E>) {
let rt: ManagedRuntime.ManagedRuntime<I, E> | undefined 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 { return {
runSync: <A, Err>(fn: (svc: S) => Effect.Effect<A, Err, I>) => getRuntime().runSync(attach(service.use(fn))), runSync: <A, Err>(fn: (svc: S) => Effect.Effect<A, Err, I>) => getRuntime().runSync(attach(service.use(fn))),
+15 -19
View File
@@ -5,12 +5,10 @@ import { Config } from "../../config/config"
import { Provider } from "../../provider/provider" import { Provider } from "../../provider/provider"
import { mapValues } from "remeda" import { mapValues } from "remeda"
import { errors } from "../error" import { errors } from "../error"
import { Log } from "../../util/log"
import { lazy } from "../../util/lazy" import { lazy } from "../../util/lazy"
import { AppRuntime } from "../../effect/app-runtime" import { AppRuntime } from "../../effect/app-runtime"
import { Effect } from "effect" import { Effect } from "effect"
import { jsonRequest } from "./trace"
const log = Log.create({ service: "server" })
export const ConfigRoutes = lazy(() => export const ConfigRoutes = lazy(() =>
new Hono() new Hono()
@@ -31,9 +29,11 @@ export const ConfigRoutes = lazy(() =>
}, },
}, },
}), }),
async (c) => { async (c) =>
return c.json(await AppRuntime.runPromise(Config.Service.use((cfg) => cfg.get()))) jsonRequest("ConfigRoutes.get", c, function* () {
}, const cfg = yield* Config.Service
return yield* cfg.get()
}),
) )
.patch( .patch(
"/", "/",
@@ -82,18 +82,14 @@ export const ConfigRoutes = lazy(() =>
}, },
}, },
}), }),
async (c) => { async (c) =>
using _ = log.time("providers") jsonRequest("ConfigRoutes.providers", c, function* () {
const providers = await AppRuntime.runPromise( const svc = yield* Provider.Service
Effect.gen(function* () { const providers = mapValues(yield* svc.list(), (item) => item)
const svc = yield* Provider.Service return {
return mapValues(yield* svc.list(), (item) => item) providers: Object.values(providers),
}), default: mapValues(providers, (item) => Provider.sort(Object.values(item.models))[0].id),
) }
return c.json({ }),
providers: Object.values(providers),
default: mapValues(providers, (item) => Provider.sort(Object.values(item.models))[0].id),
})
},
), ),
) )
@@ -26,6 +26,7 @@ import { errors } from "../error"
import { lazy } from "../../util/lazy" import { lazy } from "../../util/lazy"
import { Bus } from "../../bus" import { Bus } from "../../bus"
import { NamedError } from "@opencode-ai/shared/util/error" import { NamedError } from "@opencode-ai/shared/util/error"
import { jsonRequest } from "./trace"
const log = Log.create({ service: "server" }) const log = Log.create({ service: "server" })
@@ -94,10 +95,11 @@ export const SessionRoutes = lazy(() =>
...errors(400), ...errors(400),
}, },
}), }),
async (c) => { async (c) =>
const result = await AppRuntime.runPromise(SessionStatus.Service.use((svc) => svc.list())) jsonRequest("SessionRoutes.status", c, function* () {
return c.json(Object.fromEntries(result)) const svc = yield* SessionStatus.Service
}, return Object.fromEntries(yield* svc.list())
}),
) )
.get( .get(
"/:sessionID", "/:sessionID",
@@ -126,8 +128,10 @@ export const SessionRoutes = lazy(() =>
), ),
async (c) => { async (c) => {
const sessionID = c.req.valid("param").sessionID const sessionID = c.req.valid("param").sessionID
const session = await AppRuntime.runPromise(Session.Service.use((svc) => svc.get(sessionID))) return jsonRequest("SessionRoutes.get", c, function* () {
return c.json(session) const session = yield* Session.Service
return yield* session.get(sessionID)
})
}, },
) )
.get( .get(
@@ -157,8 +161,10 @@ export const SessionRoutes = lazy(() =>
), ),
async (c) => { async (c) => {
const sessionID = c.req.valid("param").sessionID const sessionID = c.req.valid("param").sessionID
const session = await AppRuntime.runPromise(Session.Service.use((svc) => svc.children(sessionID))) return jsonRequest("SessionRoutes.children", c, function* () {
return c.json(session) const session = yield* Session.Service
return yield* session.children(sessionID)
})
}, },
) )
.get( .get(
@@ -187,8 +193,10 @@ export const SessionRoutes = lazy(() =>
), ),
async (c) => { async (c) => {
const sessionID = c.req.valid("param").sessionID const sessionID = c.req.valid("param").sessionID
const todos = await AppRuntime.runPromise(Todo.Service.use((svc) => svc.get(sessionID))) return jsonRequest("SessionRoutes.todo", c, function* () {
return c.json(todos) const todo = yield* Todo.Service
return yield* todo.get(sessionID)
})
}, },
) )
.post( .post(
@@ -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)),
),
)
}