@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 +28 -95
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -3
- package/dist/index.js.map +1 -1
- package/dist/register.d.ts +33 -0
- package/dist/register.d.ts.map +1 -0
- package/dist/register.js +56 -0
- package/dist/register.js.map +1 -0
- package/dist/trace-wrapper.d.ts +44 -3
- package/dist/trace-wrapper.d.ts.map +1 -1
- package/dist/trace-wrapper.js +53 -7
- package/dist/trace-wrapper.js.map +1 -1
- package/package.json +8 -10
- package/dist/candidate-prompt-manager.d.ts +0 -32
- package/dist/candidate-prompt-manager.d.ts.map +0 -1
- package/dist/candidate-prompt-manager.js +0 -55
- package/dist/candidate-prompt-manager.js.map +0 -1
- package/dist/memory-exporter.d.ts +0 -43
- package/dist/memory-exporter.d.ts.map +0 -1
- package/dist/memory-exporter.js +0 -95
- package/dist/memory-exporter.js.map +0 -1
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# @uselemma/tracing
|
|
2
2
|
|
|
3
|
-
|
|
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
|
-
##
|
|
11
|
+
## Quick Start
|
|
12
12
|
|
|
13
|
-
###
|
|
13
|
+
### 1. Register the tracer provider
|
|
14
14
|
|
|
15
|
-
|
|
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 {
|
|
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
|
-
|
|
39
|
-
memoryExporter.clear();
|
|
20
|
+
registerOTel();
|
|
40
21
|
```
|
|
41
22
|
|
|
42
|
-
|
|
23
|
+
### 2. Wrap your agent
|
|
43
24
|
|
|
44
|
-
|
|
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 {
|
|
60
|
-
|
|
61
|
-
const
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
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
|
-
|
|
96
|
-
|
|
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
|
-
|
|
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
|
-
|
|
45
|
+
| Variable | Description |
|
|
46
|
+
| ------------------ | --------------------- |
|
|
47
|
+
| `LEMMA_API_KEY` | Your Lemma API key |
|
|
48
|
+
| `LEMMA_PROJECT_ID` | Your Lemma project ID |
|
|
111
49
|
|
|
112
|
-
|
|
113
|
-
import { memoryExporter } from "./instrumentation";
|
|
50
|
+
Both are required unless passed explicitly to `registerOTel()`.
|
|
114
51
|
|
|
115
|
-
|
|
116
|
-
// ... your code ...
|
|
52
|
+
## Documentation
|
|
117
53
|
|
|
118
|
-
|
|
119
|
-
|
|
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
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,
|
|
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.
|
|
4
|
-
var
|
|
5
|
-
Object.defineProperty(exports, "
|
|
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,
|
|
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"}
|
package/dist/register.js
ADDED
|
@@ -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"}
|
package/dist/trace-wrapper.d.ts
CHANGED
|
@@ -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
|
-
|
|
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
|
-
}
|
|
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,
|
|
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"}
|
package/dist/trace-wrapper.js
CHANGED
|
@@ -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
|
-
|
|
7
|
-
|
|
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(
|
|
14
|
-
"lemma.agent.is_experiment": options
|
|
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
|
-
|
|
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":";;
|
|
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": "
|
|
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/
|
|
9
|
+
"url": "https://github.com/uselemma/sdk"
|
|
10
10
|
},
|
|
11
|
-
"homepage": "https://github.com/uselemma/
|
|
11
|
+
"homepage": "https://github.com/uselemma/sdk#readme",
|
|
12
12
|
"bugs": {
|
|
13
|
-
"url": "https://github.com/uselemma/
|
|
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
|
-
".":
|
|
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"}
|
package/dist/memory-exporter.js
DELETED
|
@@ -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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"}
|