@mastra/datadog 1.4.16-alpha.0 → 1.4.16

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/dist/bridge.d.ts CHANGED
@@ -70,6 +70,15 @@ export interface DatadogBridgeConfig extends BaseExporterConfig {
70
70
  * LLM Observability tags instead of being nested in annotations.metadata.
71
71
  */
72
72
  requestContextKeys?: string[];
73
+ /**
74
+ * How long `flush()` waits, in milliseconds, after handing data to dd-trace.
75
+ * dd-trace sends LLM Observability spans and evaluations from a background
76
+ * writer and offers no way to await that request, so the wait keeps a process
77
+ * that exits right after `flush()` from cutting the send off. The wait only
78
+ * happens when something was sent since the last flush. Set to 0 to disable.
79
+ * Defaults to 2000.
80
+ */
81
+ flushGraceMs?: number;
73
82
  }
74
83
  /**
75
84
  * Datadog Bridge for Mastra Observability.
@@ -86,6 +95,11 @@ export declare class DatadogBridge extends BaseExporter implements Observability
86
95
  private startLinkKeys;
87
96
  private traceContext;
88
97
  private openSpanCounts;
98
+ private flushGraceMs;
99
+ /** True when spans or evaluations were handed to dd-trace since the last flush() */
100
+ private pendingSend;
101
+ /** Grace wait in progress, shared by flush() calls that overlap it */
102
+ private graceWait;
89
103
  constructor(config?: DatadogBridgeConfig);
90
104
  /**
91
105
  * Create a dd-trace span eagerly when a Mastra span is constructed.
@@ -126,6 +140,14 @@ export declare class DatadogBridge extends BaseExporter implements Observability
126
140
  private buildAnnotations;
127
141
  private setErrorTags;
128
142
  flush(): Promise<void>;
143
+ /**
144
+ * `llmobs.flush()` returns before the background writer's HTTP request
145
+ * completes and dd-trace gives nothing to await, so wait a bounded time
146
+ * instead. Starts one wait per batch of new data, so the repeated flushes
147
+ * during shutdown don't stack. A flush that overlaps a running wait joins
148
+ * it, so no caller resolves before the data it produced had its wait.
149
+ */
150
+ private waitForBackgroundSend;
129
151
  shutdown(): Promise<void>;
130
152
  }
131
153
  //# sourceMappingURL=bridge.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"bridge.d.ts","sourceRoot":"","sources":["../src/bridge.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,OAAO,KAAK,EACV,YAAY,EAKZ,mBAAmB,EACnB,iBAAiB,EACjB,UAAU,EACV,QAAQ,EACR,OAAO,EACR,MAAM,4BAA4B,CAAC;AAGpC,OAAO,EAAE,YAAY,EAAuB,MAAM,uBAAuB,CAAC;AAC1E,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,uBAAuB,CAAC;AA+DhE;;GAEG;AACH,MAAM,WAAW,mBAAoB,SAAQ,kBAAkB;IAC7D;;;OAGG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC;IAEhB;;;OAGG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC;IAEf;;;OAGG;IACH,IAAI,CAAC,EAAE,MAAM,CAAC;IAEd;;;OAGG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC;IAEjB;;;OAGG;IACH,GAAG,CAAC,EAAE,MAAM,CAAC;IAEb;;;;;;;;;;;;OAYG;IACH,SAAS,CAAC,EAAE,OAAO,CAAC;IAEpB;;;OAGG;IACH,mBAAmB,CAAC,EAAE,OAAO,CAAC;IAE9B;;;OAGG;IACH,kBAAkB,CAAC,EAAE,MAAM,EAAE,CAAC;CAC/B;AAED;;;;;;GAMG;AACH,qBAAa,aAAc,SAAQ,YAAa,YAAW,mBAAmB;IAC5E,IAAI,SAAoB;IAExB,OAAO,CAAC,MAAM,CAA8E;IAC5F,OAAO,CAAC,SAAS,CAA0B;IAC3C,oGAAoG;IACpG,OAAO,CAAC,aAAa,CAAsC;IAC3D,OAAO,CAAC,YAAY,CAAmC;IACvD,OAAO,CAAC,cAAc,CAA6B;IAEnD,YAAY,MAAM,GAAE,mBAAwB,EA8C3C;IAED;;OAEG;IACH,UAAU,CAAC,OAAO,EAAE,iBAAiB,CAAC,QAAQ,CAAC,GAAG,OAAO,GAAG,SAAS,CA8EpE;IAED;;OAEG;IACH,gBAAgB,CAAC,CAAC,EAAE,MAAM,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,CAEpE;IAED;;OAEG;IACH,oBAAoB,CAAC,CAAC,EAAE,MAAM,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,CAAC,GAAG,CAAC,CAEtD;IAEK,YAAY,CAAC,KAAK,EAAE,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC,CAgCnD;IAED,OAAO,CAAC,sBAAsB;IAmB9B;;OAEG;IACH,UAAgB,mBAAmB,CAAC,KAAK,EAAE,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC,CA6BtE;IAED,OAAO,CAAC,kBAAkB;IA0C1B,OAAO,CAAC,eAAe;IASvB;;;OAGG;IACH,OAAO,CAAC,qBAAqB;IAoE7B;;;;;;OAMG;IACH,WAAW,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,IAAI,CAIjD;IAED,OAAO,CAAC,mBAAmB;IAY3B,OAAO,CAAC,mBAAmB;IAQ3B,OAAO,CAAC,mBAAmB;IAW3B,OAAO,CAAC,gBAAgB;IAiGxB,OAAO,CAAC,YAAY;IASd,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAkB3B;IAEK,QAAQ,IAAI,OAAO,CAAC,IAAI,CAAC,CA0B9B;CACF"}
