@mastra/sentry 1.2.5 → 1.2.6

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/index.cjs CHANGED
@@ -1,506 +1,488 @@
1
- 'use strict';
2
-
3
- var observability$1 = require('@mastra/core/observability');
4
- var observability = require('@mastra/observability');
5
- var otelExporter = require('@mastra/otel-exporter');
6
- var Sentry = require('@sentry/node');
7
-
8
- function _interopNamespace(e) {
9
- if (e && e.__esModule) return e;
10
- var n = Object.create(null);
11
- if (e) {
12
- Object.keys(e).forEach(function (k) {
13
- if (k !== 'default') {
14
- var d = Object.getOwnPropertyDescriptor(e, k);
15
- Object.defineProperty(n, k, d.get ? d : {
16
- enumerable: true,
17
- get: function () { return e[k]; }
18
- });
19
- }
20
- });
21
- }
22
- n.default = e;
23
- return Object.freeze(n);
24
- }
25
-
26
- var Sentry__namespace = /*#__PURE__*/_interopNamespace(Sentry);
27
-
28
- // src/tracing.ts
29
- var SPAN_TYPE_CONFIG = {
30
- [observability$1.SpanType.AGENT_RUN]: { opType: "gen_ai.invoke_agent", opName: "invoke_agent" },
31
- [observability$1.SpanType.MODEL_GENERATION]: { opType: "gen_ai.chat", opName: "chat" },
32
- [observability$1.SpanType.TOOL_CALL]: { opType: "gen_ai.execute_tool", opName: "execute_tool" },
33
- [observability$1.SpanType.MCP_TOOL_CALL]: { opType: "gen_ai.execute_tool", opName: "execute_tool" },
34
- [observability$1.SpanType.PROVIDER_TOOL_CALL]: { opType: "gen_ai.execute_tool", opName: "execute_tool" },
35
- [observability$1.SpanType.WORKFLOW_RUN]: { opType: "workflow.run", opName: "workflow" },
36
- [observability$1.SpanType.WORKFLOW_STEP]: { opType: "workflow.step", opName: "step" },
37
- [observability$1.SpanType.WORKFLOW_CONDITIONAL]: { opType: "workflow.conditional", opName: "step" },
38
- [observability$1.SpanType.WORKFLOW_CONDITIONAL_EVAL]: { opType: "workflow.conditional", opName: "step" },
39
- [observability$1.SpanType.WORKFLOW_PARALLEL]: { opType: "workflow.parallel", opName: "step" },
40
- [observability$1.SpanType.WORKFLOW_LOOP]: { opType: "workflow.loop", opName: "step" },
41
- [observability$1.SpanType.WORKFLOW_SLEEP]: { opType: "workflow.sleep", opName: "step" },
42
- [observability$1.SpanType.WORKFLOW_WAIT_EVENT]: { opType: "workflow.wait", opName: "step" },
43
- [observability$1.SpanType.PROCESSOR_RUN]: { opType: "ai.processor", opName: "step" },
44
- [observability$1.SpanType.GENERIC]: { opType: "ai.span", opName: "span" },
45
- [observability$1.SpanType.MODEL_STEP]: { opType: "ai.span", opName: "step" },
46
- [observability$1.SpanType.MODEL_CHUNK]: { opType: "ai.span", opName: "step" },
47
- [observability$1.SpanType.SCORER_RUN]: { opType: "workflow.run", opName: "eval" },
48
- [observability$1.SpanType.SCORER_STEP]: { opType: "workflow.step", opName: "step" },
49
- [observability$1.SpanType.MEMORY_OPERATION]: { opType: "ai.memory", opName: "memory" }
1
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
+ //#region \0rolldown/runtime.js
3
+ var __create = Object.create;
4
+ var __defProp = Object.defineProperty;
5
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
6
+ var __getOwnPropNames = Object.getOwnPropertyNames;
7
+ var __getProtoOf = Object.getPrototypeOf;
8
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
9
+ var __copyProps = (to, from, except, desc) => {
10
+ if (from && typeof from === "object" || typeof from === "function") for (var keys = __getOwnPropNames(from), i = 0, n = keys.length, key; i < n; i++) {
11
+ key = keys[i];
12
+ if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, {
13
+ get: ((k) => from[k]).bind(null, key),
14
+ enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
15
+ });
16
+ }
17
+ return to;
50
18
  };
