Tracer API
The Tracer provides distributed tracing capabilities with span-based instrumentation, ideal for tracking execution flow across agents and capturing LLM request/response details.
Tracer Class
The Tracer manages trace context and creates spans for instrumentation.
class Tracer {
constructor ( traceId ?: string );
startSpan ( name : string , opts ?: { parent ?: Span ; taskId ?: string ; agentId ?: string }) : Span ;
propagationContext ( span : Span ) : { traceId : string ; parentSpanId : string };
getTraceId () : string ;
static fromPropagated ( ctx : { traceId : string ; parentSpanId : string }) : Tracer ;
}
Constructor
Optional trace ID. If not provided, a new UUID will be generated
Methods
startSpan
Create and start a new span.
startSpan (
name : string ,
opts ?: { parent? : Span ; taskId ?: string ; agentId ?: string }
): Span
Name of the span (e.g., “execute-task”, “llm-request”)
Parent span for creating child spans
Task ID to associate with this span
Agent ID to associate with this span
Returns: A new Span instance that automatically emits a “begin” event.
Example:
const tracer = createTracer ();
const span = tracer . startSpan ( "execute-task" , {
taskId: "task-123" ,
agentId: "worker-1"
});
propagationContext
Serialize trace context for passing to child processes or remote agents.
propagationContext ( span : Span ): { traceId: string ; parentSpanId : string }
Span to serialize context from
Returns: Object containing traceId and parentSpanId for propagation.
Example:
const ctx = tracer . propagationContext ( span );
// Send ctx to child process or remote agent
getTraceId
Get the trace ID for this tracer.
Returns: The trace ID (UUID format).
fromPropagated (static)
Recreate a Tracer from a propagated context (e.g., from a parent process).
static fromPropagated ( ctx : { traceId: string ; parentSpanId : string }): Tracer
Trace ID from parent context
Parent span ID from parent context
Returns: A new Tracer with the propagated trace ID.
Example:
// In child process:
const tracer = Tracer . fromPropagated ({
traceId: parentCtx . traceId ,
parentSpanId: parentCtx . parentSpanId
});
Span Class
Represents a single unit of work being traced.
class Span {
readonly spanId : string ;
event ( name : string , attrs ?: Record < string , string | number | boolean >) : void ;
setStatus ( status : "ok" | "error" , message ?: string ) : void ;
setAttribute ( key : string , value : string | number | boolean ) : void ;
setAttributes ( attrs : Record < string , string | number | boolean >) : void ;
child ( name : string , overrides ?: { taskId ?: string ; agentId ?: string }) : Span ;
end () : void ;
context () : TraceContext ;
}
Properties
Unique identifier for this span (16-character hex string)
Methods
event
Emit an instant event within the span.
event ( name : string , attrs ?: Record < string , string | number | boolean > ): void
attrs
Record<string, string | number | boolean>
Optional attributes to attach to the event
Example:
span . event ( "checkpoint-reached" , { step: 3 , progress: 0.75 });
setStatus
Set the final status of the span.
setStatus ( status : "ok" | "error" , message ?: string ): void
Span status: “ok” or “error”
Optional status message (typically used for errors)
Example:
span . setStatus ( "error" , "Task execution failed" );
span . end ();
setAttribute
Set a single attribute on the span.
setAttribute ( key : string , value : string | number | boolean ): void
value
string | number | boolean
required
Attribute value
Example:
span . setAttribute ( "http.status_code" , 200 );
span . setAttribute ( "http.method" , "POST" );
setAttributes
Set multiple attributes at once.
setAttributes ( attrs : Record < string , string | number | boolean > ): void
attrs
Record<string, string | number | boolean>
required
Object containing key-value pairs to set as attributes
Example:
span . setAttributes ({
"http.status_code" : 200 ,
"http.method" : "POST" ,
"response.size" : 1024
});
child
Create a child span parented to this span.
child ( name : string , overrides ?: { taskId? : string ; agentId ?: string }): Span
Override task ID (inherits from parent if not specified)
Override agent ID (inherits from parent if not specified)
Returns: A new child Span.
Example:
const parentSpan = tracer . startSpan ( "process-task" );
const childSpan = parentSpan . child ( "read-file" );
// Do work...
childSpan . end ();
parentSpan . end ();
end
End the span and emit the final “end” event with computed duration.
Always call end() when the span’s work is complete. This method is idempotent—subsequent calls will emit a warning but won’t error.
Example:
const span = tracer . startSpan ( "operation" );
try {
// Do work...
span . setStatus ( "ok" );
} catch ( err ) {
span . setStatus ( "error" , String ( err ));
} finally {
span . end ();
}
context
Get the trace context for this span.
Returns: TraceContext object containing traceId, spanId, and parentSpanId.
Functions
createTracer
Factory function to create a new Tracer instance.
function createTracer ( traceId ?: string ) : Tracer
Optional trace ID. If not provided, a new UUID will be generated
Returns: A new Tracer instance.
Example:
import { createTracer } from "@longshot/core" ;
const tracer = createTracer ();
const span = tracer . startSpan ( "main-operation" );
enableTracing
Enable trace file output. Creates timestamped NDJSON files for traces and LLM details in <projectRoot>/logs/.
function enableTracing ( projectRoot : string ) : { traceFile : string ; llmDetailFile : string }
Absolute path to the project root directory
Returns: Object containing paths to both trace and LLM detail files.
Example:
import { enableTracing } from "@longshot/core" ;
const { traceFile , llmDetailFile } = enableTracing ( "/path/to/project" );
console . log ( `Traces: ${ traceFile } ` );
console . log ( `LLM Details: ${ llmDetailFile } ` );
// Output:
// Traces: /path/to/project/logs/trace-2026-03-03T10-30-45.ndjson
// LLM Details: /path/to/project/logs/llm-detail-2026-03-03T10-30-45.ndjson
Call this function once at startup. Subsequent calls are no-ops and return the existing file paths.
closeTracing
Close trace file streams. Call on graceful shutdown.
function closeTracing () : void
Example:
import { closeTracing } from "@longshot/core" ;
process . on ( "SIGTERM" , () => {
closeTracing ();
process . exit ( 0 );
});
writeLLMDetail
Write full LLM request/response detail to the LLM detail log, correlated with a span.
function writeLLMDetail (
spanId : string ,
data : { messages : unknown []; response ?: unknown ; error ?: string }
) : void
Span ID to correlate with this LLM detail entry
Array of messages sent to the LLM
Error message if the request failed
Example:
import { writeLLMDetail } from "@longshot/core" ;
const span = tracer . startSpan ( "llm-request" );
try {
const messages = [{ role: "user" , content: "Hello" }];
const response = await callLLM ( messages );
writeLLMDetail ( span . spanId , { messages , response });
span . setStatus ( "ok" );
} catch ( err ) {
writeLLMDetail ( span . spanId , { messages , error: String ( err ) });
span . setStatus ( "error" );
} finally {
span . end ();
}
Types
TraceContext
interface TraceContext {
traceId : string ;
spanId : string ;
parentSpanId ?: string ;
}
SpanEvent
interface SpanEvent {
timestamp : number ;
trace : TraceContext ;
spanName : string ;
spanKind : "begin" | "end" | "event" ;
spanStatus ?: "ok" | "error" ;
durationMs ?: number ;
attributes ?: Record < string , string | number | boolean >;
taskId ?: string ;
agentId ?: string ;
}
LLMDetailEntry
interface LLMDetailEntry {
timestamp : number ;
spanId : string ;
messages : unknown [];
response ?: unknown ;
error ?: string ;
}
Span events are written as NDJSON:
{ "timestamp" : 1709467845000 , "trace" :{ "traceId" : "550e8400-e29b-41d4-a716-446655440000" , "spanId" : "a1b2c3d4e5f6g7h8" }, "spanName" : "execute-task" , "spanKind" : "begin" , "taskId" : "task-123" , "agentId" : "worker-1" }
{ "timestamp" : 1709467850000 , "trace" :{ "traceId" : "550e8400-e29b-41d4-a716-446655440000" , "spanId" : "a1b2c3d4e5f6g7h8" }, "spanName" : "execute-task" , "spanKind" : "end" , "spanStatus" : "ok" , "durationMs" : 5000 , "taskId" : "task-123" , "agentId" : "worker-1" }
{ "timestamp" : 1709467845000 , "spanId" : "a1b2c3d4e5f6g7h8" , "messages" :[{ "role" : "user" , "content" : "Hello" }], "response" :{ "role" : "assistant" , "content" : "Hi there!" }}
Complete Example
import { createTracer , enableTracing , closeTracing , writeLLMDetail } from "@longshot/core" ;
// Initialize tracing at startup
const { traceFile , llmDetailFile } = enableTracing ( "/path/to/project" );
console . log ( `Tracing to: ${ traceFile } ` );
// Create a tracer
const tracer = createTracer ();
// Start a parent span
const parentSpan = tracer . startSpan ( "process-task" , {
taskId: "task-123" ,
agentId: "worker-1"
});
parentSpan . setAttribute ( "task.priority" , 1 );
try {
// Create child span for file reading
const readSpan = parentSpan . child ( "read-files" );
readSpan . setAttribute ( "file.count" , 3 );
// Do work...
readSpan . setStatus ( "ok" );
readSpan . end ();
// Create child span for LLM request
const llmSpan = parentSpan . child ( "llm-request" );
const messages = [{ role: "user" , content: "Analyze this code" }];
try {
const response = await callLLM ( messages );
writeLLMDetail ( llmSpan . spanId , { messages , response });
llmSpan . setStatus ( "ok" );
} catch ( err ) {
writeLLMDetail ( llmSpan . spanId , { messages , error: String ( err ) });
llmSpan . setStatus ( "error" , String ( err ));
} finally {
llmSpan . end ();
}
parentSpan . event ( "task-checkpoint" , { step: 2 });
parentSpan . setStatus ( "ok" );
} catch ( err ) {
parentSpan . setStatus ( "error" , String ( err ));
} finally {
parentSpan . end ();
}
// Cleanup on shutdown
process . on ( "SIGTERM" , () => {
closeTracing ();
process . exit ( 0 );
});
Best Practices
Always End Spans Always call span.end() when work is complete, even in error cases. Use try-finally blocks to ensure cleanup.
Use Child Spans Create child spans for nested operations to build a hierarchical trace that shows the full execution flow.
Capture LLM Details Use writeLLMDetail() to capture full request/response data for debugging and analysis, separate from the main trace file.
Set Meaningful Attributes Add attributes to spans to provide context. Use consistent naming (e.g., http.status_code, file.path).
Propagate Context When spawning child processes or remote agents, use propagationContext() and fromPropagated() to maintain trace continuity.