import { Trace } from "../models/trace.model"; import { Span } from "../models/span.model"; import { TracingManagerInterface } from "../interfaces/tracing-manager.interface"; import { TracingContext } from "@pristine-ts/common"; import { TracerInterface } from "../interfaces/tracer.interface"; import { LogHandlerInterface } from "@pristine-ts/logging"; /** * The Tracing Manager provides methods to help with tracing. * It is tagged and can be injected using TracingManagerInterface which facilitates mocking. * It is module scoped to the TelemetryModuleKeyname. * * **Where the active `Trace` lives.** The active trace is stored on `EventContext.trace`, * propagated via `AsyncLocalStorage`. Every `TracingManager` instance — whether resolved * from the root container (kernel boot) or from a per-event child container — reads and * writes spans through the same `EventContext.trace` reference, so a span started in the * kernel and an event added in a controller belong to the same trace tree. * * **Fallback `this.trace`.** During kernel boot (`Kernel.start()` and friends), there is * no `EventContext` yet — the framework hasn't started handling an event. In that window * the manager falls back to `this.trace`. This is the only time `this.trace` is touched. * * **Lifecycle: container-scoped, not singleton.** Each per-event DI child container gets * its own `TracingManager` instance. The per-instance `this.trace` fallback is what keeps * parallel events isolated *if* tracing is somehow started outside an EventContext. * Resolving `TracingManager` from the root container returns the root instance (used for * kernel-initialization spans); resolving from a child container returns the per-event * instance — both will agree on what trace is active inside an event because they read * from EventContext. */ export declare class TracingManager implements TracingManagerInterface { private readonly tracers; private readonly loghandler; private readonly isActive; private readonly debug; private readonly tracingContext; /** * Fallback trace used only during kernel boot when no `EventContext` is active. * Inside an event, the active trace lives on `EventContext.trace` instead. */ trace?: Trace; /** * The Tracing Manager provides methods to help with tracing. * It is tagged and can be injected using TracingManagerInterface which facilitates mocking. * It is module scoped to the TelemetryModuleKeyname. * @param tracers The tracers to use. All services tagged with ServiceDefinitionTagEnum.Tracer will be injected here. * @param loghandler The log handler to output logs. * @param isActive Whether or not tracing is activated. * @param debug Whether or not tracing is in debug mode, meaning that it should output logs with the debug severity about the trace and spans. * This can be set to false to prevent having to much logs for every single span created. * @param tracingContext The tracing context. */ constructor(tracers: TracerInterface[], loghandler: LogHandlerInterface, isActive: boolean, debug: boolean, tracingContext: TracingContext); /** * Returns the currently active trace from the EventContext, falling back to the * per-instance `this.trace` when no EventContext is active (kernel boot). */ private getActiveTrace; /** * Merges the given entries into the active trace's `context` — the place tracers read * trace-wide metadata from (e.g. the observability store's `requests` listing reads * `http.method`/`http.path`/`http.statusCode` from here). A no-op when there is no * active trace. Existing entries with the same keys are overwritten. * * This is the typed mutator for trace context: consumers don't reach for the trace * object themselves, so the trace's lifecycle stays owned by `TracingManager`. */ addToTraceContext(entries: { [key: string]: string; }): void; /** * Stores `trace` as the active trace — on `EventContext.trace` when an event is active, * otherwise on the instance fallback `this.trace`. */ private setActiveTrace; /** * This methods starts the Tracing. This should be the first method called before doing anything else. * @param spanRootKeyname The keyname of the span at the root. * @param traceId The trace id if there is one. * @param context The context if there is one. */ startTracing(spanRootKeyname?: string, traceId?: string, context?: { [key: string]: string; }): Span; /** * Makes the active trace part of a trace a caller started (for example, from an incoming * `traceparent` header): the active trace takes `traceId`, and so do the logs written * after this call. A no-op when there is no active trace. * * The trace keeps its spans and start date; only its id changes. Tracers that act on * `traceEndedStream` read the caller's id. Logs written before this call keep the old id. * @param traceId The caller's trace id. */ continueTrace(traceId: string): void; /** * This method starts a new span. * @param keyname The keyname for this new span. * @param parentKeyname The keyname of the parent span. * @param parentId The id of the parent span. * @param context The context if there is one. */ startSpan(keyname: string, parentKeyname?: string, parentId?: string, context?: { [key: string]: string; }): Span; /** * This methods adds an already created Span to the trace. It assumes that it its hierarchy is correct. * @param span The span to add. */ addSpan(span: Span): Span; /** * This method ends the span using a keyname. * @param keyname The keyname of the span to end. */ endSpanKeyname(keyname: string): void; /** * This methods ends the span by setting the end date and by calling the tracers. * It will also end the trace if the rootspan is being ended. * @param span The span to end. */ endSpan(span: Span): void; /** * This method ends the trace entirely. */ endTrace(): void; /** * Attaches a named, timestamped marker to the most-recently-started in-progress span. * Use for noteworthy moments that don't warrant a child span — "validation passed", * "found 50 rows", "rate limit ok". Cheap (just pushes onto an array); shows up in * the trace rendered by tracers (ConsoleTracer, the observability tracer, X-Ray, etc.). * * If no span is currently active (no trace started, or every span has already ended), * a warning is logged and the marker is dropped. The warning is the explicit signal * that "this marker call had nowhere to go" — usually the sign of a missing * `startTracing()` call earlier in the flow. */ addMarkerToCurrentSpan(message: string, attributes?: { [key: string]: string; }): void; /** * Returns the active trace's spans + their markers as a flat, timestamp-sorted list of * `{kind, name, date, attributes}` entries. Public utility for custom tracers, debug * endpoints, test helpers, or anyone who wants "the active trace as a flat list." * Returns an empty array when no active trace exists. */ getCurrentTrail(): Array<{ kind: "span" | "marker"; name: string; date: Date; attributes: { [key: string]: string; }; }>; /** * Finds the deepest in-progress span — the leaf of the still-open subtree. Used as * the target for `addMarkerToCurrentSpan`. Intuition: markers attach to whatever is * currently open at the bottom of the call stack. * * Walking the in-progress subtree (rather than ranking all spans by start date) * avoids the edge case where a parent and child have the same `Date.now()` value — * picking the "latest started" by raw timestamp would incorrectly attach to the * parent. Depth-first traversal of in-progress children naturally lands on the * deepest leaf. Tie-broken by latest start date when multiple leaves exist. * * Returns undefined when nothing is in progress (no trace, or every span has ended). * @private */ private findActiveLeafSpan; }