Trace
Trace one function, with no engine involved.
@trace reports each completed method call to a callback while preserving the method's normal return value. executionTrace does the same work for a plain function and returns the trace record, or a promise of it.
No graph here
This path records calls individually. It does not track order, nesting or parallelism, and produces no nodes or edges. For that, route calls through an engine instead — see the engine Trace guide.
Usage
@trace decorator
import { trace } from 'execution-engine';
class MathOperations {
@trace(console.log)
add(a: number, b: number): number {
return a + b;
}
}
const mathOps = new MathOperations();
console.log(mathOps.add(2, 3)); // 5The decorated method still returns its own value. Every call additionally invokes the callback with a TraceContext describing what happened.
executionTrace function
For code without classes, call the underlying function directly:
import { executionTrace } from 'execution-engine';
const result = executionTrace(
(a: number, b: number) => a + b,
[2, 3],
(ctx) => console.log(ctx.duration, ctx.outputs)
);
console.log(result.outputs); // 5Unlike the decorator, this returns the whole trace object, not just the output.
Reading the trace context inside the function
By default, the function receives only the arguments you pass. Set injectContextInArgs to append the in-progress trace context. contextKey is optional; it stores that in-progress context on this. This decorator example uses both so its class and method metadata are available inside the call:
import { trace, TraceContext } from 'execution-engine';
class Service {
@trace(console.log, {}, { contextKey: 'traceContext', injectContextInArgs: true })
process(payload: string, ctx?: TraceContext<string>) {
console.log(ctx?.metadata.method); // "process"
return payload.toUpperCase();
}
}Changed in 4.0.0
injectContextInArgs defaults to false for both @trace and executionTrace. Before 4.0.0 the context was always appended. See Migration.
The injected object contains the data known at call time. outputs, errors and final timing are added afterwards; fields you add while the function runs are preserved in the completed trace.
Attaching your own metadata
additionalContext adds your own top-level fields to every trace from the method. Use it for tags such as a domain, owner or feature flag:
class Service {
@trace(sendToLogger, { domain: 'billing', critical: true })
chargeCard(amount: number) {
/* … */
}
}API
trace(onTraceEvent, additionalContext?, options?)
A method decorator that wraps the original method with execution tracing.
| Parameter | Type | Description |
|---|---|---|
onTraceEvent | (traceContext: TraceContext<O>) => void | Called with the trace context after execution. Required. |
additionalContext | Record<string, any> | Extra fields merged into every trace context. Defaults to {}. |
options.contextKey | string | Property name under which the trace context is stored on the instance (this). |
options.errorStrategy | 'catch' | 'throw' | How thrown errors are handled. Defaults to 'throw'. |
options.injectContextInArgs | boolean | Append the trace context as a trailing argument. Defaults to false. |
errorStrategy: 'catch' changes the return value
With 'throw' (the default), failures are recorded and then re-thrown. With 'catch', executionTrace returns a trace containing errors; @trace suppresses the exception and no longer preserves the method's normal return contract. Use 'catch' only when callers do not expect the successful return type.
executionTrace(blockFunction, inputs?, onTraceEvent?, options?)
The function behind @trace. Handles both synchronous and asynchronous blockFunctions.
| Parameter | Type | Description |
|---|---|---|
blockFunction | (...params: unknown[]) => O | Promise<O> | The function to execute and trace. |
inputs | Array<unknown> | Arguments passed to blockFunction. Defaults to []. |
onTraceEvent | (traceContext: TraceContext<O>) => void | Optional callback fired after execution. |
options | same as above | contextKey, errorStrategy, injectContextInArgs. |
Returns an ExecutionTrace if blockFunction is synchronous, or a Promise<ExecutionTrace> if it is asynchronous.
TraceContext
The object passed to onTraceEvent. It extends ExecutionTrace with function metadata:
interface TraceContext<O> extends ExecutionTrace<Array<unknown>, O> {
metadata: FunctionMetadata;
[key: string]: unknown;
}metadata is a FunctionMetadata record: name, class, method, methodSignature, parameters, isAsync and isBound.
Remarks
- Timing is measured with
performance.now()viaExecutionTimer, andelapsedTimeis reported to three decimal places. - Errors are normalized before being stored, so non-
Errorthrows (strings or objects) still serialize cleanly. onTraceEventruns inline after the call. If the callback throws, that error reaches the caller.- When the context is injected, fields added during the call remain on the final record. Completion fields such as
outputs,errors,endTimeanddurationare populated after the function settles.
See also
- TraceableEngine — builds a full node/edge execution graph on top of
executionTrace. - ExecutionEngine — adds a shared context on top of
TraceableEngine. - Which API to use — when to prefer this over the engine.