@respan/tracing 1.0.45 → 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 +68 -66
- package/dist/contexts/index.d.ts +1 -0
- package/dist/contexts/index.js +1 -0
- package/dist/contexts/index.js.map +1 -1
- package/dist/contexts/propagation.d.ts +25 -0
- package/dist/contexts/propagation.js +47 -0
- package/dist/contexts/propagation.js.map +1 -0
- package/dist/processor/composite.js +111 -3
- package/dist/processor/composite.js.map +1 -1
- package/dist/utils/batchLogging.d.ts +46 -0
- package/dist/utils/batchLogging.js +107 -0
- package/dist/utils/batchLogging.js.map +1 -0
- package/dist/utils/context.d.ts +6 -0
- package/dist/utils/context.js +9 -0
- package/dist/utils/context.js.map +1 -1
- package/dist/utils/index.d.ts +1 -0
- package/dist/utils/index.js +1 -0
- package/dist/utils/index.js.map +1 -1
- package/dist/utils/spanFactory.d.ts +36 -0
- package/dist/utils/spanFactory.js +148 -0
- package/dist/utils/spanFactory.js.map +1 -0
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
|
-
#
|
|
1
|
+
# Respan Tracing SDK
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
**[respan.ai](https://respan.ai)** | **[Documentation](https://docs.respan.ai)**
|
|
4
|
+
|
|
5
|
+
A lightweight OpenTelemetry-based tracing SDK for Respan, built with minimal dependencies and optional instrumentation support.
|
|
4
6
|
Inspired by [Openllmetry](https://github.com/traceloop/openllmetry-js)
|
|
5
7
|
|
|
6
8
|
## Features
|
|
@@ -14,13 +16,13 @@ Inspired by [Openllmetry](https://github.com/traceloop/openllmetry-js)
|
|
|
14
16
|
- **Span Management**: Full control over spans with `getClient()` API
|
|
15
17
|
- **Multi-Processor Routing**: Route spans to multiple destinations
|
|
16
18
|
- **Span Buffering**: Manual control over span export timing
|
|
17
|
-
- **
|
|
19
|
+
- **Respan Parameters**: Add customer identifiers and trace group identifiers
|
|
18
20
|
|
|
19
21
|
## Installation
|
|
20
22
|
|
|
21
23
|
### Core Package
|
|
22
24
|
```bash
|
|
23
|
-
npm install @
|
|
25
|
+
npm install @respan/tracing
|
|
24
26
|
```
|
|
25
27
|
|
|
26
28
|
### Optional Instrumentations
|
|
@@ -63,24 +65,24 @@ npm install @traceloop/instrumentation-vertexai
|
|
|
63
65
|
### Method 1: Dynamic Instrumentation (Recommended for Node.js)
|
|
64
66
|
|
|
65
67
|
```typescript
|
|
66
|
-
import {
|
|
68
|
+
import { RespanTelemetry } from '@respan/tracing';
|
|
67
69
|
import OpenAI from 'openai';
|
|
68
70
|
|
|
69
71
|
// Initialize the SDK
|
|
70
|
-
const
|
|
71
|
-
apiKey: process.env.
|
|
72
|
-
baseURL: process.env.
|
|
72
|
+
const respan = new RespanTelemetry({
|
|
73
|
+
apiKey: process.env.RESPAN_API_KEY,
|
|
74
|
+
baseURL: process.env.RESPAN_BASE_URL,
|
|
73
75
|
appName: 'my-app'
|
|
74
76
|
});
|
|
75
77
|
|
|
76
78
|
// Enable instrumentations you need
|
|
77
|
-
await
|
|
79
|
+
await respan.enableInstrumentation('openai');
|
|
78
80
|
|
|
79
81
|
const openai = new OpenAI();
|
|
80
82
|
|
|
81
83
|
// Use decorators to trace your functions
|
|
82
84
|
const generateJoke = async () => {
|
|
83
|
-
return await
|
|
85
|
+
return await respan.withTask(
|
|
84
86
|
{ name: 'joke_generation' },
|
|
85
87
|
async () => {
|
|
86
88
|
const completion = await openai.chat.completions.create({
|
|
@@ -96,14 +98,14 @@ const generateJoke = async () => {
|
|
|
96
98
|
### Method 2: Manual Instrumentation (Recommended for Next.js)
|
|
97
99
|
|
|
98
100
|
```typescript
|
|
99
|
-
import {
|
|
101
|
+
import { RespanTelemetry } from '@respan/tracing';
|
|
100
102
|
import OpenAI from 'openai';
|
|
101
103
|
import Anthropic from '@anthropic-ai/sdk';
|
|
102
104
|
|
|
103
105
|
// Manual instrumentation - pass the actual imported modules
|
|
104
|
-
const
|
|
105
|
-
apiKey: process.env.
|
|
106
|
-
baseURL: process.env.
|
|
106
|
+
const respan = new RespanTelemetry({
|
|
107
|
+
apiKey: process.env.RESPAN_API_KEY,
|
|
108
|
+
baseURL: process.env.RESPAN_BASE_URL,
|
|
107
109
|
appName: 'my-app',
|
|
108
110
|
// Specify modules to instrument manually
|
|
109
111
|
instrumentModules: {
|
|
@@ -114,7 +116,7 @@ const keywordsAi = new KeywordsAITelemetry({
|
|
|
114
116
|
});
|
|
115
117
|
|
|
116
118
|
// Wait for initialization (optional but recommended)
|
|
117
|
-
await
|
|
119
|
+
await respan.initialize();
|
|
118
120
|
|
|
119
121
|
// Create clients - they will be automatically instrumented
|
|
120
122
|
const openai = new OpenAI();
|
|
@@ -122,7 +124,7 @@ const anthropic = new Anthropic();
|
|
|
122
124
|
|
|
123
125
|
// Use decorators to trace your functions
|
|
124
126
|
const generateContent = async () => {
|
|
125
|
-
return await
|
|
127
|
+
return await respan.withWorkflow(
|
|
126
128
|
{ name: 'content_generation', version: 1 },
|
|
127
129
|
async () => {
|
|
128
130
|
const result = await openai.chat.completions.create({
|
|
@@ -149,15 +151,15 @@ const generateContent = async () => {
|
|
|
149
151
|
|
|
150
152
|
## API Reference
|
|
151
153
|
|
|
152
|
-
###
|
|
154
|
+
### RespanTelemetry
|
|
153
155
|
|
|
154
156
|
#### Constructor Options
|
|
155
157
|
|
|
156
158
|
```typescript
|
|
157
|
-
interface
|
|
159
|
+
interface RespanOptions {
|
|
158
160
|
appName?: string; // App name for traces
|
|
159
|
-
apiKey?: string; //
|
|
160
|
-
baseURL?: string; //
|
|
161
|
+
apiKey?: string; // Respan API key
|
|
162
|
+
baseURL?: string; // Respan base URL
|
|
161
163
|
disableBatch?: boolean; // Disable batching for development
|
|
162
164
|
logLevel?: "debug" | "info" | "warn" | "error";
|
|
163
165
|
traceContent?: boolean; // Log prompts and completions
|
|
@@ -209,7 +211,7 @@ interface KeywordsAIOptions {
|
|
|
209
211
|
#### withWorkflow
|
|
210
212
|
Trace high-level workflows:
|
|
211
213
|
```typescript
|
|
212
|
-
await
|
|
214
|
+
await respan.withWorkflow(
|
|
213
215
|
{ name: 'my_workflow', version: 1 },
|
|
214
216
|
async () => {
|
|
215
217
|
// Your workflow logic
|
|
@@ -220,7 +222,7 @@ await keywordsAi.withWorkflow(
|
|
|
220
222
|
#### withTask
|
|
221
223
|
Trace individual tasks:
|
|
222
224
|
```typescript
|
|
223
|
-
await
|
|
225
|
+
await respan.withTask(
|
|
224
226
|
{ name: 'my_task' },
|
|
225
227
|
async () => {
|
|
226
228
|
// Your task logic
|
|
@@ -231,7 +233,7 @@ await keywordsAi.withTask(
|
|
|
231
233
|
#### withAgent
|
|
232
234
|
Trace agent operations:
|
|
233
235
|
```typescript
|
|
234
|
-
await
|
|
236
|
+
await respan.withAgent(
|
|
235
237
|
{ name: 'my_agent', associationProperties: { type: 'assistant' } },
|
|
236
238
|
async () => {
|
|
237
239
|
// Your agent logic
|
|
@@ -242,7 +244,7 @@ await keywordsAi.withAgent(
|
|
|
242
244
|
#### withTool
|
|
243
245
|
Trace tool usage:
|
|
244
246
|
```typescript
|
|
245
|
-
await
|
|
247
|
+
await respan.withTool(
|
|
246
248
|
{ name: 'my_tool' },
|
|
247
249
|
async () => {
|
|
248
250
|
// Your tool logic
|
|
@@ -271,9 +273,9 @@ interface DecoratorConfig {
|
|
|
271
273
|
Get full control over your spans with the client API:
|
|
272
274
|
|
|
273
275
|
```typescript
|
|
274
|
-
import {
|
|
276
|
+
import { RespanTelemetry, getClient } from '@respan/tracing';
|
|
275
277
|
|
|
276
|
-
const kai = new
|
|
278
|
+
const kai = new RespanTelemetry({ apiKey: 'your-key' });
|
|
277
279
|
await kai.initialize();
|
|
278
280
|
|
|
279
281
|
await kai.withTask({ name: 'process_data' }, async () => {
|
|
@@ -284,9 +286,9 @@ await kai.withTask({ name: 'process_data' }, async () => {
|
|
|
284
286
|
const spanId = client.getCurrentSpanId();
|
|
285
287
|
console.log(`Trace: ${traceId}, Span: ${spanId}`);
|
|
286
288
|
|
|
287
|
-
// Update span with
|
|
289
|
+
// Update span with Respan parameters
|
|
288
290
|
client.updateCurrentSpan({
|
|
289
|
-
|
|
291
|
+
respanParams: {
|
|
290
292
|
customerIdentifier: 'user-123',
|
|
291
293
|
traceGroupIdentifier: 'data-pipeline',
|
|
292
294
|
metadata: {
|
|
@@ -316,7 +318,7 @@ await kai.withTask({ name: 'process_data' }, async () => {
|
|
|
316
318
|
**Available Client Methods:**
|
|
317
319
|
- `getCurrentTraceId()` - Get the current trace ID
|
|
318
320
|
- `getCurrentSpanId()` - Get the current span ID
|
|
319
|
-
- `updateCurrentSpan(options)` - Update span attributes, name, status, or
|
|
321
|
+
- `updateCurrentSpan(options)` - Update span attributes, name, status, or Respan params
|
|
320
322
|
- `addEvent(name, attributes?)` - Add an event to the current span
|
|
321
323
|
- `recordException(exception)` - Record an exception on the current span
|
|
322
324
|
- `isRecording()` - Check if the span is recording
|
|
@@ -328,11 +330,11 @@ await kai.withTask({ name: 'process_data' }, async () => {
|
|
|
328
330
|
Route spans to different destinations based on processor names:
|
|
329
331
|
|
|
330
332
|
```typescript
|
|
331
|
-
import {
|
|
333
|
+
import { RespanTelemetry } from '@respan/tracing';
|
|
332
334
|
|
|
333
|
-
const kai = new
|
|
335
|
+
const kai = new RespanTelemetry({ apiKey: 'your-key' });
|
|
334
336
|
|
|
335
|
-
// Add a debug processor (in addition to default
|
|
337
|
+
// Add a debug processor (in addition to default Respan processor)
|
|
336
338
|
kai.addProcessor({
|
|
337
339
|
exporter: new YourCustomExporter(),
|
|
338
340
|
name: 'debug',
|
|
@@ -359,7 +361,7 @@ await kai.withTask(
|
|
|
359
361
|
await kai.withTask(
|
|
360
362
|
{ name: 'normal_task' },
|
|
361
363
|
async () => {
|
|
362
|
-
// This span goes to the default
|
|
364
|
+
// This span goes to the default Respan processor
|
|
363
365
|
}
|
|
364
366
|
);
|
|
365
367
|
```
|
|
@@ -379,9 +381,9 @@ interface ProcessorConfig {
|
|
|
379
381
|
Buffer spans and control when they're exported:
|
|
380
382
|
|
|
381
383
|
```typescript
|
|
382
|
-
import {
|
|
384
|
+
import { RespanTelemetry } from '@respan/tracing';
|
|
383
385
|
|
|
384
|
-
const kai = new
|
|
386
|
+
const kai = new RespanTelemetry({ apiKey: 'your-key' });
|
|
385
387
|
const manager = kai.getSpanBufferManager();
|
|
386
388
|
|
|
387
389
|
// Create a buffer (spans won't be auto-exported)
|
|
@@ -407,7 +409,7 @@ const isSuccessful = true; // Your business logic
|
|
|
407
409
|
const isPremiumUser = true; // Your business logic
|
|
408
410
|
|
|
409
411
|
if (isSuccessful && isPremiumUser) {
|
|
410
|
-
// Export to
|
|
412
|
+
// Export to Respan
|
|
411
413
|
await manager.processSpans(spans);
|
|
412
414
|
} else {
|
|
413
415
|
// Discard spans
|
|
@@ -428,18 +430,18 @@ if (isSuccessful && isPremiumUser) {
|
|
|
428
430
|
- `getSpanCount()` - Get the number of buffered spans
|
|
429
431
|
- `clearSpans()` - Discard all buffered spans without exporting
|
|
430
432
|
|
|
431
|
-
###
|
|
433
|
+
### Respan-Specific Parameters
|
|
432
434
|
|
|
433
435
|
Add customer and trace group identifiers to your spans:
|
|
434
436
|
|
|
435
437
|
```typescript
|
|
436
|
-
import { getClient } from '@
|
|
438
|
+
import { getClient } from '@respan/tracing';
|
|
437
439
|
|
|
438
440
|
await kai.withWorkflow({ name: 'user_workflow' }, async () => {
|
|
439
441
|
const client = getClient();
|
|
440
442
|
|
|
441
443
|
client.updateCurrentSpan({
|
|
442
|
-
|
|
444
|
+
respanParams: {
|
|
443
445
|
// Group traces by customer
|
|
444
446
|
customerIdentifier: 'user-123',
|
|
445
447
|
|
|
@@ -518,7 +520,7 @@ Use manual instrumentation instead:
|
|
|
518
520
|
await kai.enableInstrumentation('anthropic');
|
|
519
521
|
|
|
520
522
|
// Use this:
|
|
521
|
-
const kai = new
|
|
523
|
+
const kai = new RespanTelemetry({
|
|
522
524
|
instrumentModules: {
|
|
523
525
|
anthropic: Anthropic
|
|
524
526
|
}
|
|
@@ -558,16 +560,16 @@ const kai = new KeywordsAITelemetry({
|
|
|
558
560
|
### Spans not showing up?
|
|
559
561
|
|
|
560
562
|
1. Check that you're using decorators (`withTask`, `withWorkflow`, etc.)
|
|
561
|
-
2. Verify API key is set: `process.env.
|
|
563
|
+
2. Verify API key is set: `process.env.RESPAN_API_KEY`
|
|
562
564
|
3. Enable debug logging: `logLevel: 'debug'`
|
|
563
|
-
4. Check network requests to
|
|
565
|
+
4. Check network requests to Respan endpoint
|
|
564
566
|
|
|
565
567
|
## Environment Variables
|
|
566
568
|
|
|
567
|
-
- `
|
|
568
|
-
- `
|
|
569
|
-
- `
|
|
570
|
-
- `
|
|
569
|
+
- `RESPAN_API_KEY`: Your Respan API key
|
|
570
|
+
- `RESPAN_BASE_URL`: Respan base URL (default: https://api.respan.ai)
|
|
571
|
+
- `RESPAN_APP_NAME`: Default app name
|
|
572
|
+
- `RESPAN_TRACE_CONTENT`: Enable/disable content tracing (default: true)
|
|
571
573
|
|
|
572
574
|
## Provider-Specific Examples
|
|
573
575
|
|
|
@@ -575,11 +577,11 @@ const kai = new KeywordsAITelemetry({
|
|
|
575
577
|
|
|
576
578
|
**Method 1: Dynamic Instrumentation (Simple)**
|
|
577
579
|
```typescript
|
|
578
|
-
import {
|
|
580
|
+
import { RespanTelemetry } from '@respan/tracing';
|
|
579
581
|
import OpenAI from 'openai';
|
|
580
582
|
|
|
581
|
-
const kai = new
|
|
582
|
-
apiKey: process.env.
|
|
583
|
+
const kai = new RespanTelemetry({
|
|
584
|
+
apiKey: process.env.RESPAN_API_KEY,
|
|
583
585
|
appName: 'openai-app'
|
|
584
586
|
});
|
|
585
587
|
|
|
@@ -599,11 +601,11 @@ await kai.withTask({ name: 'chat' }, async () => {
|
|
|
599
601
|
|
|
600
602
|
**Method 2: Manual Instrumentation (Next.js/Webpack)**
|
|
601
603
|
```typescript
|
|
602
|
-
import {
|
|
604
|
+
import { RespanTelemetry } from '@respan/tracing';
|
|
603
605
|
import OpenAI from 'openai';
|
|
604
606
|
|
|
605
|
-
const kai = new
|
|
606
|
-
apiKey: process.env.
|
|
607
|
+
const kai = new RespanTelemetry({
|
|
608
|
+
apiKey: process.env.RESPAN_API_KEY,
|
|
607
609
|
appName: 'openai-app',
|
|
608
610
|
instrumentModules: {
|
|
609
611
|
openAI: OpenAI // Pass the OpenAI class
|
|
@@ -626,12 +628,12 @@ await kai.withTask({ name: 'chat' }, async () => {
|
|
|
626
628
|
### Anthropic (Claude)
|
|
627
629
|
|
|
628
630
|
```typescript
|
|
629
|
-
import {
|
|
631
|
+
import { RespanTelemetry } from '@respan/tracing';
|
|
630
632
|
import Anthropic from '@anthropic-ai/sdk';
|
|
631
633
|
|
|
632
634
|
// Initialize with Anthropic instrumentation
|
|
633
|
-
const kai = new
|
|
634
|
-
apiKey: process.env.
|
|
635
|
+
const kai = new RespanTelemetry({
|
|
636
|
+
apiKey: process.env.RESPAN_API_KEY,
|
|
635
637
|
appName: 'anthropic-app',
|
|
636
638
|
instrumentModules: {
|
|
637
639
|
anthropic: Anthropic // Pass the Anthropic class
|
|
@@ -684,11 +686,11 @@ npm install @anthropic-ai/sdk @traceloop/instrumentation-anthropic
|
|
|
684
686
|
### Example 1: Full Workflow with Span Management
|
|
685
687
|
|
|
686
688
|
```typescript
|
|
687
|
-
import {
|
|
689
|
+
import { RespanTelemetry, getClient } from '@respan/tracing';
|
|
688
690
|
import OpenAI from 'openai';
|
|
689
691
|
|
|
690
|
-
const kai = new
|
|
691
|
-
apiKey: process.env.
|
|
692
|
+
const kai = new RespanTelemetry({
|
|
693
|
+
apiKey: process.env.RESPAN_API_KEY,
|
|
692
694
|
appName: 'my-app',
|
|
693
695
|
resourceAttributes: {
|
|
694
696
|
environment: 'production',
|
|
@@ -704,7 +706,7 @@ await kai.withWorkflow({ name: 'process_user_request', version: 1 }, async () =>
|
|
|
704
706
|
|
|
705
707
|
// Set customer context
|
|
706
708
|
client.updateCurrentSpan({
|
|
707
|
-
|
|
709
|
+
respanParams: {
|
|
708
710
|
customerIdentifier: 'user-123',
|
|
709
711
|
traceGroupIdentifier: 'onboarding'
|
|
710
712
|
}
|
|
@@ -737,9 +739,9 @@ await kai.withWorkflow({ name: 'process_user_request', version: 1 }, async () =>
|
|
|
737
739
|
### Example 2: Backend Workflow with Span Buffering
|
|
738
740
|
|
|
739
741
|
```typescript
|
|
740
|
-
import {
|
|
742
|
+
import { RespanTelemetry } from '@respan/tracing';
|
|
741
743
|
|
|
742
|
-
const kai = new
|
|
744
|
+
const kai = new RespanTelemetry({ apiKey: 'your-key' });
|
|
743
745
|
const manager = kai.getSpanBufferManager();
|
|
744
746
|
|
|
745
747
|
// Ingest workflow results from backend
|
|
@@ -781,10 +783,10 @@ async function ingestWorkflow(workflowResult: any, orgId: string) {
|
|
|
781
783
|
### Example 3: Multi-Destination Routing
|
|
782
784
|
|
|
783
785
|
```typescript
|
|
784
|
-
import {
|
|
786
|
+
import { RespanTelemetry } from '@respan/tracing';
|
|
785
787
|
import { FileExporter, AnalyticsExporter } from './exporters';
|
|
786
788
|
|
|
787
|
-
const kai = new
|
|
789
|
+
const kai = new RespanTelemetry({ apiKey: 'your-key' });
|
|
788
790
|
|
|
789
791
|
// Add debug file exporter
|
|
790
792
|
kai.addProcessor({
|
|
@@ -799,10 +801,10 @@ kai.addProcessor({
|
|
|
799
801
|
filter: (span) => !span.name.includes('test')
|
|
800
802
|
});
|
|
801
803
|
|
|
802
|
-
// Route to default
|
|
804
|
+
// Route to default Respan processor
|
|
803
805
|
await kai.withTask(
|
|
804
806
|
{ name: 'production_task' },
|
|
805
|
-
async () => { /* goes to
|
|
807
|
+
async () => { /* goes to Respan */ }
|
|
806
808
|
);
|
|
807
809
|
|
|
808
810
|
// Route to debug processor
|
|
@@ -851,7 +853,7 @@ All new features are **backward compatible**. Existing code will continue to wor
|
|
|
851
853
|
|
|
852
854
|
To use new features, simply import and use them:
|
|
853
855
|
```typescript
|
|
854
|
-
import { getClient } from '@
|
|
856
|
+
import { getClient } from '@respan/tracing'; // New in v1.1.0
|
|
855
857
|
```
|
|
856
858
|
|
|
857
859
|
## License
|
package/dist/contexts/index.d.ts
CHANGED
package/dist/contexts/index.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/contexts/index.ts"],"names":[],"mappings":"AAAA,cAAc,WAAW,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/contexts/index.ts"],"names":[],"mappings":"AAAA,cAAc,WAAW,CAAC;AAC1B,cAAc,kBAAkB,CAAC"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import type { RespanParams } from "@respan/respan-sdk";
|
|
2
|
+
/**
|
|
3
|
+
* Run a function within a context that propagates Respan attributes to all
|
|
4
|
+
* spans created within its scope.
|
|
5
|
+
*
|
|
6
|
+
* Attributes are merged into every span at creation time via
|
|
7
|
+
* `RespanCompositeProcessor.onStart()`. Nested calls merge attributes
|
|
8
|
+
* (inner wins). Metadata dicts are merged, not replaced.
|
|
9
|
+
*
|
|
10
|
+
* @param attrs - Respan attributes to propagate (customer_identifier,
|
|
11
|
+
* thread_identifier, metadata, prompt, environment, etc.)
|
|
12
|
+
* @param fn - The function to execute within the propagation scope
|
|
13
|
+
* @returns The result of `fn`
|
|
14
|
+
*
|
|
15
|
+
* @example
|
|
16
|
+
* ```typescript
|
|
17
|
+
* await propagateAttributes(
|
|
18
|
+
* { customer_identifier: "user_123", thread_identifier: "conv_abc" },
|
|
19
|
+
* async () => {
|
|
20
|
+
* await Runner.run(agent, "Hello");
|
|
21
|
+
* }
|
|
22
|
+
* );
|
|
23
|
+
* ```
|
|
24
|
+
*/
|
|
25
|
+
export declare function propagateAttributes<T>(attrs: Partial<RespanParams>, fn: () => T): T;
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { context } from "@opentelemetry/api";
|
|
2
|
+
import { RESPAN_SPAN_ATTRIBUTES_MAP } from "@respan/respan-sdk";
|
|
3
|
+
import { PROPAGATED_ATTRIBUTES_KEY, getPropagatedAttributes, } from "../utils/context.js";
|
|
4
|
+
/**
|
|
5
|
+
* Run a function within a context that propagates Respan attributes to all
|
|
6
|
+
* spans created within its scope.
|
|
7
|
+
*
|
|
8
|
+
* Attributes are merged into every span at creation time via
|
|
9
|
+
* `RespanCompositeProcessor.onStart()`. Nested calls merge attributes
|
|
10
|
+
* (inner wins). Metadata dicts are merged, not replaced.
|
|
11
|
+
*
|
|
12
|
+
* @param attrs - Respan attributes to propagate (customer_identifier,
|
|
13
|
+
* thread_identifier, metadata, prompt, environment, etc.)
|
|
14
|
+
* @param fn - The function to execute within the propagation scope
|
|
15
|
+
* @returns The result of `fn`
|
|
16
|
+
*
|
|
17
|
+
* @example
|
|
18
|
+
* ```typescript
|
|
19
|
+
* await propagateAttributes(
|
|
20
|
+
* { customer_identifier: "user_123", thread_identifier: "conv_abc" },
|
|
21
|
+
* async () => {
|
|
22
|
+
* await Runner.run(agent, "Hello");
|
|
23
|
+
* }
|
|
24
|
+
* );
|
|
25
|
+
* ```
|
|
26
|
+
*/
|
|
27
|
+
export function propagateAttributes(attrs, fn) {
|
|
28
|
+
// Merge with any already-active attributes (supports nesting)
|
|
29
|
+
const parent = getPropagatedAttributes() ?? {};
|
|
30
|
+
const merged = { ...parent };
|
|
31
|
+
for (const [key, value] of Object.entries(attrs)) {
|
|
32
|
+
if (!(key in RESPAN_SPAN_ATTRIBUTES_MAP)) {
|
|
33
|
+
console.warn(`[Respan] Ignoring unsupported attribute: ${key}`);
|
|
34
|
+
continue;
|
|
35
|
+
}
|
|
36
|
+
if (key === "metadata" && typeof value === "object" && value !== null) {
|
|
37
|
+
// Merge metadata dicts instead of replacing
|
|
38
|
+
merged.metadata = { ...(merged.metadata ?? {}), ...value };
|
|
39
|
+
}
|
|
40
|
+
else {
|
|
41
|
+
merged[key] = value;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
const ctx = context.active().setValue(PROPAGATED_ATTRIBUTES_KEY, merged);
|
|
45
|
+
return context.with(ctx, fn);
|
|
46
|
+
}
|
|
47
|
+
//# sourceMappingURL=propagation.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"propagation.js","sourceRoot":"","sources":["../../src/contexts/propagation.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,oBAAoB,CAAC;AAC7C,OAAO,EAAE,0BAA0B,EAAE,MAAM,oBAAoB,CAAC;AAEhE,OAAO,EACL,yBAAyB,EACzB,uBAAuB,GACxB,MAAM,qBAAqB,CAAC;AAE7B;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,MAAM,UAAU,mBAAmB,CACjC,KAA4B,EAC5B,EAAW;IAEX,8DAA8D;IAC9D,MAAM,MAAM,GAAG,uBAAuB,EAAE,IAAI,EAAE,CAAC;IAC/C,MAAM,MAAM,GAA0B,EAAE,GAAG,MAAM,EAAE,CAAC;IAEpD,KAAK,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC;QACjD,IAAI,CAAC,CAAC,GAAG,IAAI,0BAA0B,CAAC,EAAE,CAAC;YACzC,OAAO,CAAC,IAAI,CAAC,4CAA4C,GAAG,EAAE,CAAC,CAAC;YAChE,SAAS;QACX,CAAC;QACD,IAAI,GAAG,KAAK,UAAU,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,KAAK,IAAI,EAAE,CAAC;YACtE,4CAA4C;YAC5C,MAAM,CAAC,QAAQ,GAAG,EAAE,GAAG,CAAC,MAAM,CAAC,QAAQ,IAAI,EAAE,CAAC,EAAE,GAAG,KAAK,EAAE,CAAC;QAC7D,CAAC;aAAM,CAAC;YACL,MAAc,CAAC,GAAG,CAAC,GAAG,KAAK,CAAC;QAC/B,CAAC;IACH,CAAC;IAED,MAAM,GAAG,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,yBAAyB,EAAE,MAAM,CAAC,CAAC;IACzE,OAAO,OAAO,CAAC,IAAI,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC;AAC/B,CAAC"}
|
|
@@ -1,5 +1,72 @@
|
|
|
1
1
|
import { SpanAttributes } from "@traceloop/ai-semantic-conventions";
|
|
2
|
-
import {
|
|
2
|
+
import { RESPAN_SPAN_ATTRIBUTES_MAP, RespanSpanAttributes, RespanLogType, } from "@respan/respan-sdk";
|
|
3
|
+
import { getEntityPath, getPropagatedAttributes } from "../utils/context.js";
|
|
4
|
+
// ── OpenInference span enrichment ──────────────────────────────────────────
|
|
5
|
+
/** Map OI span kinds → Traceloop span kinds */
|
|
6
|
+
const OI_KIND_TO_TRACELOOP = {
|
|
7
|
+
LLM: RespanLogType.TASK,
|
|
8
|
+
CHAIN: RespanLogType.WORKFLOW,
|
|
9
|
+
TOOL: RespanLogType.TOOL,
|
|
10
|
+
AGENT: RespanLogType.AGENT,
|
|
11
|
+
EMBEDDING: RespanLogType.TASK,
|
|
12
|
+
RETRIEVER: RespanLogType.TASK,
|
|
13
|
+
RERANKER: RespanLogType.TASK,
|
|
14
|
+
GUARDRAIL: RespanLogType.TASK,
|
|
15
|
+
EVALUATOR: RespanLogType.TASK,
|
|
16
|
+
};
|
|
17
|
+
/** OI span kinds that imply an LLM request type */
|
|
18
|
+
const OI_LLM_REQUEST_KINDS = {
|
|
19
|
+
LLM: RespanLogType.CHAT,
|
|
20
|
+
EMBEDDING: RespanLogType.EMBEDDING,
|
|
21
|
+
};
|
|
22
|
+
/** Map OI span kinds → respan.entity.log_type values */
|
|
23
|
+
const OI_LOG_TYPE = {
|
|
24
|
+
LLM: RespanLogType.CHAT,
|
|
25
|
+
CHAIN: RespanLogType.WORKFLOW,
|
|
26
|
+
TOOL: RespanLogType.TOOL,
|
|
27
|
+
AGENT: RespanLogType.AGENT,
|
|
28
|
+
EMBEDDING: RespanLogType.EMBEDDING,
|
|
29
|
+
RETRIEVER: RespanLogType.TASK,
|
|
30
|
+
RERANKER: RespanLogType.TASK,
|
|
31
|
+
GUARDRAIL: RespanLogType.GUARDRAIL,
|
|
32
|
+
EVALUATOR: RespanLogType.TASK,
|
|
33
|
+
};
|
|
34
|
+
/**
|
|
35
|
+
* Build Traceloop/GenAI enrichment attributes for an OpenInference span.
|
|
36
|
+
* Returns only the attributes that need to be *added*; callers merge them
|
|
37
|
+
* on top of the original span attributes.
|
|
38
|
+
*/
|
|
39
|
+
function getOIEnrichmentAttrs(span) {
|
|
40
|
+
const attrs = {};
|
|
41
|
+
const oiKind = String(span.attributes[RespanSpanAttributes.OPENINFERENCE_SPAN_KIND] ?? "");
|
|
42
|
+
if (OI_KIND_TO_TRACELOOP[oiKind]) {
|
|
43
|
+
attrs[SpanAttributes.TRACELOOP_SPAN_KIND] = OI_KIND_TO_TRACELOOP[oiKind];
|
|
44
|
+
}
|
|
45
|
+
if (OI_LLM_REQUEST_KINDS[oiKind]) {
|
|
46
|
+
attrs[RespanSpanAttributes.LLM_REQUEST_TYPE] = OI_LLM_REQUEST_KINDS[oiKind];
|
|
47
|
+
}
|
|
48
|
+
if (OI_LOG_TYPE[oiKind]) {
|
|
49
|
+
attrs[RespanSpanAttributes.RESPAN_LOG_TYPE] = OI_LOG_TYPE[oiKind];
|
|
50
|
+
}
|
|
51
|
+
// Bridge OI semantic attrs → Traceloop/GenAI equivalents
|
|
52
|
+
if (span.attributes["input.value"] !== undefined)
|
|
53
|
+
attrs[SpanAttributes.TRACELOOP_ENTITY_INPUT] = span.attributes["input.value"];
|
|
54
|
+
if (span.attributes["output.value"] !== undefined)
|
|
55
|
+
attrs[SpanAttributes.TRACELOOP_ENTITY_OUTPUT] = span.attributes["output.value"];
|
|
56
|
+
if (span.attributes["llm.model_name"] !== undefined)
|
|
57
|
+
attrs[RespanSpanAttributes.GEN_AI_REQUEST_MODEL] = span.attributes["llm.model_name"];
|
|
58
|
+
if (span.attributes["llm.token_count.prompt"] !== undefined)
|
|
59
|
+
attrs[RespanSpanAttributes.GEN_AI_USAGE_PROMPT_TOKENS] = span.attributes["llm.token_count.prompt"];
|
|
60
|
+
if (span.attributes["llm.token_count.completion"] !== undefined)
|
|
61
|
+
attrs[RespanSpanAttributes.GEN_AI_USAGE_COMPLETION_TOKENS] = span.attributes["llm.token_count.completion"];
|
|
62
|
+
// Entity name / path
|
|
63
|
+
attrs[SpanAttributes.TRACELOOP_ENTITY_NAME] = span.name;
|
|
64
|
+
if (OI_KIND_TO_TRACELOOP[oiKind] !== "workflow") {
|
|
65
|
+
attrs[SpanAttributes.TRACELOOP_ENTITY_PATH] = span.name;
|
|
66
|
+
}
|
|
67
|
+
return attrs;
|
|
68
|
+
}
|
|
69
|
+
// ── Composite processor ────────────────────────────────────────────────────
|
|
3
70
|
/**
|
|
4
71
|
* Composite processor that combines filtering with multi-processor routing.
|
|
5
72
|
*
|
|
@@ -28,6 +95,28 @@ export class RespanCompositeProcessor {
|
|
|
28
95
|
// We need to cast to any to set attributes during onStart
|
|
29
96
|
span.setAttribute(SpanAttributes.TRACELOOP_ENTITY_PATH, entityPath);
|
|
30
97
|
}
|
|
98
|
+
// Apply propagated attributes (customer_identifier, thread_identifier, etc.)
|
|
99
|
+
const propagated = getPropagatedAttributes(parentContext);
|
|
100
|
+
if (propagated) {
|
|
101
|
+
for (const [key, value] of Object.entries(propagated)) {
|
|
102
|
+
if (value === undefined || value === null)
|
|
103
|
+
continue;
|
|
104
|
+
const attrKey = RESPAN_SPAN_ATTRIBUTES_MAP[key];
|
|
105
|
+
if (!attrKey)
|
|
106
|
+
continue;
|
|
107
|
+
if (key === "metadata" && typeof value === "object") {
|
|
108
|
+
for (const [mk, mv] of Object.entries(value)) {
|
|
109
|
+
span.setAttribute(`${RespanSpanAttributes.RESPAN_METADATA}.${mk}`, typeof mv === "string" ? mv : JSON.stringify(mv));
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
else if (key === "prompt" && typeof value === "object") {
|
|
113
|
+
span.setAttribute(attrKey, JSON.stringify(value));
|
|
114
|
+
}
|
|
115
|
+
else {
|
|
116
|
+
span.setAttribute(attrKey, value);
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
}
|
|
31
120
|
// Forward to processor manager
|
|
32
121
|
this._processorManager.onStart(span, parentContext);
|
|
33
122
|
}
|
|
@@ -45,8 +134,8 @@ export class RespanCompositeProcessor {
|
|
|
45
134
|
}
|
|
46
135
|
// Check if this is an LLM instrumentation span (OpenAI, Anthropic, etc.)
|
|
47
136
|
// These have gen_ai.* or llm.* attributes
|
|
48
|
-
const isLLMSpan = span.attributes[
|
|
49
|
-
span.attributes[
|
|
137
|
+
const isLLMSpan = span.attributes[RespanSpanAttributes.GEN_AI_SYSTEM] !== undefined ||
|
|
138
|
+
span.attributes[RespanSpanAttributes.LLM_SYSTEM] !== undefined ||
|
|
50
139
|
span.attributes['gen_ai.request.model'] !== undefined ||
|
|
51
140
|
span.name.includes('anthropic.messages') ||
|
|
52
141
|
span.name.includes('openai.chat') ||
|
|
@@ -81,6 +170,25 @@ export class RespanCompositeProcessor {
|
|
|
81
170
|
// Route to processors
|
|
82
171
|
this._processorManager.onEnd(span);
|
|
83
172
|
}
|
|
173
|
+
else if (span.attributes[RespanSpanAttributes.OPENINFERENCE_SPAN_KIND] !== undefined) {
|
|
174
|
+
// OpenInference span — enrich with Traceloop/GenAI attrs, then route
|
|
175
|
+
console.debug(`[Respan Debug] Processing OpenInference span: ${span.name} (kind: ${span.attributes[RespanSpanAttributes.OPENINFERENCE_SPAN_KIND]})`);
|
|
176
|
+
const enrichmentAttrs = getOIEnrichmentAttrs(span);
|
|
177
|
+
const enrichedSpan = Object.create(Object.getPrototypeOf(span));
|
|
178
|
+
Object.assign(enrichedSpan, span);
|
|
179
|
+
Object.defineProperty(enrichedSpan, "attributes", {
|
|
180
|
+
value: { ...span.attributes, ...enrichmentAttrs },
|
|
181
|
+
writable: false,
|
|
182
|
+
configurable: true,
|
|
183
|
+
enumerable: true,
|
|
184
|
+
});
|
|
185
|
+
this._processorManager.onEnd(enrichedSpan);
|
|
186
|
+
}
|
|
187
|
+
else if (span.attributes[RespanSpanAttributes.RESPAN_LOG_TYPE] !== undefined) {
|
|
188
|
+
// Enriched Respan span (from an instrumentation plugin)
|
|
189
|
+
console.debug(`[Respan Debug] Processing enriched Respan span: ${span.name}`);
|
|
190
|
+
this._processorManager.onEnd(span);
|
|
191
|
+
}
|
|
84
192
|
else {
|
|
85
193
|
// This span has none of the above - it's pure auto-instrumentation noise (HTTP calls, etc.)
|
|
86
194
|
console.debug(`[Respan Debug] Filtering out auto-instrumentation span: ${span.name}`);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"composite.js","sourceRoot":"","sources":["../../src/processor/composite.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,cAAc,EAAE,MAAM,oCAAoC,CAAC;
|
|
1
|
+
{"version":3,"file":"composite.js","sourceRoot":"","sources":["../../src/processor/composite.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Batch API result logging utilities.
|
|
3
|
+
*
|
|
4
|
+
* Logs OpenAI Batch API results as individual chat completion spans
|
|
5
|
+
* injected into the OTEL pipeline.
|
|
6
|
+
*/
|
|
7
|
+
export interface BatchRequest {
|
|
8
|
+
custom_id: string;
|
|
9
|
+
body?: {
|
|
10
|
+
messages?: any[];
|
|
11
|
+
model?: string;
|
|
12
|
+
[key: string]: any;
|
|
13
|
+
};
|
|
14
|
+
[key: string]: any;
|
|
15
|
+
}
|
|
16
|
+
export interface BatchResult {
|
|
17
|
+
custom_id: string;
|
|
18
|
+
response?: {
|
|
19
|
+
status_code?: number;
|
|
20
|
+
body?: {
|
|
21
|
+
choices?: Array<{
|
|
22
|
+
message?: any;
|
|
23
|
+
[key: string]: any;
|
|
24
|
+
}>;
|
|
25
|
+
usage?: {
|
|
26
|
+
prompt_tokens?: number;
|
|
27
|
+
completion_tokens?: number;
|
|
28
|
+
};
|
|
29
|
+
model?: string;
|
|
30
|
+
created?: number;
|
|
31
|
+
[key: string]: any;
|
|
32
|
+
};
|
|
33
|
+
[key: string]: any;
|
|
34
|
+
};
|
|
35
|
+
[key: string]: any;
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Log OpenAI Batch API results as individual chat completion spans.
|
|
39
|
+
*
|
|
40
|
+
* Trace linking (in priority order):
|
|
41
|
+
* 1. OTEL context — when called inside a `withTask` / `withWorkflow`,
|
|
42
|
+
* auto-links to the active trace.
|
|
43
|
+
* 2. Explicit `traceId` — for async batches where results arrive later.
|
|
44
|
+
* 3. Auto-generated — creates a new standalone trace.
|
|
45
|
+
*/
|
|
46
|
+
export declare function logBatchResults(requests: BatchRequest[], results: BatchResult[], traceId?: string): void;
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Batch API result logging utilities.
|
|
3
|
+
*
|
|
4
|
+
* Logs OpenAI Batch API results as individual chat completion spans
|
|
5
|
+
* injected into the OTEL pipeline.
|
|
6
|
+
*/
|
|
7
|
+
import { SpanAttributes } from "@traceloop/ai-semantic-conventions";
|
|
8
|
+
import { RespanSpanAttributes } from "@respan/respan-sdk";
|
|
9
|
+
import { buildReadableSpan, injectSpan, ensureSpanId } from "./spanFactory.js";
|
|
10
|
+
import { getClient } from "./client.js";
|
|
11
|
+
/**
|
|
12
|
+
* Log OpenAI Batch API results as individual chat completion spans.
|
|
13
|
+
*
|
|
14
|
+
* Trace linking (in priority order):
|
|
15
|
+
* 1. OTEL context — when called inside a `withTask` / `withWorkflow`,
|
|
16
|
+
* auto-links to the active trace.
|
|
17
|
+
* 2. Explicit `traceId` — for async batches where results arrive later.
|
|
18
|
+
* 3. Auto-generated — creates a new standalone trace.
|
|
19
|
+
*/
|
|
20
|
+
export function logBatchResults(requests, results, traceId) {
|
|
21
|
+
const client = getClient();
|
|
22
|
+
// Resolve trace context: OTEL > explicit > auto-generated.
|
|
23
|
+
let otelTraceId = client.getCurrentTraceId();
|
|
24
|
+
let otelSpanId = client.getCurrentSpanId();
|
|
25
|
+
if (otelTraceId && /^0+$/.test(otelTraceId))
|
|
26
|
+
otelTraceId = undefined;
|
|
27
|
+
if (otelSpanId && /^0+$/.test(otelSpanId))
|
|
28
|
+
otelSpanId = undefined;
|
|
29
|
+
const resolvedTraceId = otelTraceId ?? traceId ?? undefined;
|
|
30
|
+
const parentSpanId = otelSpanId ?? undefined;
|
|
31
|
+
// Index requests by custom_id
|
|
32
|
+
const requestsById = new Map();
|
|
33
|
+
for (const req of requests) {
|
|
34
|
+
requestsById.set(req.custom_id, req.body ?? {});
|
|
35
|
+
}
|
|
36
|
+
// When no OTEL context, create a grouping span so completions are nested
|
|
37
|
+
let groupSpanId;
|
|
38
|
+
if (!otelSpanId) {
|
|
39
|
+
groupSpanId = ensureSpanId();
|
|
40
|
+
}
|
|
41
|
+
const completionTimestamps = [];
|
|
42
|
+
for (const result of results) {
|
|
43
|
+
const customId = result.custom_id ?? "";
|
|
44
|
+
const response = result.response ?? {};
|
|
45
|
+
const body = response.body ?? {};
|
|
46
|
+
const statusCode = response.status_code ?? 200;
|
|
47
|
+
const original = requestsById.get(customId) ?? {};
|
|
48
|
+
const messages = original.messages ?? [];
|
|
49
|
+
const choices = body.choices ?? [{}];
|
|
50
|
+
const output = choices[0]?.message ?? {};
|
|
51
|
+
const usage = body.usage ?? {};
|
|
52
|
+
// Extract timestamp
|
|
53
|
+
const created = body.created;
|
|
54
|
+
let endTimeIso;
|
|
55
|
+
if (created) {
|
|
56
|
+
const ts = new Date(created * 1000);
|
|
57
|
+
endTimeIso = ts.toISOString();
|
|
58
|
+
completionTimestamps.push(ts);
|
|
59
|
+
}
|
|
60
|
+
const model = body.model ?? original.model ?? "";
|
|
61
|
+
const span = buildReadableSpan({
|
|
62
|
+
name: `batch:${customId}`,
|
|
63
|
+
traceId: resolvedTraceId,
|
|
64
|
+
parentId: groupSpanId ?? parentSpanId,
|
|
65
|
+
endTimeIso,
|
|
66
|
+
attributes: {
|
|
67
|
+
"llm.request.type": "chat",
|
|
68
|
+
"gen_ai.request.model": model,
|
|
69
|
+
"gen_ai.usage.prompt_tokens": usage.prompt_tokens ?? 0,
|
|
70
|
+
"gen_ai.usage.completion_tokens": usage.completion_tokens ?? 0,
|
|
71
|
+
[SpanAttributes.TRACELOOP_ENTITY_INPUT]: JSON.stringify(messages),
|
|
72
|
+
[SpanAttributes.TRACELOOP_ENTITY_OUTPUT]: JSON.stringify(output),
|
|
73
|
+
[SpanAttributes.TRACELOOP_ENTITY_PATH]: "batch_results",
|
|
74
|
+
[SpanAttributes.TRACELOOP_SPAN_KIND]: "task",
|
|
75
|
+
[RespanSpanAttributes.RESPAN_LOG_TYPE]: "chat",
|
|
76
|
+
},
|
|
77
|
+
statusCode,
|
|
78
|
+
});
|
|
79
|
+
injectSpan(span);
|
|
80
|
+
}
|
|
81
|
+
// Create the grouping "batch_results" task span (when no OTEL context)
|
|
82
|
+
if (groupSpanId) {
|
|
83
|
+
let earliestIso;
|
|
84
|
+
let latestIso;
|
|
85
|
+
if (completionTimestamps.length > 0) {
|
|
86
|
+
completionTimestamps.sort((a, b) => a.getTime() - b.getTime());
|
|
87
|
+
earliestIso = completionTimestamps[0].toISOString();
|
|
88
|
+
latestIso =
|
|
89
|
+
completionTimestamps[completionTimestamps.length - 1].toISOString();
|
|
90
|
+
}
|
|
91
|
+
const parentSpan = buildReadableSpan({
|
|
92
|
+
name: "batch_results.task",
|
|
93
|
+
traceId: resolvedTraceId,
|
|
94
|
+
spanId: groupSpanId,
|
|
95
|
+
startTimeIso: earliestIso,
|
|
96
|
+
endTimeIso: latestIso,
|
|
97
|
+
attributes: {
|
|
98
|
+
[SpanAttributes.TRACELOOP_SPAN_KIND]: "task",
|
|
99
|
+
[SpanAttributes.TRACELOOP_ENTITY_NAME]: "batch_results",
|
|
100
|
+
[SpanAttributes.TRACELOOP_ENTITY_PATH]: "",
|
|
101
|
+
[RespanSpanAttributes.RESPAN_LOG_TYPE]: "task",
|
|
102
|
+
},
|
|
103
|
+
});
|
|
104
|
+
injectSpan(parentSpan);
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
//# sourceMappingURL=batchLogging.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"batchLogging.js","sourceRoot":"","sources":["../../src/utils/batchLogging.ts"],"names":[],"mappings":"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"}
|
package/dist/utils/context.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { Context } from "@opentelemetry/api";
|
|
2
|
+
import { RespanParams } from "@respan/respan-sdk";
|
|
2
3
|
/**
|
|
3
4
|
* Context Keys: Type-safe identifiers for storing values in OpenTelemetry context
|
|
4
5
|
*
|
|
@@ -19,6 +20,11 @@ export declare const ASSOCIATION_PROPERTIES_KEY: symbol;
|
|
|
19
20
|
* @returns The entity path string or undefined if not set
|
|
20
21
|
*/
|
|
21
22
|
export declare const getEntityPath: (ctx?: Context) => string | undefined;
|
|
23
|
+
export declare const PROPAGATED_ATTRIBUTES_KEY: symbol;
|
|
24
|
+
/**
|
|
25
|
+
* Get propagated attributes from the given context.
|
|
26
|
+
*/
|
|
27
|
+
export declare const getPropagatedAttributes: (ctx?: Context) => Partial<RespanParams> | undefined;
|
|
22
28
|
/**
|
|
23
29
|
* Determines whether trace content (input/output data) should be captured.
|
|
24
30
|
* This can be controlled via environment variable for security/privacy.
|
package/dist/utils/context.js
CHANGED
|
@@ -32,6 +32,15 @@ export const getEntityPath = (ctx = context.active()) => {
|
|
|
32
32
|
const workflowName = ctx.getValue(WORKFLOW_NAME_KEY);
|
|
33
33
|
return workflowName;
|
|
34
34
|
};
|
|
35
|
+
// Stores propagated Respan attributes (customer_identifier, thread_identifier, etc.)
|
|
36
|
+
// These are merged onto every span created within the context scope.
|
|
37
|
+
export const PROPAGATED_ATTRIBUTES_KEY = createContextKey("respan.propagated_attributes");
|
|
38
|
+
/**
|
|
39
|
+
* Get propagated attributes from the given context.
|
|
40
|
+
*/
|
|
41
|
+
export const getPropagatedAttributes = (ctx = context.active()) => {
|
|
42
|
+
return ctx.getValue(PROPAGATED_ATTRIBUTES_KEY);
|
|
43
|
+
};
|
|
35
44
|
/**
|
|
36
45
|
* Determines whether trace content (input/output data) should be captured.
|
|
37
46
|
* This can be controlled via environment variable for security/privacy.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"context.js","sourceRoot":"","sources":["../../src/utils/context.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAW,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AACxE,OAAO,EAAE,cAAc,EAAE,MAAM,oCAAoC,CAAC;
|
|
1
|
+
{"version":3,"file":"context.js","sourceRoot":"","sources":["../../src/utils/context.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAW,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AACxE,OAAO,EAAE,cAAc,EAAE,MAAM,oCAAoC,CAAC;AAGpE;;;;;;;;GAQG;AAEH,gEAAgE;AAChE,MAAM,CAAC,MAAM,iBAAiB,GAAG,gBAAgB,CAC/C,cAAc,CAAC,uBAAuB,CACvC,CAAC;AAEF,qFAAqF;AACrF,MAAM,CAAC,MAAM,eAAe,GAAG,gBAAgB,CAC7C,cAAc,CAAC,qBAAqB,CACrC,CAAC;AAEF,yDAAyD;AACzD,MAAM,CAAC,MAAM,0BAA0B,GAAG,gBAAgB,CACxD,cAAc,CAAC,gCAAgC,CAChD,CAAC;AAEF;;;;;;GAMG;AACH,MAAM,CAAC,MAAM,aAAa,GAAG,CAAC,GAAG,GAAG,OAAO,CAAC,MAAM,EAAE,EAAsB,EAAE;IAC1E,4DAA4D;IAC5D,MAAM,UAAU,GAAG,GAAG,CAAC,QAAQ,CAAC,eAAe,CAAuB,CAAC;IACvE,IAAI,UAAU,EAAE,CAAC;QACf,OAAO,UAAU,CAAC;IACpB,CAAC;IAED,2DAA2D;IAC3D,MAAM,YAAY,GAAG,GAAG,CAAC,QAAQ,CAAC,iBAAiB,CAAuB,CAAC;IAC3E,OAAO,YAAY,CAAC;AACtB,CAAC,CAAC;AAEF,qFAAqF;AACrF,qEAAqE;AACrE,MAAM,CAAC,MAAM,yBAAyB,GAAG,gBAAgB,CACvD,8BAA8B,CAC/B,CAAC;AAEF;;GAEG;AACH,MAAM,CAAC,MAAM,uBAAuB,GAAG,CACrC,MAAe,OAAO,CAAC,MAAM,EAAE,EACI,EAAE;IACrC,OAAO,GAAG,CAAC,QAAQ,CAAC,yBAAyB,CAEhC,CAAC;AAChB,CAAC,CAAC;AAEF;;;;;GAKG;AACH,MAAM,CAAC,MAAM,gBAAgB,GAAG,GAAY,EAAE;IAC5C,OAAO,OAAO,CAAC,GAAG,CAAC,oBAAoB,KAAK,OAAO,CAAC;AACtD,CAAC,CAAC"}
|
package/dist/utils/index.d.ts
CHANGED
package/dist/utils/index.js
CHANGED
package/dist/utils/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/utils/index.ts"],"names":[],"mappings":"AAAA,cAAc,cAAc,CAAC;AAC7B,cAAc,WAAW,CAAC;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/utils/index.ts"],"names":[],"mappings":"AAAA,cAAc,cAAc,CAAC;AAC7B,cAAc,WAAW,CAAC;AAC1B,cAAc,kBAAkB,CAAC;AAEjC,kDAAkD;AAClD,OAAO,EAAE,YAAY,EAAE,UAAU,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AAEzE,gCAAgC;AAChC,cAAc,aAAa,CAAC;AAC5B,cAAc,iBAAiB,CAAC"}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared utilities for constructing and injecting ReadableSpan objects.
|
|
3
|
+
*
|
|
4
|
+
* Used by the `Respan` unified entry point (e.g. `logBatchResults`) and
|
|
5
|
+
* instrumentation plugins to emit spans into the OTEL pipeline without
|
|
6
|
+
* going through a live tracer context.
|
|
7
|
+
*/
|
|
8
|
+
import type { ReadableSpan } from "@opentelemetry/sdk-trace-base";
|
|
9
|
+
export declare function ensureTraceId(id?: string): string;
|
|
10
|
+
export declare function ensureSpanId(id?: string): string;
|
|
11
|
+
export declare function parseISOToHrTime(iso: string | undefined): [number, number] | null;
|
|
12
|
+
export interface BuildSpanOptions {
|
|
13
|
+
name: string;
|
|
14
|
+
traceId?: string;
|
|
15
|
+
spanId?: string;
|
|
16
|
+
parentId?: string;
|
|
17
|
+
startTimeIso?: string;
|
|
18
|
+
endTimeIso?: string;
|
|
19
|
+
startTimeHr?: [number, number] | null;
|
|
20
|
+
endTimeHr?: [number, number] | null;
|
|
21
|
+
attributes: Record<string, any>;
|
|
22
|
+
statusCode?: number;
|
|
23
|
+
errorMessage?: string;
|
|
24
|
+
/** Merge propagated attributes from context. Default: true (matches Python). */
|
|
25
|
+
mergePropagated?: boolean;
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Construct a ReadableSpan-compatible object with explicit IDs and attributes.
|
|
29
|
+
*/
|
|
30
|
+
export declare function buildReadableSpan(opts: BuildSpanOptions): ReadableSpan;
|
|
31
|
+
/**
|
|
32
|
+
* Push a ReadableSpan through the active TracerProvider's processor chain.
|
|
33
|
+
*
|
|
34
|
+
* Returns true on success, false if no processor is available.
|
|
35
|
+
*/
|
|
36
|
+
export declare function injectSpan(span: ReadableSpan): boolean;
|
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared utilities for constructing and injecting ReadableSpan objects.
|
|
3
|
+
*
|
|
4
|
+
* Used by the `Respan` unified entry point (e.g. `logBatchResults`) and
|
|
5
|
+
* instrumentation plugins to emit spans into the OTEL pipeline without
|
|
6
|
+
* going through a live tracer context.
|
|
7
|
+
*/
|
|
8
|
+
import { trace, SpanKind, SpanStatusCode } from "@opentelemetry/api";
|
|
9
|
+
import { hrTime, hrTimeDuration } from "@opentelemetry/core";
|
|
10
|
+
import { RESPAN_SPAN_ATTRIBUTES_MAP, RespanSpanAttributes } from "@respan/respan-sdk";
|
|
11
|
+
import { RESPAN_PACKAGE_NAME } from "../constants/index.js";
|
|
12
|
+
import { getPropagatedAttributes } from "./context.js";
|
|
13
|
+
// ── ID helpers ──────────────────────────────────────────────────────────────
|
|
14
|
+
function hashStringToHexId(s, length) {
|
|
15
|
+
let hash = 0;
|
|
16
|
+
for (let i = 0; i < s.length; i++) {
|
|
17
|
+
hash = ((hash << 5) - hash + s.charCodeAt(i)) | 0;
|
|
18
|
+
}
|
|
19
|
+
const hex = Math.abs(hash).toString(16).padStart(8, "0");
|
|
20
|
+
return (hex + hex + hex + hex).slice(0, length);
|
|
21
|
+
}
|
|
22
|
+
function generateHexId(length) {
|
|
23
|
+
return Array.from({ length }, () => Math.floor(Math.random() * 16).toString(16)).join("");
|
|
24
|
+
}
|
|
25
|
+
export function ensureTraceId(id) {
|
|
26
|
+
if (!id)
|
|
27
|
+
return generateHexId(32);
|
|
28
|
+
if (/^[0-9a-f]{32}$/i.test(id))
|
|
29
|
+
return id.toLowerCase();
|
|
30
|
+
return hashStringToHexId(id, 32);
|
|
31
|
+
}
|
|
32
|
+
export function ensureSpanId(id) {
|
|
33
|
+
if (!id)
|
|
34
|
+
return generateHexId(16);
|
|
35
|
+
if (/^[0-9a-f]{16}$/i.test(id))
|
|
36
|
+
return id.toLowerCase();
|
|
37
|
+
return hashStringToHexId(id, 16);
|
|
38
|
+
}
|
|
39
|
+
// ── Timestamp helpers ───────────────────────────────────────────────────────
|
|
40
|
+
export function parseISOToHrTime(iso) {
|
|
41
|
+
if (!iso)
|
|
42
|
+
return null;
|
|
43
|
+
try {
|
|
44
|
+
const ms = new Date(iso).getTime();
|
|
45
|
+
const secs = Math.floor(ms / 1000);
|
|
46
|
+
const nanos = (ms % 1000) * 1_000_000;
|
|
47
|
+
return [secs, nanos];
|
|
48
|
+
}
|
|
49
|
+
catch {
|
|
50
|
+
return null;
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Construct a ReadableSpan-compatible object with explicit IDs and attributes.
|
|
55
|
+
*/
|
|
56
|
+
export function buildReadableSpan(opts) {
|
|
57
|
+
const startTime = opts.startTimeHr ??
|
|
58
|
+
parseISOToHrTime(opts.startTimeIso) ??
|
|
59
|
+
hrTime();
|
|
60
|
+
const endTime = opts.endTimeHr ??
|
|
61
|
+
parseISOToHrTime(opts.endTimeIso) ??
|
|
62
|
+
hrTime();
|
|
63
|
+
const traceId = ensureTraceId(opts.traceId);
|
|
64
|
+
const spanId = ensureSpanId(opts.spanId);
|
|
65
|
+
const parentSpanId = opts.parentId
|
|
66
|
+
? ensureSpanId(opts.parentId)
|
|
67
|
+
: undefined;
|
|
68
|
+
// Merge propagated attributes (customer_identifier, thread_id, etc.)
|
|
69
|
+
// Matches Python's merge_propagated=True default in build_readable_span()
|
|
70
|
+
const attrs = { ...opts.attributes };
|
|
71
|
+
if (opts.mergePropagated !== false) {
|
|
72
|
+
const propagated = getPropagatedAttributes();
|
|
73
|
+
if (propagated) {
|
|
74
|
+
for (const [key, value] of Object.entries(propagated)) {
|
|
75
|
+
if (value === undefined || value === null)
|
|
76
|
+
continue;
|
|
77
|
+
const attrKey = RESPAN_SPAN_ATTRIBUTES_MAP[key];
|
|
78
|
+
if (!attrKey)
|
|
79
|
+
continue;
|
|
80
|
+
// Only set if not already present (caller attrs take precedence)
|
|
81
|
+
if (attrs[attrKey] !== undefined)
|
|
82
|
+
continue;
|
|
83
|
+
if (key === "metadata" && typeof value === "object") {
|
|
84
|
+
for (const [mk, mv] of Object.entries(value)) {
|
|
85
|
+
const fullKey = `${RespanSpanAttributes.RESPAN_METADATA}.${mk}`;
|
|
86
|
+
if (attrs[fullKey] === undefined) {
|
|
87
|
+
attrs[fullKey] = typeof mv === "string" ? mv : JSON.stringify(mv);
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
else if (key === "prompt" && typeof value === "object") {
|
|
92
|
+
attrs[attrKey] = JSON.stringify(value);
|
|
93
|
+
}
|
|
94
|
+
else {
|
|
95
|
+
attrs[attrKey] = value;
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
const status = opts.errorMessage
|
|
101
|
+
? { code: SpanStatusCode.ERROR, message: opts.errorMessage }
|
|
102
|
+
: opts.statusCode && opts.statusCode >= 400
|
|
103
|
+
? { code: SpanStatusCode.ERROR, message: `HTTP ${opts.statusCode}` }
|
|
104
|
+
: { code: SpanStatusCode.OK, message: "" };
|
|
105
|
+
return {
|
|
106
|
+
name: opts.name,
|
|
107
|
+
kind: SpanKind.INTERNAL,
|
|
108
|
+
spanContext: () => ({
|
|
109
|
+
traceId,
|
|
110
|
+
spanId,
|
|
111
|
+
traceFlags: 1,
|
|
112
|
+
isRemote: false,
|
|
113
|
+
}),
|
|
114
|
+
parentSpanId,
|
|
115
|
+
startTime,
|
|
116
|
+
endTime,
|
|
117
|
+
duration: hrTimeDuration(startTime, endTime),
|
|
118
|
+
status,
|
|
119
|
+
attributes: attrs,
|
|
120
|
+
links: [],
|
|
121
|
+
events: [],
|
|
122
|
+
resource: { attributes: {} },
|
|
123
|
+
instrumentationLibrary: {
|
|
124
|
+
name: RESPAN_PACKAGE_NAME,
|
|
125
|
+
version: "1.0.0",
|
|
126
|
+
},
|
|
127
|
+
ended: true,
|
|
128
|
+
droppedAttributesCount: 0,
|
|
129
|
+
droppedEventsCount: 0,
|
|
130
|
+
droppedLinksCount: 0,
|
|
131
|
+
};
|
|
132
|
+
}
|
|
133
|
+
// ── Inject into OTEL pipeline ───────────────────────────────────────────────
|
|
134
|
+
/**
|
|
135
|
+
* Push a ReadableSpan through the active TracerProvider's processor chain.
|
|
136
|
+
*
|
|
137
|
+
* Returns true on success, false if no processor is available.
|
|
138
|
+
*/
|
|
139
|
+
export function injectSpan(span) {
|
|
140
|
+
const tp = trace.getTracerProvider();
|
|
141
|
+
const processor = tp?.activeSpanProcessor ?? tp?._delegate?.activeSpanProcessor;
|
|
142
|
+
if (processor && typeof processor.onEnd === "function") {
|
|
143
|
+
processor.onEnd(span);
|
|
144
|
+
return true;
|
|
145
|
+
}
|
|
146
|
+
return false;
|
|
147
|
+
}
|
|
148
|
+
//# sourceMappingURL=spanFactory.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"spanFactory.js","sourceRoot":"","sources":["../../src/utils/spanFactory.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@respan/tracing",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "1.0
|
|
5
|
-
"description": "
|
|
4
|
+
"version": "1.1.0",
|
|
5
|
+
"description": "OpenTelemetry-based tracing SDK for LLM applications",
|
|
6
6
|
"main": "dist/index.js",
|
|
7
7
|
"types": "dist/index.d.ts",
|
|
8
8
|
"files": [
|