@mastra/datadog 1.0.22 → 1.1.0-alpha.1
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/CHANGELOG.md +46 -0
- package/dist/bridge.d.ts +120 -0
- package/dist/bridge.d.ts.map +1 -0
- package/dist/index.cjs +454 -27
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +13 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +454 -28
- package/dist/index.js.map +1 -1
- package/dist/tracing.d.ts.map +1 -1
- package/package.json +4 -4
package/dist/index.js
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { SpanType } from '@mastra/core/observability';
|
|
2
2
|
import { omitKeys } from '@mastra/core/utils';
|
|
3
|
-
import { BaseExporter } from '@mastra/observability';
|
|
4
|
-
import
|
|
3
|
+
import { BaseExporter, getExternalParentId } from '@mastra/observability';
|
|
4
|
+
import tracer3 from 'dd-trace';
|
|
5
5
|
|
|
6
|
-
// src/
|
|
6
|
+
// src/bridge.ts
|
|
7
7
|
|
|
8
8
|
// src/metrics.ts
|
|
9
9
|
function formatUsageMetrics(usage) {
|
|
@@ -50,16 +50,16 @@ function ensureTracer(config) {
|
|
|
50
50
|
if (config.apiKey) {
|
|
51
51
|
process.env.DD_API_KEY = config.apiKey;
|
|
52
52
|
}
|
|
53
|
-
const alreadyStarted =
|
|
53
|
+
const alreadyStarted = tracer3._tracer?.started;
|
|
54
54
|
if (!alreadyStarted) {
|
|
55
|
-
|
|
55
|
+
tracer3.init({
|
|
56
56
|
service: config.service || config.mlApp,
|
|
57
57
|
env: config.env || process.env.DD_ENV,
|
|
58
58
|
// Disable automatic integrations by default to avoid surprise instrumentation
|
|
59
59
|
plugins: config.integrationsEnabled ?? false
|
|
60
60
|
});
|
|
61
61
|
}
|
|
62
|
-
|
|
62
|
+
tracer3.llmobs.enable({
|
|
63
63
|
mlApp: config.mlApp,
|
|
64
64
|
agentlessEnabled: config.agentless
|
|
65
65
|
});
|
|
@@ -136,7 +136,440 @@ function formatOutput(output, spanType) {
|
|
|
136
136
|
return safeStringify(output);
|
|
137
137
|
}
|
|
138
138
|
|
|
139
|
-
// src/
|
|
139
|
+
// src/bridge.ts
|
|
140
|
+
function flushApmExporter() {
|
|
141
|
+
const exporterFlush = tracer3?._tracer?._exporter?.flush;
|
|
142
|
+
if (typeof exporterFlush !== "function") {
|
|
143
|
+
return Promise.resolve();
|
|
144
|
+
}
|
|
145
|
+
return new Promise((resolve, reject) => {
|
|
146
|
+
let settled = false;
|
|
147
|
+
const done = (error) => {
|
|
148
|
+
if (settled) return;
|
|
149
|
+
settled = true;
|
|
150
|
+
if (error) {
|
|
151
|
+
reject(error);
|
|
152
|
+
return;
|
|
153
|
+
}
|
|
154
|
+
resolve();
|
|
155
|
+
};
|
|
156
|
+
try {
|
|
157
|
+
exporterFlush.call(tracer3._tracer._exporter, done);
|
|
158
|
+
} catch (error) {
|
|
159
|
+
reject(error);
|
|
160
|
+
}
|
|
161
|
+
});
|
|
162
|
+
}
|
|
163
|
+
var DatadogBridge = class extends BaseExporter {
|
|
164
|
+
name = "datadog-bridge";
|
|
165
|
+
config;
|
|
166
|
+
ddSpanMap = /* @__PURE__ */ new Map();
|
|
167
|
+
traceContext = /* @__PURE__ */ new Map();
|
|
168
|
+
openSpanCounts = /* @__PURE__ */ new Map();
|
|
169
|
+
constructor(config = {}) {
|
|
170
|
+
super(config);
|
|
171
|
+
const mlApp = config.mlApp ?? process.env.DD_LLMOBS_ML_APP;
|
|
172
|
+
const apiKey = config.apiKey ?? process.env.DD_API_KEY;
|
|
173
|
+
const site = config.site ?? process.env.DD_SITE ?? "datadoghq.com";
|
|
174
|
+
const env = config.env ?? process.env.DD_ENV;
|
|
175
|
+
const envAgentless = process.env.DD_LLMOBS_AGENTLESS_ENABLED?.toLowerCase();
|
|
176
|
+
const agentless = config.agentless ?? (envAgentless === "true" || envAgentless === "1" ? true : false);
|
|
177
|
+
if (!mlApp) {
|
|
178
|
+
this.setDisabled(`Missing required mlApp. Set DD_LLMOBS_ML_APP environment variable or pass mlApp in config.`);
|
|
179
|
+
this.config = config;
|
|
180
|
+
return;
|
|
181
|
+
}
|
|
182
|
+
if (agentless && !apiKey) {
|
|
183
|
+
this.setDisabled(
|
|
184
|
+
`Missing required apiKey for agentless mode. Set DD_API_KEY environment variable or pass apiKey in config.`
|
|
185
|
+
);
|
|
186
|
+
this.config = config;
|
|
187
|
+
return;
|
|
188
|
+
}
|
|
189
|
+
this.config = { ...config, mlApp, site, apiKey, agentless, env };
|
|
190
|
+
ensureTracer({
|
|
191
|
+
mlApp,
|
|
192
|
+
site,
|
|
193
|
+
apiKey,
|
|
194
|
+
agentless,
|
|
195
|
+
service: config.service,
|
|
196
|
+
env,
|
|
197
|
+
integrationsEnabled: config.integrationsEnabled ?? true
|
|
198
|
+
});
|
|
199
|
+
this.logger.info("Datadog bridge initialized", { mlApp, site, agentless });
|
|
200
|
+
}
|
|
201
|
+
/**
|
|
202
|
+
* Create a dd-trace span eagerly when a Mastra span is constructed.
|
|
203
|
+
*/
|
|
204
|
+
createSpan(options) {
|
|
205
|
+
if (this.isDisabled) return void 0;
|
|
206
|
+
try {
|
|
207
|
+
let apmParentDdSpan = void 0;
|
|
208
|
+
let llmobsParentDdSpan = void 0;
|
|
209
|
+
let parentSource = "none";
|
|
210
|
+
const externalParentId = getExternalParentId(options);
|
|
211
|
+
if (externalParentId) {
|
|
212
|
+
apmParentDdSpan = this.ddSpanMap.get(externalParentId);
|
|
213
|
+
llmobsParentDdSpan = apmParentDdSpan;
|
|
214
|
+
if (apmParentDdSpan) {
|
|
215
|
+
parentSource = "external-parent";
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
if (!apmParentDdSpan) {
|
|
219
|
+
apmParentDdSpan = tracer3.scope().active() ?? void 0;
|
|
220
|
+
if (apmParentDdSpan) {
|
|
221
|
+
parentSource = "active-scope";
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
if (!llmobsParentDdSpan && externalParentId) {
|
|
225
|
+
llmobsParentDdSpan = apmParentDdSpan;
|
|
226
|
+
}
|
|
227
|
+
const ddSpan = tracer3.startSpan(options.name, {
|
|
228
|
+
...apmParentDdSpan ? { childOf: apmParentDdSpan } : {},
|
|
229
|
+
...options.startTime ? { startTime: toDate(options.startTime).getTime() } : {}
|
|
230
|
+
});
|
|
231
|
+
const ddContext = ddSpan.context?.();
|
|
232
|
+
const spanId = ddContext?.toSpanId?.(true) ?? generateSpanId();
|
|
233
|
+
const traceId = ddContext?.toTraceId?.(true) ?? (externalParentId ? options.parent?.traceId ?? generateTraceId() : generateTraceId());
|
|
234
|
+
const parentContext = apmParentDdSpan?.context?.();
|
|
235
|
+
const parentSpanId = parentContext?.toSpanId?.(true) ?? externalParentId;
|
|
236
|
+
this.captureTraceContext(traceId, options);
|
|
237
|
+
this.openSpanCounts.set(traceId, (this.openSpanCounts.get(traceId) ?? 0) + 1);
|
|
238
|
+
this.ddSpanMap.set(spanId, ddSpan);
|
|
239
|
+
this.registerLlmObsSpan(ddSpan, traceId, options, llmobsParentDdSpan);
|
|
240
|
+
this.logger.debug(
|
|
241
|
+
`[DatadogBridge.createSpan] Created APM span [spanId=${spanId}] [traceId=${traceId}] [parentSpanId=${parentSpanId}] [type=${options.type}] [mapSize=${this.ddSpanMap.size}] [parentSource=${parentSource}] [externalParentId=${externalParentId ?? "none"}]`
|
|
242
|
+
);
|
|
243
|
+
return { spanId, traceId, parentSpanId };
|
|
244
|
+
} catch (error) {
|
|
245
|
+
this.logger.error("[DatadogBridge] Failed to create span:", error);
|
|
246
|
+
return void 0;
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
/**
|
|
250
|
+
* Execute an async function within the dd-trace context of a Mastra span.
|
|
251
|
+
*/
|
|
252
|
+
executeInContext(spanId, fn) {
|
|
253
|
+
return this.executeWithSpanContext(spanId, fn);
|
|
254
|
+
}
|
|
255
|
+
/**
|
|
256
|
+
* Execute a synchronous function within the dd-trace context of a Mastra span.
|
|
257
|
+
*/
|
|
258
|
+
executeInContextSync(spanId, fn) {
|
|
259
|
+
return this.executeWithSpanContext(spanId, fn);
|
|
260
|
+
}
|
|
261
|
+
executeWithSpanContext(spanId, fn) {
|
|
262
|
+
const ddSpan = this.ddSpanMap.get(spanId);
|
|
263
|
+
if (ddSpan) {
|
|
264
|
+
return tracer3.scope().activate(ddSpan, () => {
|
|
265
|
+
const llmobs = tracer3.llmobs;
|
|
266
|
+
if (typeof llmobs?._activate === "function") {
|
|
267
|
+
return llmobs._activate(ddSpan, void 0, fn);
|
|
268
|
+
}
|
|
269
|
+
return fn();
|
|
270
|
+
});
|
|
271
|
+
}
|
|
272
|
+
return fn();
|
|
273
|
+
}
|
|
274
|
+
/**
|
|
275
|
+
* Handle tracing events from the observability bus.
|
|
276
|
+
*/
|
|
277
|
+
async _exportTracingEvent(event) {
|
|
278
|
+
if (this.isDisabled) return;
|
|
279
|
+
try {
|
|
280
|
+
const span = event.exportedSpan;
|
|
281
|
+
if (span.isEvent) {
|
|
282
|
+
if (event.type === "span_started" || event.type === "span_ended") {
|
|
283
|
+
this.annotateAndFinishSpan(span);
|
|
284
|
+
}
|
|
285
|
+
return;
|
|
286
|
+
}
|
|
287
|
+
switch (event.type) {
|
|
288
|
+
case "span_started":
|
|
289
|
+
case "span_updated":
|
|
290
|
+
return;
|
|
291
|
+
case "span_ended":
|
|
292
|
+
this.annotateAndFinishSpan(span);
|
|
293
|
+
return;
|
|
294
|
+
}
|
|
295
|
+
} catch (error) {
|
|
296
|
+
this.logger.error("Datadog bridge error", {
|
|
297
|
+
error,
|
|
298
|
+
eventType: event.type,
|
|
299
|
+
spanId: event.exportedSpan?.id,
|
|
300
|
+
spanName: event.exportedSpan?.name
|
|
301
|
+
});
|
|
302
|
+
}
|
|
303
|
+
}
|
|
304
|
+
registerLlmObsSpan(ddSpan, traceId, options, parentDdSpan) {
|
|
305
|
+
const tagger = this.getLlmObsTagger();
|
|
306
|
+
if (!tagger) return;
|
|
307
|
+
try {
|
|
308
|
+
const kind = kindFor(options.type);
|
|
309
|
+
const ownAttrs = options.attributes;
|
|
310
|
+
const inheritedModelAttrs = options.parent?.type === SpanType.MODEL_GENERATION ? options.parent.attributes : void 0;
|
|
311
|
+
const traceCtx = this.resolveTraceContext(traceId, options);
|
|
312
|
+
tagger.registerLLMObsSpan(ddSpan, {
|
|
313
|
+
parent: parentDdSpan,
|
|
314
|
+
kind,
|
|
315
|
+
name: options.name,
|
|
316
|
+
userId: traceCtx.userId,
|
|
317
|
+
sessionId: traceCtx.sessionId,
|
|
318
|
+
...kind === "llm" && (ownAttrs?.model ?? inheritedModelAttrs?.model) ? { modelName: ownAttrs?.model ?? inheritedModelAttrs?.model } : {},
|
|
319
|
+
...kind === "llm" && (ownAttrs?.provider ?? inheritedModelAttrs?.provider) ? { modelProvider: ownAttrs?.provider ?? inheritedModelAttrs?.provider } : {}
|
|
320
|
+
});
|
|
321
|
+
} catch (error) {
|
|
322
|
+
this.logger.warn("[DatadogBridge] Failed to register LLMObs span", {
|
|
323
|
+
error,
|
|
324
|
+
spanName: options.name,
|
|
325
|
+
spanType: options.type
|
|
326
|
+
});
|
|
327
|
+
}
|
|
328
|
+
}
|
|
329
|
+
getLlmObsTagger() {
|
|
330
|
+
const tagger = tracer3.llmobs?._tagger;
|
|
331
|
+
if (tagger && typeof tagger.registerLLMObsSpan === "function") {
|
|
332
|
+
return tagger;
|
|
333
|
+
}
|
|
334
|
+
return void 0;
|
|
335
|
+
}
|
|
336
|
+
/**
|
|
337
|
+
* Annotate the eagerly-created dd span and finish it using the final Mastra
|
|
338
|
+
* span state.
|
|
339
|
+
*/
|
|
340
|
+
annotateAndFinishSpan(span) {
|
|
341
|
+
const ddSpan = this.ddSpanMap.get(span.id);
|
|
342
|
+
if (!ddSpan) {
|
|
343
|
+
this.logger.warn("[DatadogBridge] No dd span found when finalizing Mastra span", {
|
|
344
|
+
spanId: span.id,
|
|
345
|
+
spanName: span.name,
|
|
346
|
+
spanType: span.type,
|
|
347
|
+
mapSize: this.ddSpanMap.size
|
|
348
|
+
});
|
|
349
|
+
return;
|
|
350
|
+
}
|
|
351
|
+
const endTime = span.endTime ? toDate(span.endTime) : span.isEvent ? toDate(span.startTime) : /* @__PURE__ */ new Date();
|
|
352
|
+
const annotations = this.buildAnnotations(span);
|
|
353
|
+
try {
|
|
354
|
+
if (Object.keys(annotations).length > 0 && tracer3.llmobs?.annotate) {
|
|
355
|
+
tracer3.llmobs.annotate(ddSpan, annotations);
|
|
356
|
+
}
|
|
357
|
+
} catch (error) {
|
|
358
|
+
this.logger.error("[DatadogBridge] Failed to annotate span before finish", {
|
|
359
|
+
error,
|
|
360
|
+
spanId: span.id,
|
|
361
|
+
spanName: span.name
|
|
362
|
+
});
|
|
363
|
+
}
|
|
364
|
+
try {
|
|
365
|
+
if (span.errorInfo) {
|
|
366
|
+
this.setErrorTags(ddSpan, span.errorInfo);
|
|
367
|
+
}
|
|
368
|
+
} catch (error) {
|
|
369
|
+
this.logger.error("[DatadogBridge] Failed to set error tags on dd span", {
|
|
370
|
+
error,
|
|
371
|
+
spanId: span.id,
|
|
372
|
+
spanName: span.name
|
|
373
|
+
});
|
|
374
|
+
}
|
|
375
|
+
try {
|
|
376
|
+
if (typeof ddSpan.finish === "function") {
|
|
377
|
+
ddSpan.finish(endTime.getTime());
|
|
378
|
+
}
|
|
379
|
+
} catch (error) {
|
|
380
|
+
this.logger.error("[DatadogBridge] Failed to finish dd span", {
|
|
381
|
+
error,
|
|
382
|
+
spanId: span.id,
|
|
383
|
+
spanName: span.name
|
|
384
|
+
});
|
|
385
|
+
} finally {
|
|
386
|
+
this.ddSpanMap.delete(span.id);
|
|
387
|
+
this.releaseTraceContext(span.traceId);
|
|
388
|
+
}
|
|
389
|
+
}
|
|
390
|
+
captureTraceContext(traceId, options) {
|
|
391
|
+
const existing = this.traceContext.get(traceId);
|
|
392
|
+
const next = {
|
|
393
|
+
userId: firstString(options.metadata?.userId, options.parent?.metadata?.userId, existing?.userId),
|
|
394
|
+
sessionId: firstString(options.metadata?.sessionId, options.parent?.metadata?.sessionId, existing?.sessionId)
|
|
395
|
+
};
|
|
396
|
+
if (next.userId || next.sessionId) {
|
|
397
|
+
this.traceContext.set(traceId, next);
|
|
398
|
+
}
|
|
399
|
+
}
|
|
400
|
+
resolveTraceContext(traceId, options) {
|
|
401
|
+
const stored = this.traceContext.get(traceId);
|
|
402
|
+
return {
|
|
403
|
+
userId: firstString(options.metadata?.userId, options.parent?.metadata?.userId, stored?.userId),
|
|
404
|
+
sessionId: firstString(options.metadata?.sessionId, options.parent?.metadata?.sessionId, stored?.sessionId)
|
|
405
|
+
};
|
|
406
|
+
}
|
|
407
|
+
releaseTraceContext(traceId) {
|
|
408
|
+
const nextCount = (this.openSpanCounts.get(traceId) ?? 1) - 1;
|
|
409
|
+
if (nextCount > 0) {
|
|
410
|
+
this.openSpanCounts.set(traceId, nextCount);
|
|
411
|
+
return;
|
|
412
|
+
}
|
|
413
|
+
this.openSpanCounts.delete(traceId);
|
|
414
|
+
this.traceContext.delete(traceId);
|
|
415
|
+
}
|
|
416
|
+
buildAnnotations(span) {
|
|
417
|
+
const annotations = {};
|
|
418
|
+
if (span.input !== void 0) {
|
|
419
|
+
annotations.inputData = formatInput(span.input, span.type);
|
|
420
|
+
}
|
|
421
|
+
if (span.output !== void 0) {
|
|
422
|
+
annotations.outputData = formatOutput(span.output, span.type);
|
|
423
|
+
}
|
|
424
|
+
if (span.type === SpanType.MODEL_STEP) {
|
|
425
|
+
const usage = span.attributes?.usage;
|
|
426
|
+
const metrics = formatUsageMetrics(usage);
|
|
427
|
+
if (metrics) {
|
|
428
|
+
annotations.metrics = metrics;
|
|
429
|
+
}
|
|
430
|
+
}
|
|
431
|
+
const knownFields = ["usage", "model", "provider", "parameters"];
|
|
432
|
+
const otherAttributes = omitKeys(span.attributes ?? {}, knownFields);
|
|
433
|
+
const contextKeySet = new Set(this.config.requestContextKeys ?? []);
|
|
434
|
+
const flatContextTags = {};
|
|
435
|
+
const remainingMetadata = {};
|
|
436
|
+
for (const [key, value] of Object.entries(span.metadata ?? {})) {
|
|
437
|
+
if (contextKeySet.has(key)) {
|
|
438
|
+
flatContextTags[key] = value;
|
|
439
|
+
} else {
|
|
440
|
+
remainingMetadata[key] = value;
|
|
441
|
+
}
|
|
442
|
+
}
|
|
443
|
+
const remainingAttributes = {};
|
|
444
|
+
for (const [key, value] of Object.entries(otherAttributes)) {
|
|
445
|
+
if (contextKeySet.has(key)) {
|
|
446
|
+
if (!(key in flatContextTags)) {
|
|
447
|
+
flatContextTags[key] = value;
|
|
448
|
+
}
|
|
449
|
+
} else {
|
|
450
|
+
remainingAttributes[key] = value;
|
|
451
|
+
}
|
|
452
|
+
}
|
|
453
|
+
const combinedMetadata = {
|
|
454
|
+
...remainingMetadata,
|
|
455
|
+
...remainingAttributes
|
|
456
|
+
};
|
|
457
|
+
if (span.errorInfo) {
|
|
458
|
+
combinedMetadata["error.message"] = span.errorInfo.message;
|
|
459
|
+
}
|
|
460
|
+
if (Object.keys(combinedMetadata).length > 0) {
|
|
461
|
+
annotations.metadata = combinedMetadata;
|
|
462
|
+
}
|
|
463
|
+
const tags = {
|
|
464
|
+
...flatContextTags
|
|
465
|
+
};
|
|
466
|
+
if (span.tags?.length) {
|
|
467
|
+
for (const tag of span.tags) {
|
|
468
|
+
const colonIndex = tag.indexOf(":");
|
|
469
|
+
if (colonIndex > 0) {
|
|
470
|
+
tags[tag.substring(0, colonIndex)] = tag.substring(colonIndex + 1);
|
|
471
|
+
} else {
|
|
472
|
+
tags[tag] = true;
|
|
473
|
+
}
|
|
474
|
+
}
|
|
475
|
+
}
|
|
476
|
+
if (span.errorInfo) {
|
|
477
|
+
tags.error = true;
|
|
478
|
+
if (span.errorInfo.id) {
|
|
479
|
+
tags["error.id"] = span.errorInfo.id;
|
|
480
|
+
}
|
|
481
|
+
if (span.errorInfo.domain) {
|
|
482
|
+
tags["error.domain"] = span.errorInfo.domain;
|
|
483
|
+
}
|
|
484
|
+
if (span.errorInfo.category) {
|
|
485
|
+
tags["error.category"] = span.errorInfo.category;
|
|
486
|
+
}
|
|
487
|
+
}
|
|
488
|
+
if (Object.keys(tags).length > 0) {
|
|
489
|
+
annotations.tags = tags;
|
|
490
|
+
}
|
|
491
|
+
return annotations;
|
|
492
|
+
}
|
|
493
|
+
setErrorTags(ddSpan, errorInfo) {
|
|
494
|
+
ddSpan.setTag("error", true);
|
|
495
|
+
ddSpan.setTag("error.message", errorInfo.message);
|
|
496
|
+
ddSpan.setTag("error.type", errorInfo.name ?? errorInfo.category ?? "Error");
|
|
497
|
+
if (errorInfo.stack) {
|
|
498
|
+
ddSpan.setTag("error.stack", errorInfo.stack);
|
|
499
|
+
}
|
|
500
|
+
}
|
|
501
|
+
async flush() {
|
|
502
|
+
if (this.isDisabled) return;
|
|
503
|
+
if (tracer3.llmobs?.flush) {
|
|
504
|
+
try {
|
|
505
|
+
await tracer3.llmobs.flush();
|
|
506
|
+
this.logger.debug("Datadog llmobs flushed");
|
|
507
|
+
} catch (e) {
|
|
508
|
+
this.logger.error("Error flushing llmobs", { error: e });
|
|
509
|
+
}
|
|
510
|
+
}
|
|
511
|
+
try {
|
|
512
|
+
await flushApmExporter();
|
|
513
|
+
this.logger.debug("Datadog APM exporter flushed");
|
|
514
|
+
} catch (e) {
|
|
515
|
+
this.logger.error("Error flushing Datadog APM exporter", { error: e });
|
|
516
|
+
}
|
|
517
|
+
}
|
|
518
|
+
async shutdown() {
|
|
519
|
+
for (const [spanId, ddSpan] of this.ddSpanMap) {
|
|
520
|
+
this.logger.warn(`[DatadogBridge] Force-finishing APM span that was not properly closed [id=${spanId}]`);
|
|
521
|
+
try {
|
|
522
|
+
if (typeof ddSpan.finish === "function") {
|
|
523
|
+
ddSpan.finish();
|
|
524
|
+
}
|
|
525
|
+
} catch {
|
|
526
|
+
}
|
|
527
|
+
}
|
|
528
|
+
this.ddSpanMap.clear();
|
|
529
|
+
this.openSpanCounts.clear();
|
|
530
|
+
this.traceContext.clear();
|
|
531
|
+
await this.flush();
|
|
532
|
+
if (tracer3.llmobs?.disable) {
|
|
533
|
+
try {
|
|
534
|
+
tracer3.llmobs.disable();
|
|
535
|
+
} catch (e) {
|
|
536
|
+
this.logger.error("Error disabling llmobs", { error: e });
|
|
537
|
+
}
|
|
538
|
+
}
|
|
539
|
+
await super.shutdown();
|
|
540
|
+
}
|
|
541
|
+
};
|
|
542
|
+
function firstString(...values) {
|
|
543
|
+
for (const value of values) {
|
|
544
|
+
if (typeof value === "string") {
|
|
545
|
+
return value;
|
|
546
|
+
}
|
|
547
|
+
}
|
|
548
|
+
return void 0;
|
|
549
|
+
}
|
|
550
|
+
function fillRandomBytes(bytes) {
|
|
551
|
+
try {
|
|
552
|
+
const webCrypto = globalThis.crypto;
|
|
553
|
+
if (webCrypto?.getRandomValues) {
|
|
554
|
+
webCrypto.getRandomValues.call(webCrypto, bytes);
|
|
555
|
+
return;
|
|
556
|
+
}
|
|
557
|
+
} catch {
|
|
558
|
+
}
|
|
559
|
+
for (let i = 0; i < bytes.length; i++) {
|
|
560
|
+
bytes[i] = Math.floor(Math.random() * 256);
|
|
561
|
+
}
|
|
562
|
+
}
|
|
563
|
+
function generateSpanId() {
|
|
564
|
+
const bytes = new Uint8Array(8);
|
|
565
|
+
fillRandomBytes(bytes);
|
|
566
|
+
return Array.from(bytes, (byte) => byte.toString(16).padStart(2, "0")).join("");
|
|
567
|
+
}
|
|
568
|
+
function generateTraceId() {
|
|
569
|
+
const bytes = new Uint8Array(16);
|
|
570
|
+
fillRandomBytes(bytes);
|
|
571
|
+
return Array.from(bytes, (byte) => byte.toString(16).padStart(2, "0")).join("");
|
|
572
|
+
}
|
|
140
573
|
var MAX_TRACE_LIFETIME_MS = 30 * 60 * 1e3;
|
|
141
574
|
var REGULAR_CLEANUP_INTERVAL_MS = 1 * 60 * 1e3;
|
|
142
575
|
var DatadogExporter = class extends BaseExporter {
|
|
@@ -180,7 +613,7 @@ var DatadogExporter = class extends BaseExporter {
|
|
|
180
613
|
* Main entry point for tracing events from Mastra.
|
|
181
614
|
*/
|
|
182
615
|
async _exportTracingEvent(event) {
|
|
183
|
-
if (this.isDisabled || !
|
|
616
|
+
if (this.isDisabled || !tracer3.llmobs) return;
|
|
184
617
|
try {
|
|
185
618
|
const span = event.exportedSpan;
|
|
186
619
|
if (span.isEvent) {
|
|
@@ -330,21 +763,14 @@ var DatadogExporter = class extends BaseExporter {
|
|
|
330
763
|
* are exported before the runtime instance is terminated.
|
|
331
764
|
*/
|
|
332
765
|
async flush() {
|
|
333
|
-
if (this.isDisabled || !
|
|
334
|
-
if (
|
|
766
|
+
if (this.isDisabled || !tracer3.llmobs) return;
|
|
767
|
+
if (tracer3.llmobs?.flush) {
|
|
335
768
|
try {
|
|
336
|
-
await
|
|
769
|
+
await tracer3.llmobs.flush();
|
|
337
770
|
this.logger.debug("Datadog llmobs flushed");
|
|
338
771
|
} catch (e) {
|
|
339
772
|
this.logger.error("Error flushing llmobs", { error: e });
|
|
340
773
|
}
|
|
341
|
-
} else if (tracer2.flush) {
|
|
342
|
-
try {
|
|
343
|
-
await tracer2.flush();
|
|
344
|
-
this.logger.debug("Datadog tracer flushed");
|
|
345
|
-
} catch (e) {
|
|
346
|
-
this.logger.error("Error flushing tracer", { error: e });
|
|
347
|
-
}
|
|
348
774
|
}
|
|
349
775
|
}
|
|
350
776
|
/**
|
|
@@ -368,9 +794,9 @@ var DatadogExporter = class extends BaseExporter {
|
|
|
368
794
|
}
|
|
369
795
|
this.traceState.clear();
|
|
370
796
|
await this.flush();
|
|
371
|
-
if (
|
|
797
|
+
if (tracer3.llmobs?.disable) {
|
|
372
798
|
try {
|
|
373
|
-
|
|
799
|
+
tracer3.llmobs.disable();
|
|
374
800
|
} catch (e) {
|
|
375
801
|
this.logger.error("Error disabling llmobs", { error: e });
|
|
376
802
|
}
|
|
@@ -559,15 +985,15 @@ var DatadogExporter = class extends BaseExporter {
|
|
|
559
985
|
model: span.attributes?.model,
|
|
560
986
|
provider: span.attributes?.provider
|
|
561
987
|
} : inheritedModelAttrs;
|
|
562
|
-
|
|
988
|
+
tracer3.llmobs.trace(traceOptions, (ddSpan) => {
|
|
563
989
|
const annotations = this.buildAnnotations(span);
|
|
564
990
|
if (Object.keys(annotations).length > 0) {
|
|
565
|
-
|
|
991
|
+
tracer3.llmobs.annotate(ddSpan, annotations);
|
|
566
992
|
}
|
|
567
993
|
if (span.errorInfo) {
|
|
568
994
|
this.setErrorTags(ddSpan, span.errorInfo);
|
|
569
995
|
}
|
|
570
|
-
const exported =
|
|
996
|
+
const exported = tracer3.llmobs.exportSpan ? tracer3.llmobs.exportSpan(ddSpan) : void 0;
|
|
571
997
|
state.contexts.set(span.id, { ddSpan, exported });
|
|
572
998
|
for (const child of node.children) {
|
|
573
999
|
this.emitSpanTree(child, state, childInheritedModelAttrs);
|
|
@@ -583,28 +1009,28 @@ var DatadogExporter = class extends BaseExporter {
|
|
|
583
1009
|
*/
|
|
584
1010
|
emitSingleSpan(span, state, parent) {
|
|
585
1011
|
const { traceOptions, endTimeMs } = this.buildSpanOptions(span);
|
|
586
|
-
const runTrace = () =>
|
|
1012
|
+
const runTrace = () => tracer3.llmobs.trace(traceOptions, (ddSpan) => {
|
|
587
1013
|
const annotations = this.buildAnnotations(span);
|
|
588
1014
|
if (Object.keys(annotations).length > 0) {
|
|
589
|
-
|
|
1015
|
+
tracer3.llmobs.annotate(ddSpan, annotations);
|
|
590
1016
|
}
|
|
591
1017
|
if (span.errorInfo) {
|
|
592
1018
|
this.setErrorTags(ddSpan, span.errorInfo);
|
|
593
1019
|
}
|
|
594
|
-
const exported =
|
|
1020
|
+
const exported = tracer3.llmobs.exportSpan ? tracer3.llmobs.exportSpan(ddSpan) : void 0;
|
|
595
1021
|
state.contexts.set(span.id, { ddSpan, exported });
|
|
596
1022
|
if (typeof ddSpan.finish === "function") {
|
|
597
1023
|
ddSpan.finish(endTimeMs);
|
|
598
1024
|
}
|
|
599
1025
|
});
|
|
600
1026
|
if (parent) {
|
|
601
|
-
|
|
1027
|
+
tracer3.scope().activate(parent, runTrace);
|
|
602
1028
|
} else {
|
|
603
1029
|
runTrace();
|
|
604
1030
|
}
|
|
605
1031
|
}
|
|
606
1032
|
};
|
|
607
1033
|
|
|
608
|
-
export { DatadogExporter };
|
|
1034
|
+
export { DatadogBridge, DatadogExporter };
|
|
609
1035
|
//# sourceMappingURL=index.js.map
|
|
610
1036
|
//# sourceMappingURL=index.js.map
|