@uselemma/tracing 0.15.0 → 1.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # @uselemma/tracing
2
2
 
3
- Utilities for OpenTelemetry-based tracing and prompt management.
3
+ OpenTelemetry-based tracing for AI agents. Capture inputs, outputs, timing, token usage, and errors — then view everything in [Lemma](https://uselemma.ai).
4
4
 
5
5
  ## Installation
6
6
 
@@ -8,118 +8,51 @@ Utilities for OpenTelemetry-based tracing and prompt management.
8
8
  npm install @uselemma/tracing
9
9
  ```
10
10
 
11
- ## Components
11
+ ## Quick Start
12
12
 
13
- ### MemorySpanExporter
13
+ ### 1. Register the tracer provider
14
14
 
15
- A custom OpenTelemetry span exporter that stores spans in memory for programmatic access. Useful for testing, debugging, or capturing trace data for custom processing.
16
-
17
- #### Usage
15
+ Call `registerOTel` once when your application starts. It reads `LEMMA_API_KEY` and `LEMMA_PROJECT_ID` from environment variables by default.
18
16
 
19
17
  ```typescript
20
- import { NodeSDK } from "@opentelemetry/sdk-node";
21
- import { SimpleSpanProcessor } from "@opentelemetry/sdk-trace-base";
22
- import { MemorySpanExporter } from "@uselemma/tracing";
23
-
24
- // Create and configure the exporter
25
- const memoryExporter = new MemorySpanExporter();
26
-
27
- const sdk = new NodeSDK({
28
- spanProcessors: [new SimpleSpanProcessor(memoryExporter)],
29
- });
30
-
31
- sdk.start();
32
-
33
- // Later, retrieve spans
34
- const allSpans = memoryExporter.getSpans();
35
- const spansAsDicts = memoryExporter.getSpansAsDicts();
36
- const traceSpans = memoryExporter.getSpansByTraceId("your-trace-id");
18
+ import { registerOTel } from "@uselemma/tracing";
37
19
 
38
- // Clear memory when needed
39
- memoryExporter.clear();
20
+ registerOTel();
40
21
  ```
41
22
 
42
- #### Methods
23
+ ### 2. Wrap your agent
43
24
 
44
- - **`getSpans(): ReadableSpan[]`** - Get all stored spans as OpenTelemetry ReadableSpan objects
45
- - **`getSpansAsDicts(): SpanDict[]`** - Get all stored spans as formatted dictionaries
46
- - **`getSpansByTraceId(traceId: string): SpanDict[]`** - Get all spans for a specific trace ID
47
- - **`clear(): void`** - Clear all stored spans from memory
48
- - **`export(spans: ReadableSpan[]): Promise<{ code: ExportResultCode }>`** - Export spans (called automatically by OpenTelemetry)
49
- - **`shutdown(): Promise<void>`** - Shutdown the exporter
50
- - **`forceFlush(): Promise<void>`** - Force flush pending spans
51
-
52
- ### CandidatePromptManager
53
-
54
- Manages prompt template overrides using AsyncLocalStorage for context-local state. Useful for A/B testing or evaluating different prompt variations.
55
-
56
- #### Usage
25
+ `wrapAgent` creates an OpenTelemetry span around your agent function and provides helpers for recording results.
57
26
 
58
27
  ```typescript
59
- import { CandidatePromptManager } from "@uselemma/tracing";
60
-
61
- const promptManager = new CandidatePromptManager();
62
-
63
- // Run code with prompt overrides
64
- await promptManager.run(
65
- {
66
- greeting: "Hello {{ name }}, welcome!",
67
- farewell: "Goodbye {{ name }}!",
28
+ import { wrapAgent } from "@uselemma/tracing";
29
+
30
+ const wrappedFn = wrapAgent(
31
+ "my-agent",
32
+ { initialState: { userMessage } },
33
+ async ({ recordGenerationResults }) => {
34
+ const result = await doWork(userMessage);
35
+ recordGenerationResults({ response: result });
36
+ return result;
68
37
  },
69
- async () => {
70
- // Within this context, candidate prompts will be used
71
- const [template, wasOverridden] = promptManager.getEffectiveTemplate(
72
- "greeting",
73
- "Hi {{ name }}" // default template
74
- );
75
-
76
- console.log(template); // "Hello {{ name }}, welcome!"
77
- console.log(wasOverridden); // true
78
- }
79
38
  );
80
- ```
81
-
82
- #### Methods
83
-
84
- - **`run<T>(candidatePrompts: Record<string, string> | null, callback: () => Promise<T> | T): Promise<T>`**
85
- Run a callback with candidate prompts set in the async context
86
- - **`getEffectiveTemplate(promptName: string, defaultTemplate: string): [string, boolean]`**
87
- Get the effective template, applying candidate override if present. Returns `[template, wasOverridden]`
88
- - **`annotateSpan(span: { setAttribute: (key: string, value: unknown) => void }): void`**
89
- Annotate an OpenTelemetry span with candidate prompt metadata
90
-
91
- ## Example: Dual Processor Setup
92
-
93
- Use `MemorySpanExporter` alongside other exporters to both send traces to your backend and capture them locally:
94
39
 
95
- ```typescript
96
- import { NodeSDK } from "@opentelemetry/sdk-node";
97
- import { SimpleSpanProcessor } from "@opentelemetry/sdk-trace-base";
98
- import { MemorySpanExporter } from "@uselemma/tracing";
99
- import { OtherSpanProcessor } from "your-backend";
100
-
101
- export const memoryExporter = new MemorySpanExporter();
40
+ const { result, runId } = await wrappedFn();
41
+ ```
102
42
 
103
- const sdk = new NodeSDK({
104
- spanProcessors: [
105
- new OtherSpanProcessor(), // Send to your backend
106
- new SimpleSpanProcessor(memoryExporter), // Store in memory for local access
107
- ],
108
- });
43
+ ## Environment Variables
109
44
 
110
- sdk.start();
45
+ | Variable | Description |
46
+ | ------------------ | --------------------- |
47
+ | `LEMMA_API_KEY` | Your Lemma API key |
48
+ | `LEMMA_PROJECT_ID` | Your Lemma project ID |
111
49
 
112
- // In your application code
113
- import { memoryExporter } from "./instrumentation";
50
+ Both are required unless passed explicitly to `registerOTel()`.
114
51
 
115
- function myTracedFunction() {
116
- // ... your code ...
52
+ ## Documentation
117
53
 
118
- // Access spans programmatically
119
- const allSpans = memoryExporter.getSpansAsDicts();
120
- const myTrace = memoryExporter.getSpansByTraceId(currentTraceId);
121
- }
122
- ```
54
+ - [Tracing Overview](https://docs.uselemma.ai/tracing/overview) — concepts, API reference, and usage patterns
55
+ - [Vercel AI SDK Integration](https://docs.uselemma.ai/tracing/integrations/vercel-ai-sdk) — framework setup, streaming, and examples
123
56
 
124
57
  ## License
125
58
 
package/dist/index.d.ts CHANGED
@@ -1,3 +1,3 @@
1
- export { CandidatePromptManager } from "./candidate-prompt-manager";
1
+ export { registerOTel, type RegisterOTelOptions } from "./register";
2
2
  export { wrapAgent, type TraceContext } from "./trace-wrapper";
3
3
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,sBAAsB,EAAE,MAAM,4BAA4B,CAAC;AACpE,OAAO,EAAE,SAAS,EAAE,KAAK,YAAY,EAAE,MAAM,iBAAiB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,KAAK,mBAAmB,EAAE,MAAM,YAAY,CAAC;AACpE,OAAO,EAAE,SAAS,EAAE,KAAK,YAAY,EAAE,MAAM,iBAAiB,CAAC"}
package/dist/index.js CHANGED
@@ -1,8 +1,8 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.wrapAgent = exports.CandidatePromptManager = void 0;
4
- var candidate_prompt_manager_1 = require("./candidate-prompt-manager");
5
- Object.defineProperty(exports, "CandidatePromptManager", { enumerable: true, get: function () { return candidate_prompt_manager_1.CandidatePromptManager; } });
3
+ exports.wrapAgent = exports.registerOTel = void 0;
4
+ var register_1 = require("./register");
5
+ Object.defineProperty(exports, "registerOTel", { enumerable: true, get: function () { return register_1.registerOTel; } });
6
6
  var trace_wrapper_1 = require("./trace-wrapper");
7
7
  Object.defineProperty(exports, "wrapAgent", { enumerable: true, get: function () { return trace_wrapper_1.wrapAgent; } });
8
8
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;AAAA,uEAAoE;AAA3D,kIAAA,sBAAsB,OAAA;AAC/B,iDAA+D;AAAtD,0GAAA,SAAS,OAAA"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;AAAA,uCAAoE;AAA3D,wGAAA,YAAY,OAAA;AACrB,iDAA+D;AAAtD,0GAAA,SAAS,OAAA"}
@@ -0,0 +1,33 @@
1
+ import { NodeTracerProvider } from "@opentelemetry/sdk-trace-node";
2
+ export type RegisterOTelOptions = {
3
+ /** Lemma API key. Defaults to LEMMA_API_KEY environment variable. */
4
+ apiKey?: string;
5
+ /** Lemma project ID. Defaults to LEMMA_PROJECT_ID environment variable. */
6
+ projectId?: string;
7
+ /** Base URL for the Lemma API. Defaults to https://api.uselemma.ai */
8
+ baseUrl?: string;
9
+ };
10
+ /**
11
+ * Registers an OpenTelemetry tracer provider configured to send traces to Lemma.
12
+ *
13
+ * This is a convenience wrapper that sets up `NodeTracerProvider` with a
14
+ * `BatchSpanProcessor` and `OTLPTraceExporter` pointing at the Lemma ingest endpoint.
15
+ *
16
+ * @example
17
+ * // instrumentation.ts (Next.js)
18
+ * export async function register() {
19
+ * if (process.env.NEXT_RUNTIME === 'nodejs') {
20
+ * const { registerOTel } = await import('@uselemma/tracing');
21
+ * registerOTel();
22
+ * }
23
+ * }
24
+ *
25
+ * @example
26
+ * // With explicit options
27
+ * registerOTel({
28
+ * apiKey: 'lma_...',
29
+ * projectId: 'proj_...',
30
+ * });
31
+ */
32
+ export declare function registerOTel(options?: RegisterOTelOptions): NodeTracerProvider;
33
+ //# sourceMappingURL=register.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"register.d.ts","sourceRoot":"","sources":["../src/register.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kBAAkB,EAAE,MAAM,+BAA+B,CAAC;AAInE,MAAM,MAAM,mBAAmB,GAAG;IAChC,qEAAqE;IACrE,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,2EAA2E;IAC3E,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,sEAAsE;IACtE,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB,CAAC;AAEF;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,wBAAgB,YAAY,CAAC,OAAO,GAAE,mBAAwB,sBAkC7D"}
@@ -0,0 +1,56 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.registerOTel = registerOTel;
4
+ const sdk_trace_node_1 = require("@opentelemetry/sdk-trace-node");
5
+ const sdk_trace_base_1 = require("@opentelemetry/sdk-trace-base");
6
+ const exporter_trace_otlp_proto_1 = require("@opentelemetry/exporter-trace-otlp-proto");
7
+ /**
8
+ * Registers an OpenTelemetry tracer provider configured to send traces to Lemma.
9
+ *
10
+ * This is a convenience wrapper that sets up `NodeTracerProvider` with a
11
+ * `BatchSpanProcessor` and `OTLPTraceExporter` pointing at the Lemma ingest endpoint.
12
+ *
13
+ * @example
14
+ * // instrumentation.ts (Next.js)
15
+ * export async function register() {
16
+ * if (process.env.NEXT_RUNTIME === 'nodejs') {
17
+ * const { registerOTel } = await import('@uselemma/tracing');
18
+ * registerOTel();
19
+ * }
20
+ * }
21
+ *
22
+ * @example
23
+ * // With explicit options
24
+ * registerOTel({
25
+ * apiKey: 'lma_...',
26
+ * projectId: 'proj_...',
27
+ * });
28
+ */
29
+ function registerOTel(options = {}) {
30
+ // Resolve options, falling back to environment variables / defaults
31
+ const apiKey = options.apiKey ?? process.env.LEMMA_API_KEY;
32
+ const projectId = options.projectId ?? process.env.LEMMA_PROJECT_ID;
33
+ const baseUrl = options.baseUrl ?? "https://api.uselemma.ai";
34
+ // Fail fast if required credentials are missing
35
+ if (!apiKey || !projectId) {
36
+ throw new Error("@uselemma/tracing: Missing API key and/or project ID. Set the LEMMA_API_KEY and LEMMA_PROJECT_ID environment variables or pass them to registerOTel().");
37
+ }
38
+ // Create a Node tracer provider with a batch processor that exports
39
+ // spans to the Lemma OTLP ingest endpoint over HTTP/protobuf
40
+ const tracerProvider = new sdk_trace_node_1.NodeTracerProvider({
41
+ spanProcessors: [
42
+ new sdk_trace_base_1.BatchSpanProcessor(new exporter_trace_otlp_proto_1.OTLPTraceExporter({
43
+ url: `${baseUrl}/otel/v1/traces`,
44
+ headers: {
45
+ Authorization: `Bearer ${apiKey}`,
46
+ "X-Lemma-Project-ID": projectId,
47
+ },
48
+ })),
49
+ ],
50
+ });
51
+ // Register this provider as the global tracer provider so all
52
+ // subsequent `trace.getTracer()` calls use it
53
+ tracerProvider.register();
54
+ return tracerProvider;
55
+ }
56
+ //# sourceMappingURL=register.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"register.js","sourceRoot":"","sources":["../src/register.ts"],"names":[],"mappings":";;AAmCA,oCAkCC;AArED,kEAAmE;AACnE,kEAAmE;AACnE,wFAA6E;AAW7E;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,SAAgB,YAAY,CAAC,UAA+B,EAAE;IAC5D,oEAAoE;IACpE,MAAM,MAAM,GAAG,OAAO,CAAC,MAAM,IAAI,OAAO,CAAC,GAAG,CAAC,aAAa,CAAC;IAC3D,MAAM,SAAS,GAAG,OAAO,CAAC,SAAS,IAAI,OAAO,CAAC,GAAG,CAAC,gBAAgB,CAAC;IACpE,MAAM,OAAO,GAAG,OAAO,CAAC,OAAO,IAAI,yBAAyB,CAAC;IAE7D,gDAAgD;IAChD,IAAI,CAAC,MAAM,IAAI,CAAC,SAAS,EAAE,CAAC;QAC1B,MAAM,IAAI,KAAK,CACb,wJAAwJ,CACzJ,CAAC;IACJ,CAAC;IAED,oEAAoE;IACpE,6DAA6D;IAC7D,MAAM,cAAc,GAAG,IAAI,mCAAkB,CAAC;QAC5C,cAAc,EAAE;YACd,IAAI,mCAAkB,CACpB,IAAI,6CAAiB,CAAC;gBACpB,GAAG,EAAE,GAAG,OAAO,iBAAiB;gBAChC,OAAO,EAAE;oBACP,aAAa,EAAE,UAAU,MAAM,EAAE;oBACjC,oBAAoB,EAAE,SAAS;iBAChC;aACF,CAAC,CACH;SACF;KACF,CAAC,CAAC;IAEH,8DAA8D;IAC9D,8CAA8C;IAC9C,cAAc,CAAC,QAAQ,EAAE,CAAC;IAE1B,OAAO,cAAc,CAAC;AACxB,CAAC"}
@@ -1,16 +1,57 @@
1
1
  import { Span } from "@opentelemetry/api";
2
2
  export type TraceContext = {
3
+ /** The active OpenTelemetry span for this agent run. */
3
4
  span: Span;
5
+ /** Unique identifier for this agent run. */
4
6
  runId: string;
7
+ /** Signal that the agent completed successfully. Records the result and ends the span. */
5
8
  onComplete: (result: unknown) => void;
9
+ /** Signal that the agent encountered an error. Records the exception and ends the span. */
6
10
  onError: (error: unknown) => void;
11
+ /** Attach arbitrary generation results (e.g. model outputs) to the span. */
7
12
  recordGenerationResults: (results: Record<string, string>) => void;
8
13
  };
9
- export declare function wrapAgent<A extends unknown[]>(agentName: string, options: {
14
+ /**
15
+ * Wraps an agent function with OpenTelemetry tracing, automatically creating
16
+ * a span for the agent run and providing a `TraceContext` to the wrapped function.
17
+ *
18
+ * The returned function creates a new span on every invocation, attaches agent
19
+ * metadata (run ID, input, experiment flag), and handles error recording.
20
+ * The `input` passed to the returned function is recorded as the agent's initial
21
+ * state on the span.
22
+ *
23
+ * @example
24
+ * const myAgent = wrapAgent(
25
+ * 'my-agent',
26
+ * async (ctx, input: { topic: string }) => {
27
+ * // use ctx.span, ctx.runId, ctx.onComplete, etc.
28
+ * const result = await doWork(input.topic);
29
+ * ctx.onComplete(result);
30
+ * },
31
+ * );
32
+ * await myAgent({ topic: 'math' });
33
+ *
34
+ * @example
35
+ * // Keep the span open after the function exits
36
+ * const longRunning = wrapAgent(
37
+ * 'streaming-agent',
38
+ * async (ctx, input) => {
39
+ * // caller is responsible for calling ctx.onComplete / ctx.onError
40
+ * },
41
+ * { endOnExit: false },
42
+ * );
43
+ *
44
+ * @param agentName - Human-readable name used as the span name.
45
+ * @param fn - The agent function to wrap. Receives a {@link TraceContext} as its first argument and the call-time input as its second.
46
+ * @param options - Configuration for the agent trace.
47
+ * @param options.isExperiment - Mark this run as an experiment in Lemma.
48
+ * @param options.endOnExit - Whether to auto-end the span when the function returns. Defaults to `true`.
49
+ * @returns An async function that accepts an `input`, executes `fn` inside a traced context, and returns `{ result, runId, span }`.
50
+ */
51
+ export declare function wrapAgent<Input = unknown>(agentName: string, fn: (traceContext: TraceContext, input: Input) => any, options?: {
10
52
  isExperiment?: boolean;
11
- initialState?: any;
12
53
  endOnExit?: boolean;
13
- }, fn: (traceContext: TraceContext, ...args: A) => any): (this: any, ...args: A) => Promise<{
54
+ }): (this: any, input: Input) => Promise<{
14
55
  result: any;
15
56
  runId: string;
16
57
  span: Span;
@@ -1 +1 @@
1
- {"version":3,"file":"trace-wrapper.d.ts","sourceRoot":"","sources":["../src/trace-wrapper.ts"],"names":[],"mappings":"AAAA,OAAO,EAAkB,IAAI,EAAE,MAAM,oBAAoB,CAAC;AAG1D,MAAM,MAAM,YAAY,GAAG;IACzB,IAAI,EAAE,IAAI,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,UAAU,EAAE,CAAC,MAAM,EAAE,OAAO,KAAK,IAAI,CAAC;IACtC,OAAO,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,IAAI,CAAC;IAClC,uBAAuB,EAAE,CAAC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,KAAK,IAAI,CAAC;CACpE,CAAC;AAEF,wBAAgB,SAAS,CAAC,CAAC,SAAS,OAAO,EAAE,EAAE,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE;IAAE,YAAY,CAAC,EAAE,OAAO,CAAC;IAAC,YAAY,CAAC,EAAE,GAAG,CAAC;IAAC,SAAS,CAAC,EAAE,OAAO,CAAA;CAAE,EAAE,EAAE,EAAE,CAAC,YAAY,EAAE,YAAY,EAAE,GAAG,IAAI,EAAE,CAAC,KAAK,GAAG,UACnJ,GAAG,WAAW,CAAC;;;;GAoD9D"}
1
+ {"version":3,"file":"trace-wrapper.d.ts","sourceRoot":"","sources":["../src/trace-wrapper.ts"],"names":[],"mappings":"AAAA,OAAO,EAAkB,IAAI,EAAE,MAAM,oBAAoB,CAAC;AAG1D,MAAM,MAAM,YAAY,GAAG;IACzB,wDAAwD;IACxD,IAAI,EAAE,IAAI,CAAC;IACX,4CAA4C;IAC5C,KAAK,EAAE,MAAM,CAAC;IACd,0FAA0F;IAC1F,UAAU,EAAE,CAAC,MAAM,EAAE,OAAO,KAAK,IAAI,CAAC;IACtC,2FAA2F;IAC3F,OAAO,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,IAAI,CAAC;IAClC,4EAA4E;IAC5E,uBAAuB,EAAE,CAAC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,KAAK,IAAI,CAAC;CACpE,CAAC;AAEF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAoCG;AACH,wBAAgB,SAAS,CAAC,KAAK,GAAG,OAAO,EAAE,SAAS,EAAE,MAAM,EAAE,EAAE,EAAE,CAAC,YAAY,EAAE,YAAY,EAAE,KAAK,EAAE,KAAK,KAAK,GAAG,EAAE,OAAO,CAAC,EAAE;IAAE,YAAY,CAAC,EAAE,OAAO,CAAC;IAAC,SAAS,CAAC,EAAE,OAAO,CAAA;CAAE,UAC9H,GAAG,SAAS,KAAK;;;;GA8DhE"}
@@ -3,33 +3,78 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.wrapAgent = wrapAgent;
4
4
  const api_1 = require("@opentelemetry/api");
5
5
  const uuid_1 = require("uuid");
6
- function wrapAgent(agentName, options, fn) {
7
- const wrappedFunction = async function (...args) {
6
+ /**
7
+ * Wraps an agent function with OpenTelemetry tracing, automatically creating
8
+ * a span for the agent run and providing a `TraceContext` to the wrapped function.
9
+ *
10
+ * The returned function creates a new span on every invocation, attaches agent
11
+ * metadata (run ID, input, experiment flag), and handles error recording.
12
+ * The `input` passed to the returned function is recorded as the agent's initial
13
+ * state on the span.
14
+ *
15
+ * @example
16
+ * const myAgent = wrapAgent(
17
+ * 'my-agent',
18
+ * async (ctx, input: { topic: string }) => {
19
+ * // use ctx.span, ctx.runId, ctx.onComplete, etc.
20
+ * const result = await doWork(input.topic);
21
+ * ctx.onComplete(result);
22
+ * },
23
+ * );
24
+ * await myAgent({ topic: 'math' });
25
+ *
26
+ * @example
27
+ * // Keep the span open after the function exits
28
+ * const longRunning = wrapAgent(
29
+ * 'streaming-agent',
30
+ * async (ctx, input) => {
31
+ * // caller is responsible for calling ctx.onComplete / ctx.onError
32
+ * },
33
+ * { endOnExit: false },
34
+ * );
35
+ *
36
+ * @param agentName - Human-readable name used as the span name.
37
+ * @param fn - The agent function to wrap. Receives a {@link TraceContext} as its first argument and the call-time input as its second.
38
+ * @param options - Configuration for the agent trace.
39
+ * @param options.isExperiment - Mark this run as an experiment in Lemma.
40
+ * @param options.endOnExit - Whether to auto-end the span when the function returns. Defaults to `true`.
41
+ * @returns An async function that accepts an `input`, executes `fn` inside a traced context, and returns `{ result, runId, span }`.
42
+ */
43
+ function wrapAgent(agentName, fn, options) {
44
+ const wrappedFunction = async function (input) {
45
+ // Obtain the Lemma tracer from the global OTel provider
8
46
  const tracer = api_1.trace.getTracer("lemma");
47
+ // Generate a unique run ID and open a new span for this agent invocation
9
48
  const runId = (0, uuid_1.v4)();
10
49
  const span = tracer.startSpan(agentName, {
11
50
  attributes: {
12
51
  "lemma.agent.run_id": runId,
13
- "lemma.agent.input": JSON.stringify(options.initialState),
14
- "lemma.agent.is_experiment": options.isExperiment,
52
+ "lemma.agent.input": JSON.stringify(input),
53
+ "lemma.agent.is_experiment": options?.isExperiment,
15
54
  },
16
55
  });
56
+ // Propagate the span as the active context so child spans are nested correctly
17
57
  const ctx = api_1.trace.setSpan(api_1.context.active(), span);
18
58
  try {
19
59
  return await api_1.context.with(ctx, async () => {
60
+ // Build the TraceContext callbacks that the agent function can use
61
+ // to manually signal completion, errors, or record generation results
20
62
  const onComplete = (result) => {
21
63
  span.setAttribute("lemma.agent.output", JSON.stringify(result));
22
64
  span.end();
23
65
  };
24
66
  const onError = (error) => {
67
+ // Normalise non-Error values so OTel always receives an Error instance
25
68
  span.recordException(error instanceof Error ? error : new Error(String(error)));
26
- span.setStatus({ code: 2 });
69
+ span.setStatus({ code: 2 }); // SpanStatusCode.ERROR
27
70
  span.end();
28
71
  };
29
72
  const recordGenerationResults = (results) => {
30
73
  span.setAttribute("lemma.agent.generation_results", JSON.stringify(results));
31
74
  };
32
- const result = await fn.call(this, { span, runId, onComplete, onError, recordGenerationResults }, ...args);
75
+ // Invoke the wrapped agent function with the trace context and call-time input
76
+ const result = await fn.call(this, { span, runId, onComplete, onError, recordGenerationResults }, input);
77
+ // Auto-end the span unless the caller opted out (e.g. for streaming)
33
78
  if (options?.endOnExit !== false) {
34
79
  span.end();
35
80
  }
@@ -37,8 +82,9 @@ function wrapAgent(agentName, options, fn) {
37
82
  });
38
83
  }
39
84
  catch (err) {
85
+ // Record the exception on the span and mark it as errored
40
86
  span.recordException(err);
41
- span.setStatus({ code: 2 });
87
+ span.setStatus({ code: 2 }); // SpanStatusCode.ERROR
42
88
  if (options?.endOnExit !== false) {
43
89
  span.end();
44
90
  }
@@ -1 +1 @@
1
- {"version":3,"file":"trace-wrapper.js","sourceRoot":"","sources":["../src/trace-wrapper.ts"],"names":[],"mappings":";;AAWA,8BAqDC;AAhED,4CAA0D;AAC1D,+BAAoC;AAUpC,SAAgB,SAAS,CAAsB,SAAiB,EAAE,OAA4E,EAAE,EAAmD;IACjM,MAAM,eAAe,GAAG,KAAK,WAAsB,GAAG,IAAO;QAC3D,MAAM,MAAM,GAAG,WAAK,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC;QAExC,MAAM,KAAK,GAAG,IAAA,SAAM,GAAE,CAAC;QACvB,MAAM,IAAI,GAAG,MAAM,CAAC,SAAS,CAAC,SAAS,EAAE;YACvC,UAAU,EAAE;gBACV,oBAAoB,EAAE,KAAK;gBAC3B,mBAAmB,EAAE,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,YAAY,CAAC;gBACzD,2BAA2B,EAAE,OAAO,CAAC,YAAY;aAClD;SACF,CAAC,CAAC;QAEH,MAAM,GAAG,GAAG,WAAK,CAAC,OAAO,CAAC,aAAO,CAAC,MAAM,EAAE,EAAE,IAAI,CAAC,CAAC;QAElD,IAAI,CAAC;YACH,OAAO,MAAM,aAAO,CAAC,IAAI,CAAC,GAAG,EAAE,KAAK,IAAI,EAAE;gBACxC,MAAM,UAAU,GAAG,CAAC,MAAe,EAAE,EAAE;oBACrC,IAAI,CAAC,YAAY,CAAC,oBAAoB,EAAE,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC,CAAC;oBAChE,IAAI,CAAC,GAAG,EAAE,CAAC;gBACb,CAAC,CAAC;gBAEF,MAAM,OAAO,GAAG,CAAC,KAAc,EAAE,EAAE;oBACjC,IAAI,CAAC,eAAe,CAAC,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;oBAChF,IAAI,CAAC,SAAS,CAAC,EAAE,IAAI,EAAE,CAAC,EAAE,CAAC,CAAC;oBAC5B,IAAI,CAAC,GAAG,EAAE,CAAC;gBACb,CAAC,CAAC;gBAEF,MAAM,uBAAuB,GAAG,CAAC,OAA+B,EAAE,EAAE;oBAClE,IAAI,CAAC,YAAY,CAAC,gCAAgC,EAAE,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC,CAAC;gBAC/E,CAAC,CAAC;gBAEF,MAAM,MAAM,GAAG,MAAM,EAAE,CAAC,IAAI,CAAC,IAAI,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,UAAU,EAAE,OAAO,EAAE,uBAAuB,EAAE,EAAE,GAAG,IAAI,CAAC,CAAC;gBAE3G,IAAI,OAAO,EAAE,SAAS,KAAK,KAAK,EAAE,CAAC;oBACjC,IAAI,CAAC,GAAG,EAAE,CAAC;gBACb,CAAC;gBAED,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC;YACjC,CAAC,CAAC,CAAC;QACL,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,IAAI,CAAC,eAAe,CAAC,GAAY,CAAC,CAAC;YACnC,IAAI,CAAC,SAAS,CAAC,EAAE,IAAI,EAAE,CAAC,EAAE,CAAC,CAAC;YAE5B,IAAI,OAAO,EAAE,SAAS,KAAK,KAAK,EAAE,CAAC;gBACjC,IAAI,CAAC,GAAG,EAAE,CAAC;YACb,CAAC;YAED,MAAM,GAAG,CAAC;QACZ,CAAC;IACH,CAAC,CAAC;IAEF,OAAO,eAAe,CAAC;AACzB,CAAC"}
1
+ {"version":3,"file":"trace-wrapper.js","sourceRoot":"","sources":["../src/trace-wrapper.ts"],"names":[],"mappings":";;AAqDA,8BA+DC;AApHD,4CAA0D;AAC1D,+BAAoC;AAepC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAoCG;AACH,SAAgB,SAAS,CAAkB,SAAiB,EAAE,EAAqD,EAAE,OAAyD;IAC5K,MAAM,eAAe,GAAG,KAAK,WAAsB,KAAY;QAC7D,wDAAwD;QACxD,MAAM,MAAM,GAAG,WAAK,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC;QAExC,yEAAyE;QACzE,MAAM,KAAK,GAAG,IAAA,SAAM,GAAE,CAAC;QACvB,MAAM,IAAI,GAAG,MAAM,CAAC,SAAS,CAAC,SAAS,EAAE;YACvC,UAAU,EAAE;gBACV,oBAAoB,EAAE,KAAK;gBAC3B,mBAAmB,EAAE,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC;gBAC1C,2BAA2B,EAAE,OAAO,EAAE,YAAY;aACnD;SACF,CAAC,CAAC;QAEH,+EAA+E;QAC/E,MAAM,GAAG,GAAG,WAAK,CAAC,OAAO,CAAC,aAAO,CAAC,MAAM,EAAE,EAAE,IAAI,CAAC,CAAC;QAElD,IAAI,CAAC;YACH,OAAO,MAAM,aAAO,CAAC,IAAI,CAAC,GAAG,EAAE,KAAK,IAAI,EAAE;gBACxC,mEAAmE;gBACnE,sEAAsE;gBAEtE,MAAM,UAAU,GAAG,CAAC,MAAe,EAAE,EAAE;oBACrC,IAAI,CAAC,YAAY,CAAC,oBAAoB,EAAE,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC,CAAC;oBAChE,IAAI,CAAC,GAAG,EAAE,CAAC;gBACb,CAAC,CAAC;gBAEF,MAAM,OAAO,GAAG,CAAC,KAAc,EAAE,EAAE;oBACjC,uEAAuE;oBACvE,IAAI,CAAC,eAAe,CAAC,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;oBAChF,IAAI,CAAC,SAAS,CAAC,EAAE,IAAI,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,uBAAuB;oBACpD,IAAI,CAAC,GAAG,EAAE,CAAC;gBACb,CAAC,CAAC;gBAEF,MAAM,uBAAuB,GAAG,CAAC,OAA+B,EAAE,EAAE;oBAClE,IAAI,CAAC,YAAY,CAAC,gCAAgC,EAAE,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC,CAAC;gBAC/E,CAAC,CAAC;gBAEF,+EAA+E;gBAC/E,MAAM,MAAM,GAAG,MAAM,EAAE,CAAC,IAAI,CAAC,IAAI,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,UAAU,EAAE,OAAO,EAAE,uBAAuB,EAAE,EAAE,KAAK,CAAC,CAAC;gBAEzG,qEAAqE;gBACrE,IAAI,OAAO,EAAE,SAAS,KAAK,KAAK,EAAE,CAAC;oBACjC,IAAI,CAAC,GAAG,EAAE,CAAC;gBACb,CAAC;gBAED,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC;YACjC,CAAC,CAAC,CAAC;QACL,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,0DAA0D;YAC1D,IAAI,CAAC,eAAe,CAAC,GAAY,CAAC,CAAC;YACnC,IAAI,CAAC,SAAS,CAAC,EAAE,IAAI,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,uBAAuB;YAEpD,IAAI,OAAO,EAAE,SAAS,KAAK,KAAK,EAAE,CAAC;gBACjC,IAAI,CAAC,GAAG,EAAE,CAAC;YACb,CAAC;YAED,MAAM,GAAG,CAAC;QACZ,CAAC;IACH,CAAC,CAAC;IAEF,OAAO,eAAe,CAAC;AACzB,CAAC"}
package/package.json CHANGED
@@ -1,16 +1,16 @@
1
1
  {
2
2
  "name": "@uselemma/tracing",
3
- "version": "0.15.0",
3
+ "version": "1.1.0",
4
4
  "description": "OpenTelemetry-based tracing module for Lemma",
5
5
  "license": "MIT",
6
6
  "author": "Lemma",
7
7
  "repository": {
8
8
  "type": "git",
9
- "url": "https://github.com/uselemma/tracing"
9
+ "url": "https://github.com/uselemma/sdk"
10
10
  },
11
- "homepage": "https://github.com/uselemma/tracing#readme",
11
+ "homepage": "https://github.com/uselemma/sdk#readme",
12
12
  "bugs": {
13
- "url": "https://github.com/uselemma/tracing/issues"
13
+ "url": "https://github.com/uselemma/sdk/issues"
14
14
  },
15
15
  "keywords": [
16
16
  "opentelemetry",
@@ -23,7 +23,10 @@
23
23
  "main": "./dist/index.js",
24
24
  "types": "./dist/index.d.ts",
25
25
  "exports": {
26
- ".": "./dist/index.js"
26
+ ".": {
27
+ "types": "./dist/index.d.ts",
28
+ "default": "./dist/index.js"
29
+ }
27
30
  },
28
31
  "files": [
29
32
  "dist",
@@ -32,19 +35,14 @@
32
35
  ],
33
36
  "dependencies": {
34
37
  "@opentelemetry/api": "^1.9.0",
35
- "@opentelemetry/context-async-hooks": "^2.2.0",
36
- "@opentelemetry/core": "^2.2.0",
37
38
  "@opentelemetry/exporter-trace-otlp-proto": "^0.211.0",
38
- "@opentelemetry/resources": "^2.2.0",
39
39
  "@opentelemetry/sdk-trace-base": "^2.2.0",
40
40
  "@opentelemetry/sdk-trace-node": "^2.5.0",
41
- "nunjucks": "^3.2.4",
42
41
  "uuid": "^13.0.0"
43
42
  },
44
43
  "devDependencies": {
45
44
  "@trivago/prettier-plugin-sort-imports": "^5.2.2",
46
45
  "@types/node": "^22.18.8",
47
- "@types/nunjucks": "^3.2.6",
48
46
  "prettier": "^3.6.2",
49
47
  "prettier-plugin-tailwindcss": "^0.6.14",
50
48
  "typescript": "^5.9.3"
@@ -1,32 +0,0 @@
1
- /**
2
- * Manages candidate prompt overrides using AsyncLocalStorage for context-local state.
3
- */
4
- export declare class CandidatePromptManager {
5
- private readonly _overrides;
6
- constructor();
7
- /**
8
- * Runs a callback with candidate prompts set in the async context.
9
- *
10
- * @param candidatePrompts - Optional dictionary of prompt name -> candidate template
11
- * @param callback - Function to run with the context
12
- * @returns Result of the callback
13
- */
14
- run<T>(candidatePrompts: Record<string, string> | null | undefined, callback: () => Promise<T> | T): Promise<T>;
15
- /**
16
- * Get the effective template, applying candidate override if present.
17
- *
18
- * @param promptName - Name of the prompt
19
- * @param defaultTemplate - Default template to use if no override
20
- * @returns Tuple of [effectiveTemplate, overrideApplied]
21
- */
22
- getEffectiveTemplate(promptName: string, defaultTemplate: string): [string, boolean];
23
- /**
24
- * Annotate span with candidate prompt metadata.
25
- *
26
- * @param span - OpenTelemetry span to annotate
27
- */
28
- annotateSpan(span: {
29
- setAttribute: (key: string, value: unknown) => void;
30
- }): void;
31
- }
32
- //# sourceMappingURL=candidate-prompt-manager.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"candidate-prompt-manager.d.ts","sourceRoot":"","sources":["../src/candidate-prompt-manager.ts"],"names":[],"mappings":"AAEA;;GAEG;AACH,qBAAa,sBAAsB;IACjC,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAmD;;IAM9E;;;;;;OAMG;IACG,GAAG,CAAC,CAAC,EACT,gBAAgB,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,IAAI,GAAG,SAAS,EAC3D,QAAQ,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC,GAC7B,OAAO,CAAC,CAAC,CAAC;IAIb;;;;;;OAMG;IACH,oBAAoB,CAClB,UAAU,EAAE,MAAM,EAClB,eAAe,EAAE,MAAM,GACtB,CAAC,MAAM,EAAE,OAAO,CAAC;IAQpB;;;;OAIG;IACH,YAAY,CAAC,IAAI,EAAE;QACjB,YAAY,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,KAAK,IAAI,CAAC;KACrD,GAAG,IAAI;CAaT"}
@@ -1,55 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.CandidatePromptManager = void 0;
4
- const node_async_hooks_1 = require("node:async_hooks");
5
- /**
6
- * Manages candidate prompt overrides using AsyncLocalStorage for context-local state.
7
- */
8
- class CandidatePromptManager {
9
- _overrides;
10
- constructor() {
11
- this._overrides = new node_async_hooks_1.AsyncLocalStorage();
12
- }
13
- /**
14
- * Runs a callback with candidate prompts set in the async context.
15
- *
16
- * @param candidatePrompts - Optional dictionary of prompt name -> candidate template
17
- * @param callback - Function to run with the context
18
- * @returns Result of the callback
19
- */
20
- async run(candidatePrompts, callback) {
21
- return this._overrides.run(candidatePrompts ?? null, callback);
22
- }
23
- /**
24
- * Get the effective template, applying candidate override if present.
25
- *
26
- * @param promptName - Name of the prompt
27
- * @param defaultTemplate - Default template to use if no override
28
- * @returns Tuple of [effectiveTemplate, overrideApplied]
29
- */
30
- getEffectiveTemplate(promptName, defaultTemplate) {
31
- const overrides = this._overrides.getStore();
32
- if (overrides && promptName in overrides) {
33
- return [overrides[promptName], true];
34
- }
35
- return [defaultTemplate, false];
36
- }
37
- /**
38
- * Annotate span with candidate prompt metadata.
39
- *
40
- * @param span - OpenTelemetry span to annotate
41
- */
42
- annotateSpan(span) {
43
- const overrides = this._overrides.getStore();
44
- if (overrides !== null && overrides !== undefined) {
45
- try {
46
- span.setAttribute("candidate_prompts.count", Object.keys(overrides).length);
47
- }
48
- catch {
49
- // Best-effort; avoid breaking tracing on attribute errors
50
- }
51
- }
52
- }
53
- }
54
- exports.CandidatePromptManager = CandidatePromptManager;
55
- //# sourceMappingURL=candidate-prompt-manager.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"candidate-prompt-manager.js","sourceRoot":"","sources":["../src/candidate-prompt-manager.ts"],"names":[],"mappings":";;;AAAA,uDAAqD;AAErD;;GAEG;AACH,MAAa,sBAAsB;IAChB,UAAU,CAAmD;IAE9E;QACE,IAAI,CAAC,UAAU,GAAG,IAAI,oCAAiB,EAAiC,CAAC;IAC3E,CAAC;IAED;;;;;;OAMG;IACH,KAAK,CAAC,GAAG,CACP,gBAA2D,EAC3D,QAA8B;QAE9B,OAAO,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,gBAAgB,IAAI,IAAI,EAAE,QAAQ,CAAC,CAAC;IACjE,CAAC;IAED;;;;;;OAMG;IACH,oBAAoB,CAClB,UAAkB,EAClB,eAAuB;QAEvB,MAAM,SAAS,GAAG,IAAI,CAAC,UAAU,CAAC,QAAQ,EAAE,CAAC;QAC7C,IAAI,SAAS,IAAI,UAAU,IAAI,SAAS,EAAE,CAAC;YACzC,OAAO,CAAC,SAAS,CAAC,UAAU,CAAC,EAAE,IAAI,CAAC,CAAC;QACvC,CAAC;QACD,OAAO,CAAC,eAAe,EAAE,KAAK,CAAC,CAAC;IAClC,CAAC;IAED;;;;OAIG;IACH,YAAY,CAAC,IAEZ;QACC,MAAM,SAAS,GAAG,IAAI,CAAC,UAAU,CAAC,QAAQ,EAAE,CAAC;QAC7C,IAAI,SAAS,KAAK,IAAI,IAAI,SAAS,KAAK,SAAS,EAAE,CAAC;YAClD,IAAI,CAAC;gBACH,IAAI,CAAC,YAAY,CACf,yBAAyB,EACzB,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,MAAM,CAC9B,CAAC;YACJ,CAAC;YAAC,MAAM,CAAC;gBACP,0DAA0D;YAC5D,CAAC;QACH,CAAC;IACH,CAAC;CACF;AA3DD,wDA2DC"}
@@ -1,43 +0,0 @@
1
- import { ExportResultCode } from "@opentelemetry/core";
2
- import type { ReadableSpan, SpanExporter } from "@opentelemetry/sdk-trace-base";
3
- export interface SpanDict {
4
- timestamp: string;
5
- trace_id: string;
6
- span_id: string;
7
- parent_span_id: string | null;
8
- name: string;
9
- kind: string;
10
- start_time_ns: string;
11
- end_time_ns: string | null;
12
- duration_ms: number | null;
13
- attributes: Record<string, unknown>;
14
- status: {
15
- status_code: string;
16
- description?: string;
17
- } | null;
18
- events: Array<{
19
- name: string;
20
- timestamp_ns: string;
21
- attributes: Record<string, unknown>;
22
- }>;
23
- resource: Record<string, unknown>;
24
- }
25
- /**
26
- * Span exporter that stores spans in memory for retrieval.
27
- */
28
- export declare class MemorySpanExporter implements SpanExporter {
29
- private readonly _spans;
30
- export(spans: ReadableSpan[]): Promise<{
31
- code: ExportResultCode;
32
- }>;
33
- getSpans(): ReadableSpan[];
34
- getSpansAsDicts(): SpanDict[];
35
- getSpansByTraceId(traceId: string): SpanDict[];
36
- private _formatTraceId;
37
- private _formatSpanId;
38
- private _spanToDict;
39
- clear(): void;
40
- shutdown(): Promise<void>;
41
- forceFlush(): Promise<void>;
42
- }
43
- //# sourceMappingURL=memory-exporter.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"memory-exporter.d.ts","sourceRoot":"","sources":["../src/memory-exporter.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,MAAM,qBAAqB,CAAC;AACvD,OAAO,KAAK,EAAE,YAAY,EAAE,YAAY,EAAE,MAAM,+BAA+B,CAAC;AAEhF,MAAM,WAAW,QAAQ;IACvB,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;IAChB,cAAc,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,aAAa,EAAE,MAAM,CAAC;IACtB,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACpC,MAAM,EAAE;QACN,WAAW,EAAE,MAAM,CAAC;QACpB,WAAW,CAAC,EAAE,MAAM,CAAC;KACtB,GAAG,IAAI,CAAC;IACT,MAAM,EAAE,KAAK,CAAC;QACZ,IAAI,EAAE,MAAM,CAAC;QACb,YAAY,EAAE,MAAM,CAAC;QACrB,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;KACrC,CAAC,CAAC;IACH,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACnC;AAED;;GAEG;AACH,qBAAa,kBAAmB,YAAW,YAAY;IACrD,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAsB;IAE7C,MAAM,CAAC,KAAK,EAAE,YAAY,EAAE,GAAG,OAAO,CAAC;QAAE,IAAI,EAAE,gBAAgB,CAAA;KAAE,CAAC;IAKlE,QAAQ,IAAI,YAAY,EAAE;IAI1B,eAAe,IAAI,QAAQ,EAAE;IAI7B,iBAAiB,CAAC,OAAO,EAAE,MAAM,GAAG,QAAQ,EAAE;IAiB9C,OAAO,CAAC,cAAc;IAKtB,OAAO,CAAC,aAAa;IAKrB,OAAO,CAAC,WAAW;IAkDnB,KAAK,IAAI,IAAI;IAIb,QAAQ,IAAI,OAAO,CAAC,IAAI,CAAC;IAIzB,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC;CAG5B"}
@@ -1,95 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.MemorySpanExporter = void 0;
4
- const core_1 = require("@opentelemetry/core");
5
- /**
6
- * Span exporter that stores spans in memory for retrieval.
7
- */
8
- class MemorySpanExporter {
9
- _spans = [];
10
- export(spans) {
11
- this._spans.push(...spans);
12
- return Promise.resolve({ code: core_1.ExportResultCode.SUCCESS });
13
- }
14
- getSpans() {
15
- return [...this._spans];
16
- }
17
- getSpansAsDicts() {
18
- return this._spans.map((span) => this._spanToDict(span));
19
- }
20
- getSpansByTraceId(traceId) {
21
- const formattedTraceId = this._formatTraceId(traceId);
22
- console.log(this._spans.map((span) => {
23
- const spanDict = this._spanToDict(span);
24
- return {
25
- traceId: spanDict.trace_id,
26
- spanId: spanDict.span_id,
27
- parentSpanId: spanDict.parent_span_id,
28
- };
29
- }));
30
- return this._spans
31
- .map((span) => this._spanToDict(span))
32
- .filter((span) => span.trace_id === formattedTraceId);
33
- }
34
- _formatTraceId(traceId) {
35
- // Ensure trace ID is 32-character hex string
36
- return traceId.padStart(32, "0").slice(0, 32);
37
- }
38
- _formatSpanId(spanId) {
39
- // Ensure span ID is 16-character hex string
40
- return spanId.padStart(16, "0").slice(0, 16);
41
- }
42
- _spanToDict(span) {
43
- const spanCtx = span.spanContext();
44
- const traceId = this._formatTraceId(spanCtx.traceId);
45
- const spanId = this._formatSpanId(spanCtx.spanId);
46
- const parentSpanId = span.parentSpanContext
47
- ? this._formatSpanId(span.parentSpanContext.spanId)
48
- : null;
49
- return {
50
- timestamp: new Date().toISOString(),
51
- trace_id: traceId,
52
- span_id: spanId,
53
- parent_span_id: parentSpanId,
54
- name: span.name,
55
- kind: span.kind.toString(),
56
- start_time_ns: (BigInt(span.startTime[0]) * 1000000000n +
57
- BigInt(span.startTime[1])).toString(),
58
- end_time_ns: span.endTime
59
- ? (BigInt(span.endTime[0]) * 1000000000n +
60
- BigInt(span.endTime[1])).toString()
61
- : null,
62
- duration_ms: span.endTime
63
- ? (span.endTime[0] - span.startTime[0]) * 1000 +
64
- (span.endTime[1] - span.startTime[1]) / 1_000_000
65
- : null,
66
- attributes: span.attributes ? { ...span.attributes } : {},
67
- status: span.status
68
- ? {
69
- status_code: span.status.code.toString(),
70
- description: span.status.message,
71
- }
72
- : null,
73
- events: (span.events || []).map((event) => ({
74
- name: event.name,
75
- timestamp_ns: (BigInt(event.time[0]) * 1000000000n +
76
- BigInt(event.time[1])).toString(),
77
- attributes: event.attributes ? { ...event.attributes } : {},
78
- })),
79
- resource: span.resource?.attributes
80
- ? { ...span.resource.attributes }
81
- : {},
82
- };
83
- }
84
- clear() {
85
- this._spans.length = 0;
86
- }
87
- shutdown() {
88
- return Promise.resolve();
89
- }
90
- forceFlush() {
91
- return Promise.resolve();
92
- }
93
- }
94
- exports.MemorySpanExporter = MemorySpanExporter;
95
- //# sourceMappingURL=memory-exporter.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"memory-exporter.js","sourceRoot":"","sources":["../src/memory-exporter.ts"],"names":[],"mappings":"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"}