51
- var ATTRIBUTE_KEYS = {
52
- SPAN_TYPE: "ai.span.type",
53
- ORIGIN: "sentry.origin",
54
- TAGS: "tags",
55
- INPUT: "input",
56
- OUTPUT: "output",
57
- GEN_AI_REQUEST_STREAM: "gen_ai.request.stream",
58
- GEN_AI_RESPONSE_MODEL: "gen_ai.response.model",
59
- GEN_AI_RESPONSE_STREAMING: "gen_ai.response.streaming",
60
- GEN_AI_RESPONSE_TOOL_CALLS: "gen_ai.response.tool_calls",
61
- GEN_AI_RESPONSE_TEXT: "gen_ai.response.text",
62
- GEN_AI_CONVERSATION_ID: "gen_ai.conversation.id",
63
- GEN_AI_COMPLETION_START_TIME: "gen_ai.completion_start_time",
64
- GEN_AI_TOOL_CALL_ID: "gen_ai.tool.call.id",
65
- TOOL_SUCCESS: "tool.success",
66
- GEN_AI_PIPELINE_NAME: "gen_ai.pipeline.name",
67
- GEN_AI_AGENT_PROMPT: "gen_ai.agent.prompt",
68
- WORKFLOW_ID: "workflow.id",
69
- WORKFLOW_STATUS: "workflow.status",
70
- WORKFLOW_STEP_ID: "workflow.step.id",
71
- WORKFLOW_STEP_STATUS: "workflow.step.status",
72
- GEN_AI_USAGE_INPUT_TOKENS: "gen_ai.usage.input_tokens",
73
- GEN_AI_USAGE_OUTPUT_TOKENS: "gen_ai.usage.output_tokens",
74
- GEN_AI_USAGE_TOTAL_TOKENS: "gen_ai.usage.total_tokens",
75
- GEN_AI_USAGE_CACHE_READ_TOKENS: "gen_ai.usage.cache_read.input_tokens",
76
- GEN_AI_USAGE_CACHE_WRITE_TOKENS: "gen_ai.usage.cache_creation.input_tokens",
77
- GEN_AI_USAGE_REASONING_TOKENS: "gen_ai.usage.reasoning_tokens"
19
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", {
20
+ value: mod,
21
+ enumerable: true
22
+ }) : target, mod));
23
+ //#endregion
24
+ let _mastra_core_observability = require("@mastra/core/observability");
25
+ let _mastra_observability = require("@mastra/observability");
26
+ let _mastra_otel_exporter = require("@mastra/otel-exporter");
27
+ let _sentry_node = require("@sentry/node");
28
+ _sentry_node = __toESM(_sentry_node, 1);
29
+ //#region src/tracing.ts
30
+ const SPAN_TYPE_CONFIG = {
31
+ [_mastra_core_observability.SpanType.AGENT_RUN]: {
32
+ opType: "gen_ai.invoke_agent",
33
+ opName: "invoke_agent"
34
+ },
35
+ [_mastra_core_observability.SpanType.MODEL_GENERATION]: {
36
+ opType: "gen_ai.chat",
37
+ opName: "chat"
38
+ },
39
+ [_mastra_core_observability.SpanType.TOOL_CALL]: {
40
+ opType: "gen_ai.execute_tool",
41
+ opName: "execute_tool"
42
+ },
43
+ [_mastra_core_observability.SpanType.MCP_TOOL_CALL]: {
44
+ opType: "gen_ai.execute_tool",
45
+ opName: "execute_tool"
46
+ },
47
+ [_mastra_core_observability.SpanType.PROVIDER_TOOL_CALL]: {
48
+ opType: "gen_ai.execute_tool",
49
+ opName: "execute_tool"
50
+ },
51
+ [_mastra_core_observability.SpanType.WORKFLOW_RUN]: {
52
+ opType: "workflow.run",
53
+ opName: "workflow"
54
+ },
55
+ [_mastra_core_observability.SpanType.WORKFLOW_STEP]: {
56
+ opType: "workflow.step",
57
+ opName: "step"
58
+ },
59
+ [_mastra_core_observability.SpanType.WORKFLOW_CONDITIONAL]: {
60
+ opType: "workflow.conditional",
61
+ opName: "step"
62
+ },
63
+ [_mastra_core_observability.SpanType.WORKFLOW_CONDITIONAL_EVAL]: {
64
+ opType: "workflow.conditional",
65
+ opName: "step"
66
+ },
67
+ [_mastra_core_observability.SpanType.WORKFLOW_PARALLEL]: {
68
+ opType: "workflow.parallel",
69
+ opName: "step"
70
+ },
71
+ [_mastra_core_observability.SpanType.WORKFLOW_LOOP]: {
72
+ opType: "workflow.loop",
73
+ opName: "step"
74
+ },
75
+ [_mastra_core_observability.SpanType.WORKFLOW_SLEEP]: {
76
+ opType: "workflow.sleep",
77
+ opName: "step"
78
+ },
79
+ [_mastra_core_observability.SpanType.WORKFLOW_WAIT_EVENT]: {
80
+ opType: "workflow.wait",
81
+ opName: "step"
82
+ },
83
+ [_mastra_core_observability.SpanType.PROCESSOR_RUN]: {
84
+ opType: "ai.processor",
85
+ opName: "step"
86
+ },
87
+ [_mastra_core_observability.SpanType.GENERIC]: {
88
+ opType: "ai.span",
89
+ opName: "span"
90
+ },
91
+ [_mastra_core_observability.SpanType.MODEL_STEP]: {
92
+ opType: "ai.span",
93
+ opName: "step"
94
+ },
95
+ [_mastra_core_observability.SpanType.MODEL_CHUNK]: {
96
+ opType: "ai.span",
97
+ opName: "step"
98
+ },
99
+ [_mastra_core_observability.SpanType.SCORER_RUN]: {
100
+ opType: "workflow.run",
101
+ opName: "eval"
102
+ },
103
+ [_mastra_core_observability.SpanType.SCORER_STEP]: {
104
+ opType: "workflow.step",
105
+ opName: "step"
106
+ },
107
+ [_mastra_core_observability.SpanType.MEMORY_OPERATION]: {
108
+ opType: "ai.memory",
109
+ opName: "memory"
110
+ }
78
111
  };
