autotel-sentry 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +105 -0
- package/dist/index.cjs +330 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +88 -0
- package/dist/index.d.ts +88 -0
- package/dist/index.js +325 -0
- package/dist/index.js.map +1 -0
- package/package.json +55 -0
- package/src/helpers.test.ts +143 -0
- package/src/helpers.ts +256 -0
- package/src/index.ts +7 -0
- package/src/processor.test.ts +195 -0
- package/src/processor.ts +191 -0
- package/src/propagator.test.ts +68 -0
- package/src/propagator.ts +96 -0
package/README.md
ADDED
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
# autotel-sentry
|
|
2
|
+
|
|
3
|
+
Bridge **OpenTelemetry (Autotel)** traces to **Sentry** so you can keep instrumenting with Autotel and send the same traces to Sentry for performance monitoring and error linking.
|
|
4
|
+
|
|
5
|
+
This package is for the **Sentry SDK + OpenTelemetry in the same service** scenario. For OTel-only backends (no Sentry SDK), see [Sentry OTLP](https://docs.sentry.io/concepts/otlp/).
|
|
6
|
+
|
|
7
|
+
This package implements Sentry's [OpenTelemetry traces integration](https://develop.sentry.dev/sdk/telemetry/traces/opentelemetry/) via a `SpanProcessor` and optional `SentryPropagator` for `sentry-trace` and `baggage` headers. The implementation follows that spec and may be updated if Sentry changes it.
|
|
8
|
+
|
|
9
|
+
## Prerequisites
|
|
10
|
+
|
|
11
|
+
- **Sentry must be initialized before** the OpenTelemetry SDK (and before `init()` from Autotel).
|
|
12
|
+
- Set **`instrumenter: 'otel'`** in `Sentry.init()` so Sentry does not double-instrument. All span/transaction creation is driven by OpenTelemetry; Sentry only consumes them.
|
|
13
|
+
- For linking errors to the active trace, the Sentry SDK should expose `addGlobalEventProcessor`. If it does not (e.g. some SDK versions), the processor still sends spans/transactions; error events may not get trace context attached.
|
|
14
|
+
|
|
15
|
+
## Installation
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
pnpm add autotel autotel-sentry @sentry/node
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
## Minimal setup
|
|
22
|
+
|
|
23
|
+
1. Initialize Sentry first (with `instrumenter: 'otel'`).
|
|
24
|
+
2. Call Autotel `init()` and pass `SentrySpanProcessor` in `spanProcessors`.
|
|
25
|
+
|
|
26
|
+
```typescript
|
|
27
|
+
import * as Sentry from '@sentry/node';
|
|
28
|
+
import { init } from 'autotel';
|
|
29
|
+
import { createSentrySpanProcessor } from 'autotel-sentry';
|
|
30
|
+
|
|
31
|
+
Sentry.init({
|
|
32
|
+
dsn: process.env.SENTRY_DSN,
|
|
33
|
+
tracesSampleRate: 1.0,
|
|
34
|
+
instrumenter: 'otel',
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
init({
|
|
38
|
+
service: 'my-app',
|
|
39
|
+
spanProcessors: [createSentrySpanProcessor(Sentry)],
|
|
40
|
+
});
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
Errors captured by Sentry will be linked to the active OpenTelemetry span (trace/span IDs). Spans created by Autotel (e.g. via `autotel-hono`, `autotel-plugins/drizzle`) are sent to Sentry as transactions and child spans. Spans for requests to Sentry's ingestion endpoint are not sent to Sentry.
|
|
44
|
+
|
|
45
|
+
## Optional: sentry-trace and baggage propagation
|
|
46
|
+
|
|
47
|
+
For cross-service trace continuity and dynamic sampling, register the **SentryPropagator** so `sentry-trace` and `baggage` headers are injected and extracted. Combine it with your existing propagators (e.g. W3C Trace Context and Baggage) using a composite propagator from your OpenTelemetry setup so that outbound requests carry Sentry headers and incoming requests restore them into context.
|
|
48
|
+
|
|
49
|
+
### Example: Using SentryPropagator with Composite Propagator
|
|
50
|
+
|
|
51
|
+
```typescript
|
|
52
|
+
import * as Sentry from '@sentry/node';
|
|
53
|
+
import { init } from 'autotel';
|
|
54
|
+
import { createSentrySpanProcessor, SentryPropagator } from 'autotel-sentry';
|
|
55
|
+
import { CompositePropagator } from '@opentelemetry/core';
|
|
56
|
+
import { W3CTraceContextPropagator, W3CBaggagePropagator } from '@opentelemetry/core';
|
|
57
|
+
|
|
58
|
+
// 1. Initialize Sentry first
|
|
59
|
+
Sentry.init({
|
|
60
|
+
dsn: process.env.SENTRY_DSN,
|
|
61
|
+
tracesSampleRate: 1.0,
|
|
62
|
+
instrumenter: 'otel',
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
// 2. Initialize Autotel with Sentry processor AND propagator
|
|
66
|
+
init({
|
|
67
|
+
service: 'my-app',
|
|
68
|
+
spanProcessors: [createSentrySpanProcessor(Sentry)],
|
|
69
|
+
|
|
70
|
+
// Register SentryPropagator alongside W3C propagators
|
|
71
|
+
propagator: new CompositePropagator({
|
|
72
|
+
propagators: [
|
|
73
|
+
new W3CTraceContextPropagator(), // traceparent header
|
|
74
|
+
new W3CBaggagePropagator(), // W3C baggage header
|
|
75
|
+
new SentryPropagator(), // sentry-trace + baggage headers
|
|
76
|
+
],
|
|
77
|
+
}),
|
|
78
|
+
});
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
**What this does:**
|
|
82
|
+
|
|
83
|
+
- **Outbound requests** (fetch, http.request, etc.) get `traceparent`, `baggage`, and `sentry-trace` headers injected automatically
|
|
84
|
+
- **Incoming requests** restore trace context from all three header types
|
|
85
|
+
- Sentry's dynamic sampling decisions propagate across services via `baggage` header
|
|
86
|
+
- Full distributed tracing works across services using different backends (OTel collector + Sentry)
|
|
87
|
+
|
|
88
|
+
**When to use:**
|
|
89
|
+
|
|
90
|
+
- Multi-service architecture where some services send to Sentry, others to OTel collectors
|
|
91
|
+
- You want Sentry's dynamic sampling to work across service boundaries
|
|
92
|
+
- You need both W3C Trace Context (for OTel) and Sentry-specific headers
|
|
93
|
+
|
|
94
|
+
## API
|
|
95
|
+
|
|
96
|
+
- **`createSentrySpanProcessor(sentry)`** – Returns a `SentrySpanProcessor` instance. Pass the `@sentry/node` module (or any object implementing the minimal hub/transaction/span interface).
|
|
97
|
+
- **`SentrySpanProcessor`** – Class implementing OpenTelemetry's `SpanProcessor`. Converts OTel spans to Sentry transactions/spans and turns OTel exception events into Sentry errors.
|
|
98
|
+
- **`SentryPropagator`** – Class implementing OpenTelemetry's `TextMapPropagator` for `sentry-trace` and `baggage` headers.
|
|
99
|
+
- **`SENTRY_PROPAGATION_KEY`** – Context key under which extracted Sentry propagation data is stored (for advanced use).
|
|
100
|
+
|
|
101
|
+
## References
|
|
102
|
+
|
|
103
|
+
- [Sentry: OpenTelemetry traces](https://develop.sentry.dev/sdk/telemetry/traces/opentelemetry/) – spec this implementation follows
|
|
104
|
+
- [Sentry OTLP](https://docs.sentry.io/concepts/otlp/) – when to use OTLP direct vs SDK + OTel
|
|
105
|
+
- [Autotel init](https://github.com/jagreehal/autotel) – `spanProcessors` and configuration
|
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,330 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var api = require('@opentelemetry/api');
|
|
4
|
+
var semanticConventions = require('@opentelemetry/semantic-conventions');
|
|
5
|
+
|
|
6
|
+
// src/processor.ts
|
|
7
|
+
function convertOtelTimeToSeconds(time) {
|
|
8
|
+
if (Array.isArray(time)) {
|
|
9
|
+
return time[0] + time[1] / 1e9;
|
|
10
|
+
}
|
|
11
|
+
return time / 1e9;
|
|
12
|
+
}
|
|
13
|
+
var CANONICAL_HTTP_MAP = {
|
|
14
|
+
"400": "failed_precondition",
|
|
15
|
+
"401": "unauthenticated",
|
|
16
|
+
"403": "permission_denied",
|
|
17
|
+
"404": "not_found",
|
|
18
|
+
"409": "aborted",
|
|
19
|
+
"429": "resource_exhausted",
|
|
20
|
+
"499": "cancelled",
|
|
21
|
+
"500": "internal_error",
|
|
22
|
+
"501": "unimplemented",
|
|
23
|
+
"503": "unavailable",
|
|
24
|
+
"504": "deadline_exceeded"
|
|
25
|
+
};
|
|
26
|
+
var CANONICAL_GRPC_MAP = {
|
|
27
|
+
"1": "cancelled",
|
|
28
|
+
"2": "unknown_error",
|
|
29
|
+
"3": "invalid_argument",
|
|
30
|
+
"4": "deadline_exceeded",
|
|
31
|
+
"5": "not_found",
|
|
32
|
+
"6": "already_exists",
|
|
33
|
+
"7": "permission_denied",
|
|
34
|
+
"8": "resource_exhausted",
|
|
35
|
+
"9": "failed_precondition",
|
|
36
|
+
"10": "aborted",
|
|
37
|
+
"11": "out_of_range",
|
|
38
|
+
"12": "unimplemented",
|
|
39
|
+
"13": "internal_error",
|
|
40
|
+
"14": "unavailable",
|
|
41
|
+
"15": "data_loss",
|
|
42
|
+
"16": "unauthenticated"
|
|
43
|
+
};
|
|
44
|
+
function mapOtelStatus(otelSpan) {
|
|
45
|
+
const { status, attributes } = otelSpan;
|
|
46
|
+
const code = status.code;
|
|
47
|
+
if (code !== void 0 && (code < 0 || code > 2)) {
|
|
48
|
+
return "unknown_error";
|
|
49
|
+
}
|
|
50
|
+
if (code === 0 || code === 1) {
|
|
51
|
+
return "ok";
|
|
52
|
+
}
|
|
53
|
+
const httpCode = attributes[semanticConventions.SEMATTRS_HTTP_STATUS_CODE];
|
|
54
|
+
const grpcCode = attributes[semanticConventions.SEMATTRS_RPC_GRPC_STATUS_CODE];
|
|
55
|
+
if (typeof httpCode === "string") {
|
|
56
|
+
const sentryStatus = CANONICAL_HTTP_MAP[httpCode];
|
|
57
|
+
if (sentryStatus) return sentryStatus;
|
|
58
|
+
}
|
|
59
|
+
if (typeof httpCode === "number") {
|
|
60
|
+
const sentryStatus = CANONICAL_HTTP_MAP[String(httpCode)];
|
|
61
|
+
if (sentryStatus) return sentryStatus;
|
|
62
|
+
}
|
|
63
|
+
if (typeof grpcCode === "string") {
|
|
64
|
+
const sentryStatus = CANONICAL_GRPC_MAP[grpcCode];
|
|
65
|
+
if (sentryStatus) return sentryStatus;
|
|
66
|
+
}
|
|
67
|
+
return "unknown_error";
|
|
68
|
+
}
|
|
69
|
+
function parseSpanDescription(otelSpan) {
|
|
70
|
+
const { name, kind, attributes } = otelSpan;
|
|
71
|
+
const description = name || "unknown";
|
|
72
|
+
const spanKind = kind ?? 0;
|
|
73
|
+
const isHttp = spanKind === 2 || attributes["http.method"] != null;
|
|
74
|
+
const isDb = attributes["db.system"] != null || attributes["db.operation"] != null || attributes["db.statement"] != null;
|
|
75
|
+
let op = "default";
|
|
76
|
+
if (isHttp) {
|
|
77
|
+
op = "http.client";
|
|
78
|
+
const method = attributes["http.method"];
|
|
79
|
+
const route = attributes["http.route"] ?? attributes["http.target"];
|
|
80
|
+
if (method && route) op = "http.server";
|
|
81
|
+
} else if (isDb) {
|
|
82
|
+
op = "db.query";
|
|
83
|
+
}
|
|
84
|
+
return { op, description };
|
|
85
|
+
}
|
|
86
|
+
function getTraceData(otelSpan) {
|
|
87
|
+
const ctx = otelSpan.spanContext();
|
|
88
|
+
return {
|
|
89
|
+
traceId: ctx.traceId,
|
|
90
|
+
spanId: ctx.spanId,
|
|
91
|
+
parentSpanId: otelSpan.parentSpanContext?.spanId
|
|
92
|
+
};
|
|
93
|
+
}
|
|
94
|
+
function isSentryRequestSpan(otelSpan, getDsnHost) {
|
|
95
|
+
const httpUrl = otelSpan.attributes[semanticConventions.SEMATTRS_HTTP_URL];
|
|
96
|
+
if (httpUrl == null) return false;
|
|
97
|
+
const url = typeof httpUrl === "string" ? httpUrl : String(httpUrl);
|
|
98
|
+
const host = getDsnHost();
|
|
99
|
+
if (!host) return false;
|
|
100
|
+
return url.includes(host);
|
|
101
|
+
}
|
|
102
|
+
function getOtelContextFromSpan(otelSpan) {
|
|
103
|
+
const attributes = {};
|
|
104
|
+
for (const [k, v] of Object.entries(otelSpan.attributes)) {
|
|
105
|
+
attributes[k] = v;
|
|
106
|
+
}
|
|
107
|
+
const resource = {};
|
|
108
|
+
const res = otelSpan.resource;
|
|
109
|
+
if (res && res.attributes) {
|
|
110
|
+
for (const [k, v] of Object.entries(res.attributes)) {
|
|
111
|
+
resource[k] = v;
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
return { attributes, resource };
|
|
115
|
+
}
|
|
116
|
+
function updateSpanWithOtelData(sentrySpan, otelSpan) {
|
|
117
|
+
const status = mapOtelStatus(otelSpan);
|
|
118
|
+
sentrySpan.setStatus({ status });
|
|
119
|
+
sentrySpan.setData("otel.kind", otelSpan.kind ?? 0);
|
|
120
|
+
for (const [key, value] of Object.entries(otelSpan.attributes)) {
|
|
121
|
+
sentrySpan.setData(key, value);
|
|
122
|
+
}
|
|
123
|
+
const { op, description } = parseSpanDescription(otelSpan);
|
|
124
|
+
sentrySpan.op = op;
|
|
125
|
+
sentrySpan.description = description;
|
|
126
|
+
}
|
|
127
|
+
function updateTransactionWithOtelData(transaction, otelSpan) {
|
|
128
|
+
const status = mapOtelStatus(otelSpan);
|
|
129
|
+
transaction.setStatus({ status });
|
|
130
|
+
const { op, description } = parseSpanDescription(otelSpan);
|
|
131
|
+
transaction.op = op;
|
|
132
|
+
transaction.name = description;
|
|
133
|
+
}
|
|
134
|
+
function finishTransactionWithContextFromOtelData(transaction, otelSpan) {
|
|
135
|
+
const { attributes, resource } = getOtelContextFromSpan(otelSpan);
|
|
136
|
+
transaction.setContext("otel", { attributes, resource });
|
|
137
|
+
transaction.finish(convertOtelTimeToSeconds(otelSpan.endTime));
|
|
138
|
+
}
|
|
139
|
+
function generateSentryErrorsFromOtelSpan(otelSpan, captureException) {
|
|
140
|
+
const events = otelSpan.events ?? [];
|
|
141
|
+
for (const event of events) {
|
|
142
|
+
if (event.name !== "exception") continue;
|
|
143
|
+
const attrs = event.attributes ?? {};
|
|
144
|
+
const message = attrs[semanticConventions.SEMATTRS_EXCEPTION_MESSAGE] ?? "Unknown error";
|
|
145
|
+
const stack = attrs[semanticConventions.SEMATTRS_EXCEPTION_STACKTRACE] ?? "";
|
|
146
|
+
const type = attrs[semanticConventions.SEMATTRS_EXCEPTION_TYPE] ?? "Error";
|
|
147
|
+
const synthetic = new Error(message);
|
|
148
|
+
synthetic.name = type;
|
|
149
|
+
if (stack) synthetic.stack = stack;
|
|
150
|
+
const { attributes, resource } = getOtelContextFromSpan(otelSpan);
|
|
151
|
+
captureException(synthetic, {
|
|
152
|
+
contexts: {
|
|
153
|
+
otel: { attributes, resource },
|
|
154
|
+
trace: {
|
|
155
|
+
trace_id: otelSpan.spanContext().traceId,
|
|
156
|
+
span_id: otelSpan.spanContext().spanId,
|
|
157
|
+
parent_span_id: otelSpan.parentSpanContext?.spanId
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
});
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
// src/processor.ts
|
|
165
|
+
var INSTRUMENTER_OTEL = "otel";
|
|
166
|
+
var SentrySpanProcessor = class {
|
|
167
|
+
sentry;
|
|
168
|
+
map = /* @__PURE__ */ new Map();
|
|
169
|
+
constructor(sentry) {
|
|
170
|
+
this.sentry = sentry;
|
|
171
|
+
if (typeof sentry.addGlobalEventProcessor === "function") {
|
|
172
|
+
sentry.addGlobalEventProcessor((event) => {
|
|
173
|
+
const e = event;
|
|
174
|
+
const otelSpan = api.trace.getActiveSpan();
|
|
175
|
+
if (!otelSpan) return e;
|
|
176
|
+
if (e.contexts && e.contexts.trace) {
|
|
177
|
+
return e;
|
|
178
|
+
}
|
|
179
|
+
const ctx = otelSpan.spanContext();
|
|
180
|
+
e.contexts = {
|
|
181
|
+
...e.contexts,
|
|
182
|
+
trace: {
|
|
183
|
+
trace_id: ctx.traceId,
|
|
184
|
+
span_id: ctx.spanId
|
|
185
|
+
}
|
|
186
|
+
};
|
|
187
|
+
return e;
|
|
188
|
+
});
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
getDsnHost() {
|
|
192
|
+
const hub = this.sentry.getCurrentHub();
|
|
193
|
+
const client = hub.getClient?.();
|
|
194
|
+
return client?.getDsn()?.host;
|
|
195
|
+
}
|
|
196
|
+
onStart(span, _parentContext) {
|
|
197
|
+
const hub = this.sentry.getCurrentHub();
|
|
198
|
+
if (!hub) return;
|
|
199
|
+
const spanContext = span.spanContext();
|
|
200
|
+
const otelSpanId = spanContext.spanId;
|
|
201
|
+
const parentSpanId = span.parentSpanContext?.spanId;
|
|
202
|
+
const parentSentry = parentSpanId ? this.map.get(parentSpanId) : void 0;
|
|
203
|
+
const startTimestamp = convertOtelTimeToSeconds(span.startTime);
|
|
204
|
+
if (parentSentry && "startChild" in parentSentry) {
|
|
205
|
+
const child = parentSentry.startChild({
|
|
206
|
+
description: span.name,
|
|
207
|
+
instrumenter: INSTRUMENTER_OTEL,
|
|
208
|
+
startTimestamp,
|
|
209
|
+
spanId: otelSpanId
|
|
210
|
+
});
|
|
211
|
+
this.map.set(otelSpanId, child);
|
|
212
|
+
} else {
|
|
213
|
+
const traceData = getTraceData(span);
|
|
214
|
+
const transaction = hub.startTransaction({
|
|
215
|
+
name: span.name,
|
|
216
|
+
traceId: traceData.traceId,
|
|
217
|
+
spanId: traceData.spanId,
|
|
218
|
+
parentSpanId: traceData.parentSpanId,
|
|
219
|
+
startTimestamp,
|
|
220
|
+
instrumenter: INSTRUMENTER_OTEL
|
|
221
|
+
});
|
|
222
|
+
if (transaction) {
|
|
223
|
+
this.map.set(otelSpanId, transaction);
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
onEnd(span) {
|
|
228
|
+
const otelSpanId = span.spanContext().spanId;
|
|
229
|
+
const sentrySpan = this.map.get(otelSpanId);
|
|
230
|
+
if (isSentryRequestSpan(span, () => this.getDsnHost())) {
|
|
231
|
+
this.map.delete(otelSpanId);
|
|
232
|
+
return;
|
|
233
|
+
}
|
|
234
|
+
generateSentryErrorsFromOtelSpan(
|
|
235
|
+
span,
|
|
236
|
+
(err, opts) => this.sentry.captureException(err, opts)
|
|
237
|
+
);
|
|
238
|
+
if (!sentrySpan) return;
|
|
239
|
+
const isTransaction = "setContext" in sentrySpan && "finish" in sentrySpan;
|
|
240
|
+
if (isTransaction) {
|
|
241
|
+
updateTransactionWithOtelData(sentrySpan, span);
|
|
242
|
+
finishTransactionWithContextFromOtelData(
|
|
243
|
+
sentrySpan,
|
|
244
|
+
span
|
|
245
|
+
);
|
|
246
|
+
} else {
|
|
247
|
+
updateSpanWithOtelData(sentrySpan, span);
|
|
248
|
+
sentrySpan.finish(convertOtelTimeToSeconds(span.endTime));
|
|
249
|
+
}
|
|
250
|
+
this.map.delete(otelSpanId);
|
|
251
|
+
}
|
|
252
|
+
forceFlush() {
|
|
253
|
+
return Promise.resolve();
|
|
254
|
+
}
|
|
255
|
+
shutdown() {
|
|
256
|
+
this.map.clear();
|
|
257
|
+
return Promise.resolve();
|
|
258
|
+
}
|
|
259
|
+
};
|
|
260
|
+
function createSentrySpanProcessor(sentry) {
|
|
261
|
+
return new SentrySpanProcessor(sentry);
|
|
262
|
+
}
|
|
263
|
+
var SENTRY_PROPAGATION_KEY = /* @__PURE__ */ Symbol.for("autotel.sentry.propagation");
|
|
264
|
+
var TRACE_FLAGS_SAMPLED = 1;
|
|
265
|
+
function getSpanContextFromContext(context) {
|
|
266
|
+
const span = api.trace.getSpan(context);
|
|
267
|
+
if (!span) return null;
|
|
268
|
+
const ctx = span.spanContext();
|
|
269
|
+
return { traceId: ctx.traceId, spanId: ctx.spanId, traceFlags: ctx.traceFlags };
|
|
270
|
+
}
|
|
271
|
+
function formatSentryTrace(traceId, spanId, traceFlags) {
|
|
272
|
+
const sampled = (traceFlags & TRACE_FLAGS_SAMPLED) === TRACE_FLAGS_SAMPLED ? "1" : "0";
|
|
273
|
+
return `${traceId}-${spanId}-${sampled}`;
|
|
274
|
+
}
|
|
275
|
+
function serializeBaggage(context) {
|
|
276
|
+
const baggage = api.propagation.getBaggage(context);
|
|
277
|
+
if (!baggage) return void 0;
|
|
278
|
+
const entries = [];
|
|
279
|
+
const allEntries = baggage.getAllEntries();
|
|
280
|
+
for (const [key, entry] of allEntries) {
|
|
281
|
+
if (entry?.value !== void 0) {
|
|
282
|
+
const encoded = encodeURIComponent(key) + "=" + encodeURIComponent(entry.value);
|
|
283
|
+
entries.push(encoded);
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
return entries.length > 0 ? entries.join("; ") : void 0;
|
|
287
|
+
}
|
|
288
|
+
var SentryPropagator = class {
|
|
289
|
+
inject(context, carrier, setter) {
|
|
290
|
+
const spanCtx = getSpanContextFromContext(context);
|
|
291
|
+
if (!spanCtx) return;
|
|
292
|
+
const sentryTrace = formatSentryTrace(
|
|
293
|
+
spanCtx.traceId,
|
|
294
|
+
spanCtx.spanId,
|
|
295
|
+
spanCtx.traceFlags
|
|
296
|
+
);
|
|
297
|
+
setter.set(carrier, "sentry-trace", sentryTrace);
|
|
298
|
+
const baggageStr = serializeBaggage(context);
|
|
299
|
+
if (baggageStr) {
|
|
300
|
+
setter.set(carrier, "baggage", baggageStr);
|
|
301
|
+
}
|
|
302
|
+
}
|
|
303
|
+
extract(context, carrier, getter) {
|
|
304
|
+
const keys = getter.keys(carrier);
|
|
305
|
+
let sentryTrace;
|
|
306
|
+
let baggageStr;
|
|
307
|
+
for (const key of keys) {
|
|
308
|
+
const lower = key.toLowerCase();
|
|
309
|
+
const value = getter.get(carrier, key);
|
|
310
|
+
const str = Array.isArray(value) ? value[0] : value;
|
|
311
|
+
if (lower === "sentry-trace" && typeof str === "string") sentryTrace = str;
|
|
312
|
+
if (lower === "baggage" && typeof str === "string") baggageStr = str;
|
|
313
|
+
}
|
|
314
|
+
const data = {};
|
|
315
|
+
if (sentryTrace) data.sentryTrace = sentryTrace;
|
|
316
|
+
if (baggageStr) data.baggage = baggageStr;
|
|
317
|
+
if (Object.keys(data).length === 0) return context;
|
|
318
|
+
return context.setValue(SENTRY_PROPAGATION_KEY, data);
|
|
319
|
+
}
|
|
320
|
+
fields() {
|
|
321
|
+
return ["sentry-trace", "baggage"];
|
|
322
|
+
}
|
|
323
|
+
};
|
|
324
|
+
|
|
325
|
+
exports.SENTRY_PROPAGATION_KEY = SENTRY_PROPAGATION_KEY;
|
|
326
|
+
exports.SentryPropagator = SentryPropagator;
|
|
327
|
+
exports.SentrySpanProcessor = SentrySpanProcessor;
|
|
328
|
+
exports.createSentrySpanProcessor = createSentrySpanProcessor;
|
|
329
|
+
//# sourceMappingURL=index.cjs.map
|
|
330
|
+
//# sourceMappingURL=index.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/helpers.ts","../src/processor.ts","../src/propagator.ts"],"names":["SEMATTRS_HTTP_STATUS_CODE","SEMATTRS_RPC_GRPC_STATUS_CODE","SEMATTRS_HTTP_URL","SEMATTRS_EXCEPTION_MESSAGE","SEMATTRS_EXCEPTION_STACKTRACE","SEMATTRS_EXCEPTION_TYPE","trace","propagation"],"mappings":"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","file":"index.cjs","sourcesContent":["/**\n * Helpers for mapping OpenTelemetry spans to Sentry transactions/spans and context.\n * Aligned with Sentry's OpenTelemetry integration spec.\n */\n\nimport type { ReadableSpan } from '@opentelemetry/sdk-trace-base';\nimport {\n SEMATTRS_HTTP_URL,\n SEMATTRS_HTTP_STATUS_CODE,\n SEMATTRS_RPC_GRPC_STATUS_CODE,\n SEMATTRS_EXCEPTION_MESSAGE,\n SEMATTRS_EXCEPTION_STACKTRACE,\n SEMATTRS_EXCEPTION_TYPE,\n} from '@opentelemetry/semantic-conventions';\n\n/** Sentry span status strings per their spec (maps to gRPC-style codes). */\nexport type SentrySpanStatus =\n | 'ok'\n | 'cancelled'\n | 'unknown_error'\n | 'invalid_argument'\n | 'deadline_exceeded'\n | 'not_found'\n | 'already_exists'\n | 'permission_denied'\n | 'resource_exhausted'\n | 'failed_precondition'\n | 'aborted'\n | 'out_of_range'\n | 'unimplemented'\n | 'internal_error'\n | 'unavailable'\n | 'data_loss'\n | 'unauthenticated';\n\nexport interface ParsedSpanDescription {\n op: string;\n description: string;\n}\n\n/** OTel timestamps are typically in nanoseconds (HrTime or number). */\nexport function convertOtelTimeToSeconds(time: number | [number, number]): number {\n if (Array.isArray(time)) {\n return time[0] + time[1] / 1e9;\n }\n return time / 1e9;\n}\n\nconst CANONICAL_HTTP_MAP: Record<string, SentrySpanStatus> = {\n '400': 'failed_precondition',\n '401': 'unauthenticated',\n '403': 'permission_denied',\n '404': 'not_found',\n '409': 'aborted',\n '429': 'resource_exhausted',\n '499': 'cancelled',\n '500': 'internal_error',\n '501': 'unimplemented',\n '503': 'unavailable',\n '504': 'deadline_exceeded',\n};\n\nconst CANONICAL_GRPC_MAP: Record<string, SentrySpanStatus> = {\n '1': 'cancelled',\n '2': 'unknown_error',\n '3': 'invalid_argument',\n '4': 'deadline_exceeded',\n '5': 'not_found',\n '6': 'already_exists',\n '7': 'permission_denied',\n '8': 'resource_exhausted',\n '9': 'failed_precondition',\n '10': 'aborted',\n '11': 'out_of_range',\n '12': 'unimplemented',\n '13': 'internal_error',\n '14': 'unavailable',\n '15': 'data_loss',\n '16': 'unauthenticated',\n};\n\nexport function mapOtelStatus(otelSpan: ReadableSpan): SentrySpanStatus {\n const { status, attributes } = otelSpan;\n const code = status.code;\n\n if (code !== undefined && (code < 0 || code > 2)) {\n return 'unknown_error';\n }\n\n if (code === 0 || code === 1) {\n return 'ok';\n }\n\n const httpCode = attributes[SEMATTRS_HTTP_STATUS_CODE];\n const grpcCode = attributes[SEMATTRS_RPC_GRPC_STATUS_CODE];\n\n if (typeof httpCode === 'string') {\n const sentryStatus = CANONICAL_HTTP_MAP[httpCode];\n if (sentryStatus) return sentryStatus;\n }\n if (typeof httpCode === 'number') {\n const sentryStatus = CANONICAL_HTTP_MAP[String(httpCode)];\n if (sentryStatus) return sentryStatus;\n }\n\n if (typeof grpcCode === 'string') {\n const sentryStatus = CANONICAL_GRPC_MAP[grpcCode];\n if (sentryStatus) return sentryStatus;\n }\n\n return 'unknown_error';\n}\n\n/** Derive Sentry op and description from OTel span name, kind, and attributes. */\nexport function parseSpanDescription(otelSpan: ReadableSpan): ParsedSpanDescription {\n const { name, kind, attributes } = otelSpan;\n const description = name || 'unknown';\n\n const spanKind = kind ?? 0;\n const isHttp = spanKind === 2 || attributes['http.method'] != null;\n const isDb =\n attributes['db.system'] != null ||\n attributes['db.operation'] != null ||\n attributes['db.statement'] != null;\n\n let op = 'default';\n if (isHttp) {\n op = 'http.client';\n const method = attributes['http.method'];\n const route = attributes['http.route'] ?? attributes['http.target'];\n if (method && route) op = 'http.server';\n } else if (isDb) {\n op = 'db.query';\n }\n\n return { op, description };\n}\n\nexport interface TraceData {\n traceId: string;\n spanId: string;\n parentSpanId?: string;\n}\n\nexport function getTraceData(otelSpan: ReadableSpan): TraceData {\n const ctx = otelSpan.spanContext();\n return {\n traceId: ctx.traceId,\n spanId: ctx.spanId,\n parentSpanId: otelSpan.parentSpanContext?.spanId,\n };\n}\n\n/** Check if the span represents a request to Sentry (ingestion); such spans must not be sent to Sentry. */\nexport function isSentryRequestSpan(\n otelSpan: ReadableSpan,\n getDsnHost: () => string | undefined,\n): boolean {\n const httpUrl = otelSpan.attributes[SEMATTRS_HTTP_URL];\n if (httpUrl == null) return false;\n const url = typeof httpUrl === 'string' ? httpUrl : String(httpUrl);\n const host = getDsnHost();\n if (!host) return false;\n return url.includes(host);\n}\n\n/** Attributes and resource for Sentry's otel context. */\nexport function getOtelContextFromSpan(otelSpan: ReadableSpan): {\n attributes: Record<string, unknown>;\n resource: Record<string, unknown>;\n} {\n const attributes: Record<string, unknown> = {};\n for (const [k, v] of Object.entries(otelSpan.attributes)) {\n attributes[k] = v;\n }\n const resource: Record<string, unknown> = {};\n const res = otelSpan.resource;\n if (res && res.attributes) {\n for (const [k, v] of Object.entries(res.attributes)) {\n resource[k] = v;\n }\n }\n return { attributes, resource };\n}\n\n/** Update a Sentry span with OTel span data (status, op, description, data). */\nexport function updateSpanWithOtelData(\n sentrySpan: { setStatus: (s: { status?: string }) => void; setData: (k: string, v: unknown) => void; op?: string; description?: string },\n otelSpan: ReadableSpan,\n): void {\n const status = mapOtelStatus(otelSpan);\n sentrySpan.setStatus({ status });\n sentrySpan.setData('otel.kind', otelSpan.kind ?? 0);\n for (const [key, value] of Object.entries(otelSpan.attributes)) {\n sentrySpan.setData(key, value);\n }\n const { op, description } = parseSpanDescription(otelSpan);\n sentrySpan.op = op;\n sentrySpan.description = description;\n}\n\n/** Update a Sentry transaction with OTel span data. */\nexport function updateTransactionWithOtelData(\n transaction: { setStatus: (s: { status?: string }) => void; op?: string; name?: string },\n otelSpan: ReadableSpan,\n): void {\n const status = mapOtelStatus(otelSpan);\n transaction.setStatus({ status });\n const { op, description } = parseSpanDescription(otelSpan);\n transaction.op = op;\n transaction.name = description;\n}\n\n/** Set otel context on transaction and finish it. */\nexport function finishTransactionWithContextFromOtelData(\n transaction: {\n setContext: (name: string, ctx: { attributes?: Record<string, unknown>; resource?: Record<string, unknown> }) => void;\n finish: (endTime?: number) => void;\n },\n otelSpan: ReadableSpan,\n): void {\n const { attributes, resource } = getOtelContextFromSpan(otelSpan);\n transaction.setContext('otel', { attributes, resource });\n transaction.finish(convertOtelTimeToSeconds(otelSpan.endTime));\n}\n\n/** Build synthetic Error from OTel exception event attributes and capture with Sentry. */\nexport function generateSentryErrorsFromOtelSpan(\n otelSpan: ReadableSpan,\n captureException: (error: Error, options?: { contexts?: Record<string, unknown> }) => void,\n): void {\n const events = otelSpan.events ?? [];\n for (const event of events) {\n if (event.name !== 'exception') continue;\n const attrs = event.attributes ?? {};\n const message = (attrs[SEMATTRS_EXCEPTION_MESSAGE] as string) ?? 'Unknown error';\n const stack = (attrs[SEMATTRS_EXCEPTION_STACKTRACE] as string) ?? '';\n const type = (attrs[SEMATTRS_EXCEPTION_TYPE] as string) ?? 'Error';\n\n const synthetic = new Error(message);\n synthetic.name = type;\n if (stack) synthetic.stack = stack;\n\n const { attributes, resource } = getOtelContextFromSpan(otelSpan);\n captureException(synthetic, {\n contexts: {\n otel: { attributes, resource },\n trace: {\n trace_id: otelSpan.spanContext().traceId,\n span_id: otelSpan.spanContext().spanId,\n parent_span_id: otelSpan.parentSpanContext?.spanId,\n },\n },\n });\n }\n}\n","/**\n * SentrySpanProcessor: converts OpenTelemetry spans to Sentry transactions/spans.\n * Register with init({ spanProcessors: [new SentrySpanProcessor(Sentry)] }).\n */\n\nimport { trace } from '@opentelemetry/api';\nimport type { Context } from '@opentelemetry/api';\nimport type { Span, SpanProcessor } from '@opentelemetry/sdk-trace-base';\nimport type { ReadableSpan } from '@opentelemetry/sdk-trace-base';\nimport {\n convertOtelTimeToSeconds,\n getTraceData,\n isSentryRequestSpan,\n updateSpanWithOtelData,\n updateTransactionWithOtelData,\n finishTransactionWithContextFromOtelData,\n generateSentryErrorsFromOtelSpan,\n} from './helpers';\n\n/** Minimal Sentry hub interface for creating transactions and spans. */\nexport interface SentryHubLike {\n startTransaction(ctx: SentryTransactionContextLike): SentryTransactionLike | undefined;\n getSpan(): SentrySpanLike | undefined;\n}\n\n/** Context passed to startTransaction. */\nexport interface SentryTransactionContextLike {\n name: string;\n traceId?: string;\n spanId?: string;\n parentSpanId?: string;\n startTimestamp?: number;\n instrumenter?: string;\n}\n\n/** Sentry transaction (root span). */\nexport interface SentryTransactionLike {\n startChild(ctx: SentrySpanContextLike): SentrySpanLike;\n setStatus(s: { status?: string }): void;\n setContext(name: string, ctx: Record<string, unknown>): void;\n finish(endTime?: number): void;\n name?: string;\n op?: string;\n}\n\n/** Context passed to startChild. */\nexport interface SentrySpanContextLike {\n description?: string;\n instrumenter?: string;\n startTimestamp?: number;\n spanId?: string;\n}\n\n/** Sentry span (child or transaction). */\nexport interface SentrySpanLike {\n setStatus(s: { status?: string }): void;\n setData(key: string, value: unknown): void;\n finish(endTime?: number): void;\n op?: string;\n description?: string;\n}\n\n/** Minimal Sentry SDK interface used by the processor. */\nexport interface SentryLike {\n getCurrentHub(): SentryHubLike;\n addGlobalEventProcessor(callback: (event: unknown) => unknown): void;\n captureException(error: Error, options?: { contexts?: Record<string, unknown> }): void;\n}\n\n/** Client with getDsn() for isSentryRequest detection. */\ninterface SentryClientLike {\n getDsn(): { host: string } | undefined;\n}\n\nconst INSTRUMENTER_OTEL = 'otel';\n\nexport class SentrySpanProcessor implements SpanProcessor {\n private readonly sentry: SentryLike;\n private readonly map = new Map<string, SentrySpanLike | SentryTransactionLike>();\n\n constructor(sentry: SentryLike) {\n this.sentry = sentry;\n\n if (typeof sentry.addGlobalEventProcessor === 'function') {\n sentry.addGlobalEventProcessor((event: unknown) => {\n const e = event as { contexts?: Record<string, unknown> };\n const otelSpan = trace.getActiveSpan();\n if (!otelSpan) return e;\n\n if (e.contexts && (e.contexts as Record<string, unknown>).trace) {\n return e;\n }\n\n const ctx = otelSpan.spanContext();\n e.contexts = {\n ...e.contexts,\n trace: {\n trace_id: ctx.traceId,\n span_id: ctx.spanId,\n },\n };\n return e;\n });\n }\n }\n\n private getDsnHost(): string | undefined {\n const hub = this.sentry.getCurrentHub();\n const client = (hub as unknown as { getClient?(): SentryClientLike }).getClient?.();\n return client?.getDsn()?.host;\n }\n\n onStart(span: Span, _parentContext: Context): void {\n const hub = this.sentry.getCurrentHub();\n if (!hub) return;\n\n const spanContext = span.spanContext();\n const otelSpanId = spanContext.spanId;\n const parentSpanId = span.parentSpanContext?.spanId;\n const parentSentry = parentSpanId ? this.map.get(parentSpanId) : undefined;\n\n const startTimestamp = convertOtelTimeToSeconds(span.startTime);\n\n if (parentSentry && 'startChild' in parentSentry) {\n const child = parentSentry.startChild({\n description: span.name,\n instrumenter: INSTRUMENTER_OTEL,\n startTimestamp,\n spanId: otelSpanId,\n });\n this.map.set(otelSpanId, child);\n } else {\n const traceData = getTraceData(span as unknown as ReadableSpan);\n const transaction = hub.startTransaction({\n name: span.name,\n traceId: traceData.traceId,\n spanId: traceData.spanId,\n parentSpanId: traceData.parentSpanId,\n startTimestamp,\n instrumenter: INSTRUMENTER_OTEL,\n });\n if (transaction) {\n this.map.set(otelSpanId, transaction);\n }\n }\n }\n\n onEnd(span: ReadableSpan): void {\n const otelSpanId = span.spanContext().spanId;\n const sentrySpan = this.map.get(otelSpanId);\n\n if (isSentryRequestSpan(span, () => this.getDsnHost())) {\n this.map.delete(otelSpanId);\n return;\n }\n\n generateSentryErrorsFromOtelSpan(span, (err, opts) =>\n this.sentry.captureException(err, opts),\n );\n\n if (!sentrySpan) return;\n\n const isTransaction = 'setContext' in sentrySpan && 'finish' in sentrySpan;\n\n if (isTransaction) {\n updateTransactionWithOtelData(sentrySpan as SentryTransactionLike, span);\n finishTransactionWithContextFromOtelData(\n sentrySpan as SentryTransactionLike,\n span,\n );\n } else {\n updateSpanWithOtelData(sentrySpan as SentrySpanLike, span);\n sentrySpan.finish(convertOtelTimeToSeconds(span.endTime));\n }\n\n this.map.delete(otelSpanId);\n }\n\n forceFlush(): Promise<void> {\n return Promise.resolve();\n }\n\n shutdown(): Promise<void> {\n this.map.clear();\n return Promise.resolve();\n }\n}\n\nexport function createSentrySpanProcessor(sentry: SentryLike): SentrySpanProcessor {\n return new SentrySpanProcessor(sentry);\n}\n","/**\n * SentryPropagator: injects and extracts sentry-trace and baggage headers\n * for trace propagation and dynamic sampling with Sentry.\n */\n\nimport {\n trace,\n propagation,\n type Context,\n type TextMapPropagator,\n type TextMapSetter,\n type TextMapGetter,\n} from '@opentelemetry/api';\n\n/** Context key for stored Sentry propagation data (sentry-trace, baggage). */\nexport const SENTRY_PROPAGATION_KEY = Symbol.for('autotel.sentry.propagation');\n\nexport interface SentryPropagationData {\n sentryTrace?: string;\n baggage?: string;\n}\n\n/** Sentry trace header format: traceid-spanid-sampled (sampled 1 or 0). */\nconst TRACE_FLAGS_SAMPLED = 0x1;\n\nfunction getSpanContextFromContext(context: Context): { traceId: string; spanId: string; traceFlags: number } | null {\n const span = trace.getSpan(context);\n if (!span) return null;\n const ctx = span.spanContext();\n return { traceId: ctx.traceId, spanId: ctx.spanId, traceFlags: ctx.traceFlags };\n}\n\nfunction formatSentryTrace(traceId: string, spanId: string, traceFlags: number): string {\n const sampled = (traceFlags & TRACE_FLAGS_SAMPLED) === TRACE_FLAGS_SAMPLED ? '1' : '0';\n return `${traceId}-${spanId}-${sampled}`;\n}\n\n/** Serialize OTel baggage to header value (key=value; key2=value2). */\nfunction serializeBaggage(context: Context): string | undefined {\n const baggage = propagation.getBaggage(context);\n if (!baggage) return undefined;\n const entries: string[] = [];\n const allEntries = baggage.getAllEntries();\n for (const [key, entry] of allEntries) {\n if (entry?.value !== undefined) {\n const encoded = encodeURIComponent(key) + '=' + encodeURIComponent(entry.value);\n entries.push(encoded);\n }\n }\n return entries.length > 0 ? entries.join('; ') : undefined;\n}\n\nexport class SentryPropagator implements TextMapPropagator {\n inject(context: Context, carrier: unknown, setter: TextMapSetter): void {\n const spanCtx = getSpanContextFromContext(context);\n if (!spanCtx) return;\n\n const sentryTrace = formatSentryTrace(\n spanCtx.traceId,\n spanCtx.spanId,\n spanCtx.traceFlags,\n );\n setter.set(carrier, 'sentry-trace', sentryTrace);\n\n const baggageStr = serializeBaggage(context);\n if (baggageStr) {\n setter.set(carrier, 'baggage', baggageStr);\n }\n }\n\n extract(context: Context, carrier: unknown, getter: TextMapGetter): Context {\n const keys = getter.keys(carrier);\n let sentryTrace: string | undefined;\n let baggageStr: string | undefined;\n\n for (const key of keys) {\n const lower = key.toLowerCase();\n const value = getter.get(carrier, key);\n const str = Array.isArray(value) ? value[0] : value;\n if (lower === 'sentry-trace' && typeof str === 'string') sentryTrace = str;\n if (lower === 'baggage' && typeof str === 'string') baggageStr = str;\n }\n\n const data: SentryPropagationData = {};\n if (sentryTrace) data.sentryTrace = sentryTrace;\n if (baggageStr) data.baggage = baggageStr;\n\n if (Object.keys(data).length === 0) return context;\n\n return context.setValue(SENTRY_PROPAGATION_KEY, data);\n }\n\n fields(): string[] {\n return ['sentry-trace', 'baggage'];\n }\n}\n"]}
|
package/dist/index.d.cts
ADDED
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
import { Context, TextMapPropagator, TextMapSetter, TextMapGetter } from '@opentelemetry/api';
|
|
2
|
+
import { SpanProcessor, Span, ReadableSpan } from '@opentelemetry/sdk-trace-base';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* SentrySpanProcessor: converts OpenTelemetry spans to Sentry transactions/spans.
|
|
6
|
+
* Register with init({ spanProcessors: [new SentrySpanProcessor(Sentry)] }).
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
/** Minimal Sentry hub interface for creating transactions and spans. */
|
|
10
|
+
interface SentryHubLike {
|
|
11
|
+
startTransaction(ctx: SentryTransactionContextLike): SentryTransactionLike | undefined;
|
|
12
|
+
getSpan(): SentrySpanLike | undefined;
|
|
13
|
+
}
|
|
14
|
+
/** Context passed to startTransaction. */
|
|
15
|
+
interface SentryTransactionContextLike {
|
|
16
|
+
name: string;
|
|
17
|
+
traceId?: string;
|
|
18
|
+
spanId?: string;
|
|
19
|
+
parentSpanId?: string;
|
|
20
|
+
startTimestamp?: number;
|
|
21
|
+
instrumenter?: string;
|
|
22
|
+
}
|
|
23
|
+
/** Sentry transaction (root span). */
|
|
24
|
+
interface SentryTransactionLike {
|
|
25
|
+
startChild(ctx: SentrySpanContextLike): SentrySpanLike;
|
|
26
|
+
setStatus(s: {
|
|
27
|
+
status?: string;
|
|
28
|
+
}): void;
|
|
29
|
+
setContext(name: string, ctx: Record<string, unknown>): void;
|
|
30
|
+
finish(endTime?: number): void;
|
|
31
|
+
name?: string;
|
|
32
|
+
op?: string;
|
|
33
|
+
}
|
|
34
|
+
/** Context passed to startChild. */
|
|
35
|
+
interface SentrySpanContextLike {
|
|
36
|
+
description?: string;
|
|
37
|
+
instrumenter?: string;
|
|
38
|
+
startTimestamp?: number;
|
|
39
|
+
spanId?: string;
|
|
40
|
+
}
|
|
41
|
+
/** Sentry span (child or transaction). */
|
|
42
|
+
interface SentrySpanLike {
|
|
43
|
+
setStatus(s: {
|
|
44
|
+
status?: string;
|
|
45
|
+
}): void;
|
|
46
|
+
setData(key: string, value: unknown): void;
|
|
47
|
+
finish(endTime?: number): void;
|
|
48
|
+
op?: string;
|
|
49
|
+
description?: string;
|
|
50
|
+
}
|
|
51
|
+
/** Minimal Sentry SDK interface used by the processor. */
|
|
52
|
+
interface SentryLike {
|
|
53
|
+
getCurrentHub(): SentryHubLike;
|
|
54
|
+
addGlobalEventProcessor(callback: (event: unknown) => unknown): void;
|
|
55
|
+
captureException(error: Error, options?: {
|
|
56
|
+
contexts?: Record<string, unknown>;
|
|
57
|
+
}): void;
|
|
58
|
+
}
|
|
59
|
+
declare class SentrySpanProcessor implements SpanProcessor {
|
|
60
|
+
private readonly sentry;
|
|
61
|
+
private readonly map;
|
|
62
|
+
constructor(sentry: SentryLike);
|
|
63
|
+
private getDsnHost;
|
|
64
|
+
onStart(span: Span, _parentContext: Context): void;
|
|
65
|
+
onEnd(span: ReadableSpan): void;
|
|
66
|
+
forceFlush(): Promise<void>;
|
|
67
|
+
shutdown(): Promise<void>;
|
|
68
|
+
}
|
|
69
|
+
declare function createSentrySpanProcessor(sentry: SentryLike): SentrySpanProcessor;
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* SentryPropagator: injects and extracts sentry-trace and baggage headers
|
|
73
|
+
* for trace propagation and dynamic sampling with Sentry.
|
|
74
|
+
*/
|
|
75
|
+
|
|
76
|
+
/** Context key for stored Sentry propagation data (sentry-trace, baggage). */
|
|
77
|
+
declare const SENTRY_PROPAGATION_KEY: unique symbol;
|
|
78
|
+
interface SentryPropagationData {
|
|
79
|
+
sentryTrace?: string;
|
|
80
|
+
baggage?: string;
|
|
81
|
+
}
|
|
82
|
+
declare class SentryPropagator implements TextMapPropagator {
|
|
83
|
+
inject(context: Context, carrier: unknown, setter: TextMapSetter): void;
|
|
84
|
+
extract(context: Context, carrier: unknown, getter: TextMapGetter): Context;
|
|
85
|
+
fields(): string[];
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
export { SENTRY_PROPAGATION_KEY, type SentryLike, type SentryPropagationData, SentryPropagator, SentrySpanProcessor, createSentrySpanProcessor };
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
import { Context, TextMapPropagator, TextMapSetter, TextMapGetter } from '@opentelemetry/api';
|
|
2
|
+
import { SpanProcessor, Span, ReadableSpan } from '@opentelemetry/sdk-trace-base';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* SentrySpanProcessor: converts OpenTelemetry spans to Sentry transactions/spans.
|
|
6
|
+
* Register with init({ spanProcessors: [new SentrySpanProcessor(Sentry)] }).
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
/** Minimal Sentry hub interface for creating transactions and spans. */
|
|
10
|
+
interface SentryHubLike {
|
|
11
|
+
startTransaction(ctx: SentryTransactionContextLike): SentryTransactionLike | undefined;
|
|
12
|
+
getSpan(): SentrySpanLike | undefined;
|
|
13
|
+
}
|
|
14
|
+
/** Context passed to startTransaction. */
|
|
15
|
+
interface SentryTransactionContextLike {
|
|
16
|
+
name: string;
|
|
17
|
+
traceId?: string;
|
|
18
|
+
spanId?: string;
|
|
19
|
+
parentSpanId?: string;
|
|
20
|
+
startTimestamp?: number;
|
|
21
|
+
instrumenter?: string;
|
|
22
|
+
}
|
|
23
|
+
/** Sentry transaction (root span). */
|
|
24
|
+
interface SentryTransactionLike {
|
|
25
|
+
startChild(ctx: SentrySpanContextLike): SentrySpanLike;
|
|
26
|
+
setStatus(s: {
|
|
27
|
+
status?: string;
|
|
28
|
+
}): void;
|
|
29
|
+
setContext(name: string, ctx: Record<string, unknown>): void;
|
|
30
|
+
finish(endTime?: number): void;
|
|
31
|
+
name?: string;
|
|
32
|
+
op?: string;
|
|
33
|
+
}
|
|
34
|
+
/** Context passed to startChild. */
|
|
35
|
+
interface SentrySpanContextLike {
|
|
36
|
+
description?: string;
|
|
37
|
+
instrumenter?: string;
|
|
38
|
+
startTimestamp?: number;
|
|
39
|
+
spanId?: string;
|
|
40
|
+
}
|
|
41
|
+
/** Sentry span (child or transaction). */
|
|
42
|
+
interface SentrySpanLike {
|
|
43
|
+
setStatus(s: {
|
|
44
|
+
status?: string;
|
|
45
|
+
}): void;
|
|
46
|
+
setData(key: string, value: unknown): void;
|
|
47
|
+
finish(endTime?: number): void;
|
|
48
|
+
op?: string;
|
|
49
|
+
description?: string;
|
|
50
|
+
}
|
|
51
|
+
/** Minimal Sentry SDK interface used by the processor. */
|
|
52
|
+
interface SentryLike {
|
|
53
|
+
getCurrentHub(): SentryHubLike;
|
|
54
|
+
addGlobalEventProcessor(callback: (event: unknown) => unknown): void;
|
|
55
|
+
captureException(error: Error, options?: {
|
|
56
|
+
contexts?: Record<string, unknown>;
|
|
57
|
+
}): void;
|
|
58
|
+
}
|
|
59
|
+
declare class SentrySpanProcessor implements SpanProcessor {
|
|
60
|
+
private readonly sentry;
|
|
61
|
+
private readonly map;
|
|
62
|
+
constructor(sentry: SentryLike);
|
|
63
|
+
private getDsnHost;
|
|
64
|
+
onStart(span: Span, _parentContext: Context): void;
|
|
65
|
+
onEnd(span: ReadableSpan): void;
|
|
66
|
+
forceFlush(): Promise<void>;
|
|
67
|
+
shutdown(): Promise<void>;
|
|
68
|
+
}
|
|
69
|
+
declare function createSentrySpanProcessor(sentry: SentryLike): SentrySpanProcessor;
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* SentryPropagator: injects and extracts sentry-trace and baggage headers
|
|
73
|
+
* for trace propagation and dynamic sampling with Sentry.
|
|
74
|
+
*/
|
|
75
|
+
|
|
76
|
+
/** Context key for stored Sentry propagation data (sentry-trace, baggage). */
|
|
77
|
+
declare const SENTRY_PROPAGATION_KEY: unique symbol;
|
|
78
|
+
interface SentryPropagationData {
|
|
79
|
+
sentryTrace?: string;
|
|
80
|
+
baggage?: string;
|
|
81
|
+
}
|
|
82
|
+
declare class SentryPropagator implements TextMapPropagator {
|
|
83
|
+
inject(context: Context, carrier: unknown, setter: TextMapSetter): void;
|
|
84
|
+
extract(context: Context, carrier: unknown, getter: TextMapGetter): Context;
|
|
85
|
+
fields(): string[];
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
export { SENTRY_PROPAGATION_KEY, type SentryLike, type SentryPropagationData, SentryPropagator, SentrySpanProcessor, createSentrySpanProcessor };
|