feat(tui): add structured logging

This commit is contained in:
Dax Raad 2026-07-08 15:59:49 -04:00
commit cedf365674
9 changed files with 208 additions and 119 deletions

View file

@ -0,0 +1,24 @@
import { createContext, useContext, type ParentProps } from "solid-js"
export type LogLevel = "debug" | "info" | "warn" | "error"
export type LogTags = Readonly<Record<string, unknown>>
export type LogSink = (level: LogLevel, message: string, tags: LogTags) => void
const LogContext = createContext<LogSink>()
export function LogProvider(props: ParentProps<{ log: LogSink }>) {
return <LogContext.Provider value={props.log}>{props.children}</LogContext.Provider>
}
export function useLog(tags: LogTags = {}) {
const sink = useContext(LogContext)
if (!sink) throw new Error("Log context must be used within a LogProvider")
const write = (level: LogLevel, message: string, extra: LogTags = {}) => sink(level, message, { ...tags, ...extra })
return {
debug: (message: string, extra?: LogTags) => write("debug", message, extra),
info: (message: string, extra?: LogTags) => write("info", message, extra),
warn: (message: string, extra?: LogTags) => write("warn", message, extra),
error: (message: string, extra?: LogTags) => write("error", message, extra),
}
}

View file

@ -4,6 +4,7 @@ import { createGlobalEmitter } from "@solid-primitives/event-bus"
import { onCleanup, onMount } from "solid-js"
import { createStore } from "solid-js/store"
import { createSimpleContext } from "./helper"
import { useLog } from "./log"
export type SDKConnectionStatus = "connected" | "connecting" | "reconnecting"
@ -19,6 +20,7 @@ export const { use: useSDK, provider: SDKProvider } = createSimpleContext({
// Stops and starts the managed service; present only in service mode.
reload?: () => Promise<void>
}) => {
const log = useLog()
const abort = new AbortController()
let client = props.client
let api = props.api
@ -64,7 +66,8 @@ export const { use: useSDK, provider: SDKProvider } = createSimpleContext({
return connection.signal.reason instanceof Error
? connection.signal.reason
: new Error("Event stream disconnected")
if (first.value.type !== "server.connected") return new Error("Event stream did not start with server.connected")
if (first.value.type !== "server.connected")
return new Error("Event stream did not start with server.connected")
clearTimeout(timeout)
attempt = 0
events.emit(first.value.type, first.value)
@ -74,6 +77,12 @@ export const { use: useSDK, provider: SDKProvider } = createSimpleContext({
const event = await iterator.next()
if (abort.signal.aborted || controller.signal.aborted) return
if (event.done) return new Error("Event stream disconnected")
if ("durable" in event.value)
log.info("event", {
type: event.value.type,
aggregateID: event.value.durable.aggregateID,
seq: event.value.durable.seq,
})
events.emit(event.value.type, event.value)
}
})()