1
+ {"version":3,"file":"bridge.d.ts","sourceRoot":"","sources":["../src/bridge.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,OAAO,KAAK,EACV,YAAY,EAKZ,mBAAmB,EACnB,iBAAiB,EACjB,UAAU,EACV,QAAQ,EACR,OAAO,EACR,MAAM,4BAA4B,CAAC;AAGpC,OAAO,EAAE,YAAY,EAAuB,MAAM,uBAAuB,CAAC;AAC1E,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,uBAAuB,CAAC;AA+DhE;;GAEG;AACH,MAAM,WAAW,mBAAoB,SAAQ,kBAAkB;IAC7D;;;OAGG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC;IAEhB;;;OAGG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC;IAEf;;;OAGG;IACH,IAAI,CAAC,EAAE,MAAM,CAAC;IAEd;;;OAGG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC;IAEjB;;;OAGG;IACH,GAAG,CAAC,EAAE,MAAM,CAAC;IAEb;;;;;;;;;;;;OAYG;IACH,SAAS,CAAC,EAAE,OAAO,CAAC;IAEpB;;;OAGG;IACH,mBAAmB,CAAC,EAAE,OAAO,CAAC;IAE9B;;;OAGG;IACH,kBAAkB,CAAC,EAAE,MAAM,EAAE,CAAC;IAE9B;;;;;;;OAOG;IACH,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAED;;;;;;GAMG;AACH,qBAAa,aAAc,SAAQ,YAAa,YAAW,mBAAmB;IAC5E,IAAI,SAAoB;IAExB,OAAO,CAAC,MAAM,CAA8E;IAC5F,OAAO,CAAC,SAAS,CAA0B;IAC3C,oGAAoG;IACpG,OAAO,CAAC,aAAa,CAAsC;IAC3D,OAAO,CAAC,YAAY,CAAmC;IACvD,OAAO,CAAC,cAAc,CAA6B;IACnD,OAAO,CAAC,YAAY,CAAS;IAC7B,oFAAoF;IACpF,OAAO,CAAC,WAAW,CAAS;IAC5B,sEAAsE;IACtE,OAAO,CAAC,SAAS,CAA8B;IAE/C,YAAY,MAAM,GAAE,mBAAwB,EA+C3C;IAED;;OAEG;IACH,UAAU,CAAC,OAAO,EAAE,iBAAiB,CAAC,QAAQ,CAAC,GAAG,OAAO,GAAG,SAAS,CA8EpE;IAED;;OAEG;IACH,gBAAgB,CAAC,CAAC,EAAE,MAAM,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,CAEpE;IAED;;OAEG;IACH,oBAAoB,CAAC,CAAC,EAAE,MAAM,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,CAAC,GAAG,CAAC,CAEtD;IAEK,YAAY,CAAC,KAAK,EAAE,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC,CAiCnD;IAED,OAAO,CAAC,sBAAsB;IAmB9B;;OAEG;IACH,UAAgB,mBAAmB,CAAC,KAAK,EAAE,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC,CA6BtE;IAED,OAAO,CAAC,kBAAkB;IA0C1B,OAAO,CAAC,eAAe;IASvB;;;OAGG;IACH,OAAO,CAAC,qBAAqB;IAqE7B;;;;;;OAMG;IACH,WAAW,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,IAAI,CAIjD;IAED,OAAO,CAAC,mBAAmB;IAY3B,OAAO,CAAC,mBAAmB;IAQ3B,OAAO,CAAC,mBAAmB;IAW3B,OAAO,CAAC,gBAAgB;IAiGxB,OAAO,CAAC,YAAY;IASd,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAoB3B;IAED;;;;;;OAMG;YACW,qBAAqB;IAY7B,QAAQ,IAAI,OAAO,CAAC,IAAI,CAAC,CA2B9B;CACF"}
package/dist/index.cjs CHANGED
@@ -351,8 +351,14 @@ var DatadogBridge = class extends _mastra_observability.BaseExporter {
351
351
  startLinkKeys = /* @__PURE__ */ new WeakMap();
352
352
  traceContext = /* @__PURE__ */ new Map();
353
353
  openSpanCounts = /* @__PURE__ */ new Map();
354
+ flushGraceMs;
355
+ /** True when spans or evaluations were handed to dd-trace since the last flush() */
356
+ pendingSend = false;
357
+ /** Grace wait in progress, shared by flush() calls that overlap it */
358
+ graceWait = null;
354
359
  constructor(config = {}) {
355
360
  super(config);
361
+ this.flushGraceMs = config.flushGraceMs ?? 2e3;
356
362
  const mlApp = config.mlApp ?? process.env.DD_LLMOBS_ML_APP;
357
363
  const apiKey = config.apiKey ?? process.env.DD_API_KEY;
358
364
  const site = config.site ?? process.env.DD_SITE ?? "datadoghq.com";
@@ -459,6 +465,7 @@ var DatadogBridge = class extends _mastra_observability.BaseExporter {
459
465
  return;
460
466
  }
461
467
  try {
468
+ this.pendingSend = true;
462
469
  dd_trace.default.llmobs.submitEvaluation({
463
470
  traceId: score.traceId,
464
471
  spanId: toDatadogSpanId(score.spanId)
@@ -591,7 +598,10 @@ var DatadogBridge = class extends _mastra_observability.BaseExporter {
591
598
  });
592
599
  }
593
600
  try {
594
- if (typeof ddSpan.finish === "function") ddSpan.finish(endTime.getTime());
601
+ if (typeof ddSpan.finish === "function") {
602
+ this.pendingSend = true;
603
+ ddSpan.finish(endTime.getTime());
604
+ }
595
605
  } catch (error) {
596
606
  this.logger.error("[DatadogBridge] Failed to finish dd span", {
597
607
  error,
@@ -696,6 +706,7 @@ var DatadogBridge = class extends _mastra_observability.BaseExporter {
696
706
  } catch (e) {
697
707
  this.logger.error("Error flushing llmobs", { error: e });
698
708
  }
709
+ await this.waitForBackgroundSend();
699
710
  try {
700
711
  await flushApmExporter();
701
712
  this.logger.debug("Datadog APM exporter flushed");
@@ -703,11 +714,32 @@ var DatadogBridge = class extends _mastra_observability.BaseExporter {
703
714
  this.logger.error("Error flushing Datadog APM exporter", { error: e });
704
715
  }
705
716
  }
717
+ /**
718
+ * `llmobs.flush()` returns before the background writer's HTTP request
719
+ * completes and dd-trace gives nothing to await, so wait a bounded time
720
+ * instead. Starts one wait per batch of new data, so the repeated flushes
721
+ * during shutdown don't stack. A flush that overlaps a running wait joins
722
+ * it, so no caller resolves before the data it produced had its wait.
723
+ */
724
+ async waitForBackgroundSend() {
725
+ if (!(this.flushGraceMs > 0) || !Number.isFinite(this.flushGraceMs)) return;
726
+ if (this.pendingSend) {
727
+ this.pendingSend = false;
728
+ const wait = new Promise((resolve) => setTimeout(resolve, this.flushGraceMs)).finally(() => {
729
+ if (this.graceWait === wait) this.graceWait = null;
730
+ });
731
+ this.graceWait = wait;
732
+ }
733
+ await this.graceWait;
734
+ }
706
735
  async shutdown() {
707
736
  for (const [spanId, ddSpan] of this.ddSpanMap) {
708
737
  this.logger.warn(`[DatadogBridge] Force-finishing APM span that was not properly closed [id=${spanId}]`);
709
738
  try {
710
- if (typeof ddSpan.finish === "function") ddSpan.finish();
739
+ if (typeof ddSpan.finish === "function") {
740
+ this.pendingSend = true;
741
+ ddSpan.finish();
742
+ }
711
743
  } catch {}
712
744
  }
713
745
  this.ddSpanMap.clear();
@@ -772,8 +804,14 @@ var DatadogExporter = class extends _mastra_observability.BaseExporter {
772
804
  config;
773
805
  traceContext = /* @__PURE__ */ new Map();
774
806
  traceState = /* @__PURE__ */ new Map();
807
+ flushGraceMs;
808
+ /** True when spans or evaluations were handed to dd-trace since the last flush() */
809
+ pendingSend = false;
810
+ /** Grace wait in progress, shared by flush() calls that overlap it */
811
+ graceWait = null;
775
812
  constructor(config = {}) {
776
813
  super(config);
814
+ this.flushGraceMs = config.flushGraceMs ?? 2e3;
777
815
  const mlApp = config.mlApp ?? process.env.DD_LLMOBS_ML_APP;
778
816
  const apiKey = config.apiKey ?? process.env.DD_API_KEY;
779
817
  const site = config.site ?? process.env.DD_SITE ?? "datadoghq.com";
@@ -951,6 +989,7 @@ var DatadogExporter = class extends _mastra_observability.BaseExporter {
951
989
  return;
952
990
  }
953
991
  try {
992
+ this.pendingSend = true;
954
993
  dd_trace.default.llmobs.submitEvaluation({
955
994
  traceId: exported.traceId,
956
995
  spanId: exported.spanId
@@ -985,6 +1024,25 @@ var DatadogExporter = class extends _mastra_observability.BaseExporter {
985
1024
  } catch (e) {
986
1025
  this.logger.error("Error flushing llmobs", { error: e });
987
1026
  }
1027
+ await this.waitForBackgroundSend();
1028
+ }
1029
+ /**
1030
+ * `llmobs.flush()` returns before the background writer's HTTP request
1031
+ * completes and dd-trace gives nothing to await, so wait a bounded time
1032
+ * instead. Starts one wait per batch of new data, so the repeated flushes
1033
+ * during shutdown don't stack. A flush that overlaps a running wait joins
1034
+ * it, so no caller resolves before the data it produced had its wait.
1035
+ */
1036
+ async waitForBackgroundSend() {
1037
+ if (!(this.flushGraceMs > 0) || !Number.isFinite(this.flushGraceMs)) return;
1038
+ if (this.pendingSend) {
1039
+ this.pendingSend = false;
1040
+ const wait = new Promise((resolve) => setTimeout(resolve, this.flushGraceMs)).finally(() => {
1041
+ if (this.graceWait === wait) this.graceWait = null;
1042
+ });
1043
+ this.graceWait = wait;
1044
+ }
1045
+ await this.graceWait;
988
1046
  }
989
1047
  /**
990
1048
  * Gracefully shuts down the exporter.
@@ -1189,6 +1247,7 @@ var DatadogExporter = class extends _mastra_observability.BaseExporter {
1189
1247
  model: span.attributes?.model,
1190
1248
  provider: span.attributes?.provider
1191
1249
  } : inheritedModelAttrs;
1250
+ this.pendingSend = true;
1192
1251
  dd_trace.default.llmobs.trace(traceOptions, (ddSpan) => {
1193
1252
  const annotations = this.buildAnnotations(span);
1194
1253
  if (Object.keys(annotations).length > 0) dd_trace.default.llmobs.annotate(ddSpan, annotations);