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