79
- var SentryExporter = class extends observability.BaseExporter {
80
- name = "sentry";
81
- sentryConfig;
82
- spanMap = /* @__PURE__ */ new Map();
83
- skippedSpans = /* @__PURE__ */ new Map();
84
- initialized = false;
85
- constructor(config = {}) {
86
- super(config);
87
- this.sentryConfig = {
88
- dsn: config.dsn ?? process.env.SENTRY_DSN ?? "",
89
- environment: config.environment ?? process.env.SENTRY_ENVIRONMENT ?? "production",
90
- tracesSampleRate: config.tracesSampleRate ?? 1,
91
- release: config.release ?? process.env.SENTRY_RELEASE ?? ""
92
- };
93
- if (!this.sentryConfig.dsn) {
94
- const dsnSource = config.dsn ? "from config" : process.env.SENTRY_DSN ? "from env" : "missing";
95
- this.setDisabled(
96
- `Missing required DSN (dsn: ${dsnSource}). Set SENTRY_DSN environment variable or pass it in config.`
97
- );
98
- return;
99
- }
100
- try {
101
- Sentry__namespace.init({
102
- dsn: this.sentryConfig.dsn,
103
- environment: this.sentryConfig.environment,
104
- tracesSampleRate: this.sentryConfig.tracesSampleRate,
105
- release: this.sentryConfig.release,
106
- ...config.options
107
- });
108
- this.initialized = true;
109
- } catch (error) {
110
- this.setDisabled(`Failed to initialize Sentry: ${error}`);
111
- }
112
- }
113
- // ============================================================================
114
- // Main Event Handlers
115
- // ============================================================================
116
- async _exportTracingEvent(event) {
117
- if (!this.initialized) return;
118
- const { type, exportedSpan } = event;
119
- if (exportedSpan.isEvent) {
120
- this.handleEventSpan(exportedSpan);
121
- return;
122
- }
123
- if (exportedSpan.type === observability$1.SpanType.MODEL_CHUNK || exportedSpan.type === observability$1.SpanType.MODEL_STEP) {
124
- if (type === observability$1.TracingEventType.SPAN_STARTED) {
125
- this.skippedSpans.set(exportedSpan.id, exportedSpan.parentSpanId || "");
126
- } else if (type === observability$1.TracingEventType.SPAN_ENDED) {
127
- this.skippedSpans.delete(exportedSpan.id);
128
- }
129
- return;
130
- }
131
- switch (type) {
132
- case observability$1.TracingEventType.SPAN_STARTED:
133
- await this.handleSpanStarted(exportedSpan);
134
- break;
135
- case observability$1.TracingEventType.SPAN_UPDATED:
136
- await this.handleSpanUpdated(exportedSpan);
137
- break;
138
- case observability$1.TracingEventType.SPAN_ENDED:
139
- await this.handleSpanEnded(exportedSpan);
140
- break;
141
- }
142
- }
143
- handleEventSpan(span) {
144
- Sentry__namespace.addBreadcrumb({
145
- type: "default",
146
- category: span.type,
147
- message: span.name,
148
- level: span.errorInfo ? "error" : "info",
149
- data: {
150
- spanId: span.id,
151
- traceId: span.traceId,
152
- ...span.input && { input: this.serializeValue(span.input) },
153
- ...span.output && { output: this.serializeValue(span.output) },
154
- ...span.metadata && { metadata: span.metadata },
155
- ...span.attributes && { attributes: span.attributes }
156
- },
157
- timestamp: span.startTime.getTime() / 1e3
158
- });
159
- }
160
- async handleSpanStarted(span) {
161
- const resolvedParentId = this.resolveParentSpanId(span.parentSpanId);
162
- const sentrySpan = Sentry__namespace.startInactiveSpan({
163
- op: this.getOperationType(span),
164
- name: otelExporter.getSpanName(span),
165
- startTime: span.startTime.getTime(),
166
- forceTransaction: span.isRootSpan,
167
- parentSpan: resolvedParentId ? this.spanMap.get(resolvedParentId)?.span : void 0
168
- });
169
- sentrySpan.setAttributes(this.buildSpanAttributes(span));
170
- this.spanMap.set(span.id, {
171
- span: sentrySpan,
172
- spanType: span.type
173
- });
174
- if ((span.type === observability$1.SpanType.TOOL_CALL || span.type === observability$1.SpanType.PROVIDER_TOOL_CALL) && resolvedParentId) {
175
- this.trackToolCallForParent(span, resolvedParentId);
176
- }
177
- }
178
- async handleSpanUpdated(span) {
179
- const spanData = this.spanMap.get(span.id);
180
- if (!spanData) {
181
- this.logMissingSpan(span, "span update");
182
- return;
183
- }
184
- }
185
- async handleSpanEnded(span) {
186
- const spanData = this.spanMap.get(span.id);
187
- if (!spanData) {
188
- this.logMissingSpan(span, "span end");
189
- return;
190
- }
191
- const { span: sentrySpan } = spanData;
192
- sentrySpan.setAttributes(this.buildSpanAttributes(span));
193
- if (span.type === observability$1.SpanType.MODEL_GENERATION) {
194
- this.applyToolCallsAttribute(spanData);
195
- const resolvedParentId = this.resolveParentSpanId(span.parentSpanId);
196
- if (resolvedParentId) {
197
- const parentData = this.spanMap.get(resolvedParentId);
198
- if (parentData?.spanType === observability$1.SpanType.AGENT_RUN) {
199
- const modelAttr = span.attributes;
200
- parentData.generation = {
201
- model: modelAttr.model,
202
- output: span.output,
203
- usage: modelAttr.usage
204
- };
205
- }
206
- }
207
- }
208
- if (span.type === observability$1.SpanType.AGENT_RUN) {
209
- this.applyUsageFromGeneration(spanData);
210
- this.setGenerationResponseAttributes(spanData);
211
- }
212
- if (span.errorInfo) {
213
- sentrySpan.setStatus({
214
- code: 2,
215
- message: span.errorInfo.message
216
- });
217
- const error = new Error(span.errorInfo.message);
218
- if (span.errorInfo.name) {
219
- error.name = span.errorInfo.name;
220
- }
221
- if (span.errorInfo.stack) {
222
- error.stack = span.errorInfo.stack;
223
- }
224
- Sentry__namespace.captureException(error, {
225
- contexts: {
226
- trace: { trace_id: span.traceId, span_id: span.id },
227
- span_info: {
228
- name: span.name,
229
- type: span.type,
230
- error_id: span.errorInfo.id,
231
- error_category: span.errorInfo.category
232
- }
233
- }
234
- });
235
- }
236
- const endTime = span.endTime ? span.endTime.getTime() : void 0;
237
- sentrySpan.end(endTime);
238
- this.spanMap.delete(span.id);
239
- }
240
- // ============================================================================
241
- // Span Creation Helpers
242
- // ============================================================================
243
- resolveParentSpanId(parentSpanId) {
244
- if (!parentSpanId) return void 0;
245
- let currentParentId = parentSpanId;
246
- while (currentParentId && this.skippedSpans.has(currentParentId)) {
247
- currentParentId = this.skippedSpans.get(currentParentId);
248
- if (!currentParentId) break;
249
- }
250
- return currentParentId;
251
- }
252
- getOperationType(span) {
253
- const config = SPAN_TYPE_CONFIG[span.type];
254
- return config ? config.opType : "ai.span";
255
- }
256
- buildSpanAttributes(span) {
257
- const attributes = otelExporter.getAttributes(span);
258
- attributes[ATTRIBUTE_KEYS.SPAN_TYPE] = span.type;
259
- attributes[ATTRIBUTE_KEYS.ORIGIN] = "auto.ai.mastra";
260
- if (span.metadata) {
261
- Object.entries(span.metadata).forEach(([key, value]) => {
262
- if (value !== void 0 && value !== null && key !== "langfuse") {
263
- attributes[`metadata.${key}`] = this.serializeValue(value);
264
- }
265
- });
266
- }
267
- this.setAttributeIfDefined(attributes, ATTRIBUTE_KEYS.TAGS, span.tags?.join(","));
268
- this.setAttributeIfDefined(attributes, ATTRIBUTE_KEYS.GEN_AI_CONVERSATION_ID, span.metadata?.threadId);
269
- this.addInputOutputAttributes(attributes, span);
270
- if (span.type === observability$1.SpanType.MODEL_GENERATION) {
271
- this.addModelGenerationAttributes(attributes, span);
272
- }
273
- if (span.type === observability$1.SpanType.TOOL_CALL || span.type === observability$1.SpanType.PROVIDER_TOOL_CALL) {
274
- this.addToolCallAttributes(attributes, span);
275
- }
276
- if (span.type === observability$1.SpanType.AGENT_RUN) {
277
- this.addAgentRunAttributes(attributes, span);
278
- }
279
- if (span.type === observability$1.SpanType.WORKFLOW_RUN) {
280
- const workflowAttr = span.attributes;
281
- this.setAttributeIfDefined(attributes, ATTRIBUTE_KEYS.WORKFLOW_ID, this.getEntityName(span));
282
- this.setAttributeIfDefined(attributes, ATTRIBUTE_KEYS.WORKFLOW_STATUS, workflowAttr.status);
283
- }
284
- if (span.type === observability$1.SpanType.WORKFLOW_STEP) {
285
- const stepAttr = span.attributes;
286
- this.setAttributeIfDefined(attributes, ATTRIBUTE_KEYS.WORKFLOW_STEP_ID, this.getEntityName(span));
287
- this.setAttributeIfDefined(attributes, ATTRIBUTE_KEYS.WORKFLOW_STEP_STATUS, stepAttr.status);
288
- }
289
- return attributes;
290
- }
291
- // ============================================================================
292
- // Sentry-Specific Attribute Formatters
293
- // ============================================================================
294
- /**
295
- * Adds Sentry-specific input/output attributes that complement GenAI semantic conventions.
296
- * Adds 'input' and 'output' keys for Sentry UI compatibility.
297
- */
298
- addInputOutputAttributes(attributes, span) {
299
- if (span.input !== void 0) {
300
- attributes[ATTRIBUTE_KEYS.INPUT] = this.serializeValue(span.input);
301
- }
302
- if (span.output !== void 0) {
303
- attributes[ATTRIBUTE_KEYS.OUTPUT] = this.serializeValue(span.output);
304
- if (span.type === observability$1.SpanType.MODEL_GENERATION) {
305
- const outputText = this.extractOutputText(span.output);
306
- if (outputText) {
307
- attributes[ATTRIBUTE_KEYS.GEN_AI_RESPONSE_TEXT] = outputText;
308
- }
309
- }
310
- }
311
- }
312
- /**
313
- * Adds Sentry-specific MODEL_GENERATION attributes that complement GenAI semantic conventions.
314
- */
315
- addModelGenerationAttributes(attributes, span) {
316
- const modelAttr = span.attributes;
317
- if (modelAttr.streaming !== void 0) {
318
- attributes[ATTRIBUTE_KEYS.GEN_AI_REQUEST_STREAM] = modelAttr.streaming;
319
- attributes[ATTRIBUTE_KEYS.GEN_AI_RESPONSE_STREAMING] = modelAttr.streaming;
320
- }
321
- this.setAttributeIfDefined(
322
- attributes,
323
- ATTRIBUTE_KEYS.GEN_AI_COMPLETION_START_TIME,
324
- modelAttr.completionStartTime?.toISOString()
325
- );
326
- if (modelAttr.usage) {
327
- const totalTokens = (modelAttr.usage.inputTokens || 0) + (modelAttr.usage.outputTokens || 0);
328
- if (totalTokens > 0) {
329
- attributes[ATTRIBUTE_KEYS.GEN_AI_USAGE_TOTAL_TOKENS] = totalTokens;
330
- }
331
- }
332
- }
333
- /**
334
- * Adds Sentry-specific TOOL_CALL attributes that complement GenAI semantic conventions.
335
- */
336
- addToolCallAttributes(attributes, span) {
337
- const toolAttr = span.attributes;
338
- this.setAttributeIfDefined(attributes, ATTRIBUTE_KEYS.TOOL_SUCCESS, toolAttr.success);
339
- this.setAttributeIfDefined(attributes, ATTRIBUTE_KEYS.GEN_AI_TOOL_CALL_ID, span.metadata?.toolCallId);
340
- }
341
- /**
342
- * Adds Sentry-specific AGENT_RUN attributes that complement GenAI semantic conventions.
343
- */
344
- addAgentRunAttributes(attributes, span) {
345
- const agentAttr = span.attributes;
346
- const agentName = this.getEntityName(span);
347
- if (agentName) {
348
- attributes[ATTRIBUTE_KEYS.GEN_AI_PIPELINE_NAME] = agentName;
349
- }
350
- this.setAttributeIfDefined(attributes, ATTRIBUTE_KEYS.GEN_AI_AGENT_PROMPT, agentAttr.prompt);
351
- }
352
- // ============================================================================
353
- // Token Usage Management
354
- // ============================================================================
355
- /**
356
- * Applies token usage from the MODEL_GENERATION span to the AGENT_RUN span attributes.
357
- * Reads usage directly from the generation field.
358
- * Called when AGENT_RUN spans end to set gen_ai.usage.* attributes.
359
- */
360
- applyUsageFromGeneration(spanData) {
361
- const usage = spanData.generation?.usage;
362
- if (!usage) return;
363
- const inputTokens = usage.inputTokens || 0;
364
- const outputTokens = usage.outputTokens || 0;
365
- if (inputTokens > 0) {
366
- spanData.span.setAttribute(ATTRIBUTE_KEYS.GEN_AI_USAGE_INPUT_TOKENS, inputTokens);
367
- }
368
- if (outputTokens > 0) {
369
- spanData.span.setAttribute(ATTRIBUTE_KEYS.GEN_AI_USAGE_OUTPUT_TOKENS, outputTokens);
370
- }
371
- const totalTokens = inputTokens + outputTokens;
372
- if (totalTokens > 0) {
373
- spanData.span.setAttribute(ATTRIBUTE_KEYS.GEN_AI_USAGE_TOTAL_TOKENS, totalTokens);
374
- }
375
- const cacheReadTokens = usage.inputDetails?.cacheRead || 0;
376
- const cacheWriteTokens = usage.inputDetails?.cacheWrite || 0;
377
- const reasoningTokens = usage.outputDetails?.reasoning || 0;
378
- if (cacheReadTokens > 0) {
379
- spanData.span.setAttribute(ATTRIBUTE_KEYS.GEN_AI_USAGE_CACHE_READ_TOKENS, cacheReadTokens);
380
- }
381
- if (cacheWriteTokens > 0) {
382
- spanData.span.setAttribute(ATTRIBUTE_KEYS.GEN_AI_USAGE_CACHE_WRITE_TOKENS, cacheWriteTokens);
383
- }
384
- if (reasoningTokens > 0) {
385
- spanData.span.setAttribute(ATTRIBUTE_KEYS.GEN_AI_USAGE_REASONING_TOKENS, reasoningTokens);
386
- }
387
- }
388
- /**
389
- * Sets gen_ai.response.model and gen_ai.response.text from the MODEL_GENERATION.
390
- * Only applies to AGENT_RUN spans.
391
- */
392
- setGenerationResponseAttributes(spanData) {
393
- if (!spanData.generation) return;
394
- if (spanData.generation.model) {
395
- spanData.span.setAttribute(ATTRIBUTE_KEYS.GEN_AI_RESPONSE_MODEL, spanData.generation.model);
396
- }
397
- if (spanData.generation.output) {
398
- const outputText = this.extractOutputText(spanData.generation.output);
399
- if (outputText) {
400
- spanData.span.setAttribute(ATTRIBUTE_KEYS.GEN_AI_RESPONSE_TEXT, outputText);
401
- }
402
- }
403
- }
404
- /**
405
- * Tracks a TOOL_CALL span as a child of its parent MODEL_GENERATION span.
406
- * This builds the tool_calls array for gen_ai.response.tool_calls attribute.
407
- */
408
- trackToolCallForParent(span, parentId) {
409
- const parentSpanData = this.spanMap.get(parentId);
410
- if (!parentSpanData || parentSpanData.spanType !== observability$1.SpanType.MODEL_GENERATION) {
411
- return;
412
- }
413
- const toolAttr = span.attributes;
414
- if (!parentSpanData.toolCalls) {
415
- parentSpanData.toolCalls = [];
416
- }
417
- parentSpanData.toolCalls.push({
418
- name: this.getEntityName(span),
419
- id: span.metadata?.toolCallId,
420
- type: toolAttr.toolType || "function"
421
- });
422
- }
423
- /**
424
- * Applies the gen_ai.response.tool_calls attribute to MODEL_GENERATION spans.
425
- * Called when MODEL_GENERATION spans end if they have child tool calls.
426
- */
427
- applyToolCallsAttribute(spanData) {
428
- if (!spanData.toolCalls || spanData.toolCalls.length === 0) {
429
- return;
430
- }
431
- spanData.span.setAttribute(ATTRIBUTE_KEYS.GEN_AI_RESPONSE_TOOL_CALLS, JSON.stringify(spanData.toolCalls));
432
- }
433
- // ============================================================================
434
- // Utility Helpers
435
- // ============================================================================
436
- logMissingSpan(span, operation) {
437
- this.logger.warn(`Sentry exporter: No Sentry span found for ${operation}`, {
438
- traceId: span.traceId,
439
- spanId: span.id,
440
- spanName: span.name
441
- });
442
- }
443
- getEntityName(span) {
444
- return span.entityName || span.entityId || "unknown";
445
- }
446
- extractOutputText(output) {
447
- if (!output) return void 0;
448
- if (typeof output === "string") return output;
449
- if (output.text && typeof output.text === "string") return output.text;
450
- if (output.content && typeof output.content === "string") return output.content;
451
- if (output.message?.content && typeof output.message.content === "string") return output.message.content;
452
- return void 0;
453
- }
454
- serializeValue(value) {
455
- if (value === null || value === void 0) return value;
456
- if (typeof value === "object") {
457
- try {
458
- return JSON.stringify(value);
459
- } catch {
460
- return String(value);
461
- }
462
- }
463
- return value;
464
- }
465
- setAttributeIfDefined(attributes, key, value) {
466
- if (value !== void 0 && value !== null) {
467
- attributes[key] = value;
468
- }
469
- }
470
- // ============================================================================
471
- // Flush and Shutdown
472
- // ============================================================================
473
- /**
474
- * Force flush any buffered spans without shutting down the exporter.
475
- * This is useful in serverless environments where you need to ensure spans
476
- * are exported before the runtime instance is terminated.
477
- */
478
- async flush() {
479
- if (!this.initialized) return;
480
- try {
481
- await Sentry__namespace.flush(2e3);
482
- this.logger.debug("Sentry exporter: Flushed pending events");
483
- } catch (error) {
484
- this.logger.error("Sentry exporter: Error flushing events", { error });
485
- }
486
- }
487
- async shutdown() {
488
- for (const [spanId, spanData] of this.spanMap.entries()) {
489
- try {
490
- spanData.span.end();
491
- } catch (error) {
492
- this.logger.error("Sentry exporter: Error ending span during shutdown", { spanId, error });
493
- }
494
- }
495
- this.spanMap.clear();
496
- this.skippedSpans.clear();
497
- if (this.initialized) {
498
- await Sentry__namespace.close(2e3);
499
- }
500
- await super.shutdown();
501
- }
112
+ const ATTRIBUTE_KEYS = {
113
+ SPAN_TYPE: "ai.span.type",
114
+ ORIGIN: "sentry.origin",
115
+ TAGS: "tags",
116
+ INPUT: "input",
117
+ OUTPUT: "output",
118
+ GEN_AI_REQUEST_STREAM: "gen_ai.request.stream",
119
+ GEN_AI_RESPONSE_MODEL: "gen_ai.response.model",
120
+ GEN_AI_RESPONSE_STREAMING: "gen_ai.response.streaming",
121
+ GEN_AI_RESPONSE_TOOL_CALLS: "gen_ai.response.tool_calls",
122
+ GEN_AI_RESPONSE_TEXT: "gen_ai.response.text",
123
+ GEN_AI_CONVERSATION_ID: "gen_ai.conversation.id",
124
+ GEN_AI_COMPLETION_START_TIME: "gen_ai.completion_start_time",
125
+ GEN_AI_TOOL_CALL_ID: "gen_ai.tool.call.id",
126
+ TOOL_SUCCESS: "tool.success",
127
+ GEN_AI_PIPELINE_NAME: "gen_ai.pipeline.name",
128
+ GEN_AI_AGENT_PROMPT: "gen_ai.agent.prompt",
129
+ WORKFLOW_ID: "workflow.id",
130
+ WORKFLOW_STATUS: "workflow.status",
131
+ WORKFLOW_STEP_ID: "workflow.step.id",
132
+ WORKFLOW_STEP_STATUS: "workflow.step.status",
133
+ GEN_AI_USAGE_INPUT_TOKENS: "gen_ai.usage.input_tokens",
134
+ GEN_AI_USAGE_OUTPUT_TOKENS: "gen_ai.usage.output_tokens",
135
+ GEN_AI_USAGE_TOTAL_TOKENS: "gen_ai.usage.total_tokens",
136
+ GEN_AI_USAGE_CACHE_READ_TOKENS: "gen_ai.usage.cache_read.input_tokens",
137
+ GEN_AI_USAGE_CACHE_WRITE_TOKENS: "gen_ai.usage.cache_creation.input_tokens",
138
+ GEN_AI_USAGE_REASONING_TOKENS: "gen_ai.usage.reasoning_tokens"
502
139
  };
503
-
140
+ var SentryExporter = class extends _mastra_observability.BaseExporter {
141
+ name = "sentry";
142
+ sentryConfig;
143
+ spanMap = /* @__PURE__ */ new Map();
144
+ skippedSpans = /* @__PURE__ */ new Map();
145
+ initialized = false;
146
+ constructor(config = {}) {
147
+ super(config);
148
+ this.sentryConfig = {
149
+ dsn: config.dsn ?? process.env.SENTRY_DSN ?? "",
150
+ environment: config.environment ?? process.env.SENTRY_ENVIRONMENT ?? "production",
151
+ tracesSampleRate: config.tracesSampleRate ?? 1,
152
+ release: config.release ?? process.env.SENTRY_RELEASE ?? ""
153
+ };
154
+ if (!this.sentryConfig.dsn) {
155
+ const dsnSource = config.dsn ? "from config" : process.env.SENTRY_DSN ? "from env" : "missing";
156
+ this.setDisabled(`Missing required DSN (dsn: ${dsnSource}). Set SENTRY_DSN environment variable or pass it in config.`);
157
+ return;
158
+ }
159
+ try {
160
+ _sentry_node.init({
161
+ dsn: this.sentryConfig.dsn,
162
+ environment: this.sentryConfig.environment,
163
+ tracesSampleRate: this.sentryConfig.tracesSampleRate,
164
+ release: this.sentryConfig.release,
165
+ ...config.options
166
+ });
167
+ this.initialized = true;
168
+ } catch (error) {
169
+ this.setDisabled(`Failed to initialize Sentry: ${error}`);
170
+ }
171
+ }
172
+ async _exportTracingEvent(event) {
173
+ if (!this.initialized) return;
174
+ const { type, exportedSpan } = event;
175
+ if (exportedSpan.isEvent) {
176
+ this.handleEventSpan(exportedSpan);
177
+ return;
178
+ }
179
+ if (exportedSpan.type === _mastra_core_observability.SpanType.MODEL_CHUNK || exportedSpan.type === _mastra_core_observability.SpanType.MODEL_STEP) {
180
+ if (type === _mastra_core_observability.TracingEventType.SPAN_STARTED) this.skippedSpans.set(exportedSpan.id, exportedSpan.parentSpanId || "");
181
+ else if (type === _mastra_core_observability.TracingEventType.SPAN_ENDED) this.skippedSpans.delete(exportedSpan.id);
182
+ return;
183
+ }
184
+ switch (type) {
185
+ case _mastra_core_observability.TracingEventType.SPAN_STARTED:
186
+ await this.handleSpanStarted(exportedSpan);
187
+ break;
188
+ case _mastra_core_observability.TracingEventType.SPAN_UPDATED:
189
+ await this.handleSpanUpdated(exportedSpan);
190
+ break;
191
+ case _mastra_core_observability.TracingEventType.SPAN_ENDED:
192
+ await this.handleSpanEnded(exportedSpan);
193
+ break;
194
+ }
195
+ }
196
+ handleEventSpan(span) {
197
+ _sentry_node.addBreadcrumb({
198
+ type: "default",
199
+ category: span.type,
200
+ message: span.name,
201
+ level: span.errorInfo ? "error" : "info",
202
+ data: {
203
+ spanId: span.id,
204
+ traceId: span.traceId,
205
+ ...span.input && { input: this.serializeValue(span.input) },
206
+ ...span.output && { output: this.serializeValue(span.output) },
207
+ ...span.metadata && { metadata: span.metadata },
208
+ ...span.attributes && { attributes: span.attributes }
209
+ },
210
+ timestamp: span.startTime.getTime() / 1e3
211
+ });
212
+ }
213
+ async handleSpanStarted(span) {
214
+ const resolvedParentId = this.resolveParentSpanId(span.parentSpanId);
215
+ const sentrySpan = _sentry_node.startInactiveSpan({
216
+ op: this.getOperationType(span),
217
+ name: (0, _mastra_otel_exporter.getSpanName)(span),
218
+ startTime: span.startTime.getTime(),
219
+ forceTransaction: span.isRootSpan,
220
+ parentSpan: resolvedParentId ? this.spanMap.get(resolvedParentId)?.span : void 0
221
+ });
222
+ sentrySpan.setAttributes(this.buildSpanAttributes(span));
223
+ this.spanMap.set(span.id, {
224
+ span: sentrySpan,
225
+ spanType: span.type
226
+ });
227
+ if ((span.type === _mastra_core_observability.SpanType.TOOL_CALL || span.type === _mastra_core_observability.SpanType.PROVIDER_TOOL_CALL) && resolvedParentId) this.trackToolCallForParent(span, resolvedParentId);
228
+ }
229
+ async handleSpanUpdated(span) {
230
+ if (!this.spanMap.get(span.id)) {
231
+ this.logMissingSpan(span, "span update");
232
+ return;
233
+ }
234
+ }
235
+ async handleSpanEnded(span) {
236
+ const spanData = this.spanMap.get(span.id);
237
+ if (!spanData) {
238
+ this.logMissingSpan(span, "span end");
239
+ return;
240
+ }
241
+ const { span: sentrySpan } = spanData;
242
+ sentrySpan.setAttributes(this.buildSpanAttributes(span));
243
+ if (span.type === _mastra_core_observability.SpanType.MODEL_GENERATION) {
244
+ this.applyToolCallsAttribute(spanData);
245
+ const resolvedParentId = this.resolveParentSpanId(span.parentSpanId);
246
+ if (resolvedParentId) {
247
+ const parentData = this.spanMap.get(resolvedParentId);
248
+ if (parentData?.spanType === _mastra_core_observability.SpanType.AGENT_RUN) {
249
+ const modelAttr = span.attributes;
250
+ parentData.generation = {
251
+ model: modelAttr.model,
252
+ output: span.output,
253
+ usage: modelAttr.usage
254
+ };
255
+ }
256
+ }
257
+ }
258
+ if (span.type === _mastra_core_observability.SpanType.AGENT_RUN) {
259
+ this.applyUsageFromGeneration(spanData);
260
+ this.setGenerationResponseAttributes(spanData);
261
+ }
262
+ if (span.errorInfo) {
263
+ sentrySpan.setStatus({
264
+ code: 2,
265
+ message: span.errorInfo.message
266
+ });
267
+ const error = new Error(span.errorInfo.message);
268
+ if (span.errorInfo.name) error.name = span.errorInfo.name;
269
+ if (span.errorInfo.stack) error.stack = span.errorInfo.stack;
270
+ _sentry_node.captureException(error, { contexts: {
271
+ trace: {
272
+ trace_id: span.traceId,
273
+ span_id: span.id
274
+ },
275
+ span_info: {
276
+ name: span.name,
277
+ type: span.type,
278
+ error_id: span.errorInfo.id,
279
+ error_category: span.errorInfo.category
280
+ }
281
+ } });
282
+ }
283
+ const endTime = span.endTime ? span.endTime.getTime() : void 0;
284
+ sentrySpan.end(endTime);
285
+ this.spanMap.delete(span.id);
286
+ }
287
+ resolveParentSpanId(parentSpanId) {
288
+ if (!parentSpanId) return void 0;
289
+ let currentParentId = parentSpanId;
290
+ while (currentParentId && this.skippedSpans.has(currentParentId)) {
291
+ currentParentId = this.skippedSpans.get(currentParentId);
292
+ if (!currentParentId) break;
293
+ }
294
+ return currentParentId;
295
+ }
296
+ getOperationType(span) {
297
+ const config = SPAN_TYPE_CONFIG[span.type];
298
+ return config ? config.opType : "ai.span";
299
+ }
300
+ buildSpanAttributes(span) {
301
+ const attributes = (0, _mastra_otel_exporter.getAttributes)(span);
302
+ attributes[ATTRIBUTE_KEYS.SPAN_TYPE] = span.type;
303
+ attributes[ATTRIBUTE_KEYS.ORIGIN] = "auto.ai.mastra";
304
+ if (span.metadata) Object.entries(span.metadata).forEach(([key, value]) => {
305
+ if (value !== void 0 && value !== null && key !== "langfuse") attributes[`metadata.${key}`] = this.serializeValue(value);
306
+ });
307
+ this.setAttributeIfDefined(attributes, ATTRIBUTE_KEYS.TAGS, span.tags?.join(","));
308
+ this.setAttributeIfDefined(attributes, ATTRIBUTE_KEYS.GEN_AI_CONVERSATION_ID, span.metadata?.threadId);
309
+ this.addInputOutputAttributes(attributes, span);
310
+ if (span.type === _mastra_core_observability.SpanType.MODEL_GENERATION) this.addModelGenerationAttributes(attributes, span);
311
+ if (span.type === _mastra_core_observability.SpanType.TOOL_CALL || span.type === _mastra_core_observability.SpanType.PROVIDER_TOOL_CALL) this.addToolCallAttributes(attributes, span);
312
+ if (span.type === _mastra_core_observability.SpanType.AGENT_RUN) this.addAgentRunAttributes(attributes, span);
313
+ if (span.type === _mastra_core_observability.SpanType.WORKFLOW_RUN) {
314
+ const workflowAttr = span.attributes;
315
+ this.setAttributeIfDefined(attributes, ATTRIBUTE_KEYS.WORKFLOW_ID, this.getEntityName(span));
316
+ this.setAttributeIfDefined(attributes, ATTRIBUTE_KEYS.WORKFLOW_STATUS, workflowAttr.status);
317
+ }
318
+ if (span.type === _mastra_core_observability.SpanType.WORKFLOW_STEP) {
319
+ const stepAttr = span.attributes;
320
+ this.setAttributeIfDefined(attributes, ATTRIBUTE_KEYS.WORKFLOW_STEP_ID, this.getEntityName(span));
321
+ this.setAttributeIfDefined(attributes, ATTRIBUTE_KEYS.WORKFLOW_STEP_STATUS, stepAttr.status);
322
+ }
323
+ return attributes;
324
+ }
325
+ /**
326
+ * Adds Sentry-specific input/output attributes that complement GenAI semantic conventions.
327
+ * Adds 'input' and 'output' keys for Sentry UI compatibility.
328
+ */
329
+ addInputOutputAttributes(attributes, span) {
330
+ if (span.input !== void 0) attributes[ATTRIBUTE_KEYS.INPUT] = this.serializeValue(span.input);
331
+ if (span.output !== void 0) {
332
+ attributes[ATTRIBUTE_KEYS.OUTPUT] = this.serializeValue(span.output);
333
+ if (span.type === _mastra_core_observability.SpanType.MODEL_GENERATION) {
334
+ const outputText = this.extractOutputText(span.output);
335
+ if (outputText) attributes[ATTRIBUTE_KEYS.GEN_AI_RESPONSE_TEXT] = outputText;
336
+ }
337
+ }
338
+ }
339
+ /**
340
+ * Adds Sentry-specific MODEL_GENERATION attributes that complement GenAI semantic conventions.
341
+ */
342
+ addModelGenerationAttributes(attributes, span) {
343
+ const modelAttr = span.attributes;
344
+ if (modelAttr.streaming !== void 0) {
345
+ attributes[ATTRIBUTE_KEYS.GEN_AI_REQUEST_STREAM] = modelAttr.streaming;
346
+ attributes[ATTRIBUTE_KEYS.GEN_AI_RESPONSE_STREAMING] = modelAttr.streaming;
347
+ }
348
+ this.setAttributeIfDefined(attributes, ATTRIBUTE_KEYS.GEN_AI_COMPLETION_START_TIME, modelAttr.completionStartTime?.toISOString());
349
+ if (modelAttr.usage) {
350
+ const totalTokens = (modelAttr.usage.inputTokens || 0) + (modelAttr.usage.outputTokens || 0);
351
+ if (totalTokens > 0) attributes[ATTRIBUTE_KEYS.GEN_AI_USAGE_TOTAL_TOKENS] = totalTokens;
352
+ }
353
+ }
354
+ /**
355
+ * Adds Sentry-specific TOOL_CALL attributes that complement GenAI semantic conventions.
356
+ */
357
+ addToolCallAttributes(attributes, span) {
358
+ const toolAttr = span.attributes;
359
+ this.setAttributeIfDefined(attributes, ATTRIBUTE_KEYS.TOOL_SUCCESS, toolAttr.success);
360
+ this.setAttributeIfDefined(attributes, ATTRIBUTE_KEYS.GEN_AI_TOOL_CALL_ID, span.metadata?.toolCallId);
361
+ }
362
+ /**
363
+ * Adds Sentry-specific AGENT_RUN attributes that complement GenAI semantic conventions.
364
+ */
365
+ addAgentRunAttributes(attributes, span) {
366
+ const agentAttr = span.attributes;
367
+ const agentName = this.getEntityName(span);
368
+ if (agentName) attributes[ATTRIBUTE_KEYS.GEN_AI_PIPELINE_NAME] = agentName;
369
+ this.setAttributeIfDefined(attributes, ATTRIBUTE_KEYS.GEN_AI_AGENT_PROMPT, agentAttr.prompt);
370
+ }
371
+ /**
372
+ * Applies token usage from the MODEL_GENERATION span to the AGENT_RUN span attributes.
373
+ * Reads usage directly from the generation field.
374
+ * Called when AGENT_RUN spans end to set gen_ai.usage.* attributes.
375
+ */
376
+ applyUsageFromGeneration(spanData) {
377
+ const usage = spanData.generation?.usage;
378
+ if (!usage) return;
379
+ const inputTokens = usage.inputTokens || 0;
380
+ const outputTokens = usage.outputTokens || 0;
381
+ if (inputTokens > 0) spanData.span.setAttribute(ATTRIBUTE_KEYS.GEN_AI_USAGE_INPUT_TOKENS, inputTokens);
382
+ if (outputTokens > 0) spanData.span.setAttribute(ATTRIBUTE_KEYS.GEN_AI_USAGE_OUTPUT_TOKENS, outputTokens);
383
+ const totalTokens = inputTokens + outputTokens;
384
+ if (totalTokens > 0) spanData.span.setAttribute(ATTRIBUTE_KEYS.GEN_AI_USAGE_TOTAL_TOKENS, totalTokens);
385
+ const cacheReadTokens = usage.inputDetails?.cacheRead || 0;
386
+ const cacheWriteTokens = usage.inputDetails?.cacheWrite || 0;
387
+ const reasoningTokens = usage.outputDetails?.reasoning || 0;
388
+ if (cacheReadTokens > 0) spanData.span.setAttribute(ATTRIBUTE_KEYS.GEN_AI_USAGE_CACHE_READ_TOKENS, cacheReadTokens);
389
+ if (cacheWriteTokens > 0) spanData.span.setAttribute(ATTRIBUTE_KEYS.GEN_AI_USAGE_CACHE_WRITE_TOKENS, cacheWriteTokens);
390
+ if (reasoningTokens > 0) spanData.span.setAttribute(ATTRIBUTE_KEYS.GEN_AI_USAGE_REASONING_TOKENS, reasoningTokens);
391
+ }
392
+ /**
393
+ * Sets gen_ai.response.model and gen_ai.response.text from the MODEL_GENERATION.
394
+ * Only applies to AGENT_RUN spans.
395
+ */
396
+ setGenerationResponseAttributes(spanData) {
397
+ if (!spanData.generation) return;
398
+ if (spanData.generation.model) spanData.span.setAttribute(ATTRIBUTE_KEYS.GEN_AI_RESPONSE_MODEL, spanData.generation.model);
399
+ if (spanData.generation.output) {
400
+ const outputText = this.extractOutputText(spanData.generation.output);
401
+ if (outputText) spanData.span.setAttribute(ATTRIBUTE_KEYS.GEN_AI_RESPONSE_TEXT, outputText);
402
+ }
403
+ }
404
+ /**
405
+ * Tracks a TOOL_CALL span as a child of its parent MODEL_GENERATION span.
406
+ * This builds the tool_calls array for gen_ai.response.tool_calls attribute.
407
+ */
408
+ trackToolCallForParent(span, parentId) {
409
+ const parentSpanData = this.spanMap.get(parentId);
410
+ if (!parentSpanData || parentSpanData.spanType !== _mastra_core_observability.SpanType.MODEL_GENERATION) return;
411
+ const toolAttr = span.attributes;
412
+ if (!parentSpanData.toolCalls) parentSpanData.toolCalls = [];
413
+ parentSpanData.toolCalls.push({
414
+ name: this.getEntityName(span),
415
+ id: span.metadata?.toolCallId,
416
+ type: toolAttr.toolType || "function"
417
+ });
418
+ }
419
+ /**
420
+ * Applies the gen_ai.response.tool_calls attribute to MODEL_GENERATION spans.
421
+ * Called when MODEL_GENERATION spans end if they have child tool calls.
422
+ */
423
+ applyToolCallsAttribute(spanData) {
424
+ if (!spanData.toolCalls || spanData.toolCalls.length === 0) return;
425
+ spanData.span.setAttribute(ATTRIBUTE_KEYS.GEN_AI_RESPONSE_TOOL_CALLS, JSON.stringify(spanData.toolCalls));
426
+ }
427
+ logMissingSpan(span, operation) {
428
+ this.logger.warn(`Sentry exporter: No Sentry span found for ${operation}`, {
429
+ traceId: span.traceId,
430
+ spanId: span.id,
431
+ spanName: span.name
432
+ });
433
+ }
434
+ getEntityName(span) {
435
+ return span.entityName || span.entityId || "unknown";
436
+ }
437
+ extractOutputText(output) {
438
+ if (!output) return void 0;
439
+ if (typeof output === "string") return output;
440
+ if (output.text && typeof output.text === "string") return output.text;
441
+ if (output.content && typeof output.content === "string") return output.content;
442
+ if (output.message?.content && typeof output.message.content === "string") return output.message.content;
443
+ }
444
+ serializeValue(value) {
445
+ if (value === null || value === void 0) return value;
446
+ if (typeof value === "object") try {
447
+ return JSON.stringify(value);
448
+ } catch {
449
+ return String(value);
450
+ }
451
+ return value;
452
+ }
453
+ setAttributeIfDefined(attributes, key, value) {
454
+ if (value !== void 0 && value !== null) attributes[key] = value;
455
+ }
456
+ /**
457
+ * Force flush any buffered spans without shutting down the exporter.
458
+ * This is useful in serverless environments where you need to ensure spans
459
+ * are exported before the runtime instance is terminated.
460
+ */
461
+ async flush() {
462
+ if (!this.initialized) return;
463
+ try {
464
+ await _sentry_node.flush(2e3);
465
+ this.logger.debug("Sentry exporter: Flushed pending events");
466
+ } catch (error) {
467
+ this.logger.error("Sentry exporter: Error flushing events", { error });
468
+ }
469
+ }
470
+ async shutdown() {
471
+ for (const [spanId, spanData] of this.spanMap.entries()) try {
472
+ spanData.span.end();
473
+ } catch (error) {
474
+ this.logger.error("Sentry exporter: Error ending span during shutdown", {
475
+ spanId,
476
+ error
477
+ });
478
+ }
479
+ this.spanMap.clear();
480
+ this.skippedSpans.clear();
481
+ if (this.initialized) await _sentry_node.close(2e3);
482
+ await super.shutdown();
483
+ }
484
+ };
485
+ //#endregion
504
486
  exports.SentryExporter = SentryExporter;
505
- //# sourceMappingURL=index.cjs.map
487
+
506
488
  //# sourceMappingURL=index.cjs.map