@somnia-chain/markets-sdk / index / DebugEvent
Type Alias: DebugEvent
DebugEvent = {
kind:"log";level:"debug"|"warn";scope:string;message:string;data?:Record<string,unknown>; } | {kind:"span";phase:"start";id:number;parentId?:number;name:string;data?:Record<string,unknown>; } | {kind:"span";phase:"annotate";id:number;name:string;data:Record<string,unknown>; } | {kind:"span";phase:"end";id:number;name:string;durationMs:number;error?:unknown; }
Defined in: packages/sdk/src/debug.ts:58
One event on the client's opt-in debug channel — either a structured log line or one phase of a span. Wire a sink with ClientConfig.debug and every event the client produces flows through it.
Details
Events are data, not display strings: data carries raw values (counts,
addresses, bigints) and rendering/filtering is entirely the sink's job —
see consoleDebugSink for a ready-made renderer and
debugCollector for test capture. A span arrives as a start/end
pair sharing an id (unique within one client instance), with any number
of annotate events in between attaching data to the still-open span.
The shape maps 1:1 onto OpenTelemetry, so a real tracer is just another
sink: name ↔ span name, data ↔ attributes, error ↔ span status /
recorded exception, annotate ↔ setAttribute, parentId ↔ context
link.
Gotchas
Parenting is EXPLICIT — a span event carries parentId only when the call
site passed the parent handle — so interleaved events from concurrent
operations always attribute correctly; never infer nesting from event order.
Union Members
Type Literal
{ kind: "log"; level: "debug" | "warn"; scope: string; message: string; data?: Record<string, unknown>; }
kind
kind:
"log"
level
level:
"debug"|"warn"
"warn" for conditions worth surfacing (a failed watch); "debug" for tracing.
scope
scope:
string
Emitting module, e.g. "liveTail" — filter on it in the sink.
message
message:
string
Stable, human-readable event description, e.g. "applying logs".
data?
optionaldata?:Record<string,unknown>
Raw values for the sink to render (counts, block numbers, addresses, bigints).
Type Literal
{ kind: "span"; phase: "start"; id: number; parentId?: number; name: string; data?: Record<string, unknown>; }
kind
kind:
"span"
phase
phase:
"start"
id
id:
number
Span id — matches the annotate/end events of the same span. Unique per client.
parentId?
optionalparentId?:number
The enclosing span's id; absent on a root span. Only ever set explicitly.
name
name:
string
Span name, "<module>.<fn>" — e.g. "trade.execute", "trader.placeOrder".
data?
optionaldata?:Record<string,unknown>
The operation's input, as raw values (a trader call's params object, …).
Type Literal
{ kind: "span"; phase: "annotate"; id: number; name: string; data: Record<string, unknown>; }
kind
kind:
"span"
phase
phase:
"annotate"
id
id:
number
The still-open span this data belongs to.
name
name:
string
The annotated span's name (so sinks need no id → name lookup).
data
data:
Record<string,unknown>
Values that only exist mid-span — e.g. the tx hash once broadcast returns.
Type Literal
{ kind: "span"; phase: "end"; id: number; name: string; durationMs: number; error?: unknown; }
kind
kind:
"span"
phase
phase:
"end"
id
id:
number
Matches the span's start event.
name
name:
string
Same name as the start event.
durationMs
durationMs:
number
Wall-clock start-to-settle: for an async span, until the promise settles.
error?
optionalerror?:unknown
The thrown value / rejection reason when the span failed; absent on success.
Example
A minimal custom sink — narrow on kind/phase and the union does the rest:
const sink = (e: DebugEvent): void => {
if (e.kind === "log") console.log(e.scope, e.message, e.data);
else if (e.phase === "end" && e.error !== undefined) console.error(e.name, e.error);
else if (e.phase === "end" && e.durationMs > 500) console.log("slow:", e.name, e.durationMs);
};
const exchange = new SomniaMarkets({ ...config, debug: sink });