🚀 Socket Launch Week Day 5:Introducing Repository Access Permissions and Custom Roles.Learn more
Sign In

@sentry/opentelemetry

Package Overview
Dependencies
Maintainers
1
Versions
312
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@sentry/opentelemetry - npm Package Compare versions

Comparing version
10.60.0
to
10.61.0
+1702
build/cjs/resource-PpJQa_6P.js
const api = require('@opentelemetry/api');
const core = require('@sentry/core');
const attributes = require('@sentry/conventions/attributes');
const core$1 = require('@opentelemetry/core');
const sdkTraceBase = require('@opentelemetry/sdk-trace-base');
const SEMANTIC_ATTRIBUTE_SENTRY_PARENT_IS_REMOTE = "sentry.parentIsRemote";
const SEMANTIC_ATTRIBUTE_SENTRY_GRAPHQL_OPERATION = "sentry.graphql.operation";
function getParentSpanId(span) {
if ("parentSpanId" in span) {
return span.parentSpanId;
} else if ("parentSpanContext" in span) {
return span.parentSpanContext?.spanId;
}
return void 0;
}
function spanHasAttributes(span) {
const castSpan = span;
return !!castSpan.attributes && typeof castSpan.attributes === "object";
}
function spanHasKind(span) {
const castSpan = span;
return typeof castSpan.kind === "number";
}
function spanHasStatus(span) {
const castSpan = span;
return !!castSpan.status;
}
function spanHasName(span) {
const castSpan = span;
return !!castSpan.name;
}
function spanHasParentId(span) {
const castSpan = span;
return !!getParentSpanId(castSpan);
}
function spanHasEvents(span) {
const castSpan = span;
return Array.isArray(castSpan.events);
}
function getRequestSpanData(span) {
if (!spanHasAttributes(span)) {
return {};
}
const maybeUrlAttribute = span.attributes[attributes.URL_FULL] || span.attributes[attributes.HTTP_URL];
const data = {
url: maybeUrlAttribute,
// eslint-disable-next-line typescript/no-deprecated
"http.method": span.attributes[attributes.HTTP_REQUEST_METHOD] || span.attributes[attributes.HTTP_METHOD]
};
if (!data["http.method"] && data.url) {
data["http.method"] = "GET";
}
try {
if (typeof maybeUrlAttribute === "string") {
const url = core.parseUrl(maybeUrlAttribute);
data.url = core.getSanitizedUrlString(url);
if (url.search) {
data["http.query"] = url.search;
}
if (url.hash) {
data["http.fragment"] = url.hash;
}
}
} catch {
}
return data;
}
function wrapClientClass(ClientClass) {
class OpenTelemetryClient extends ClientClass {
constructor(...args) {
super(...args);
}
/** Get the OTEL tracer. */
get tracer() {
if (this._tracer) {
return this._tracer;
}
const name = "@sentry/opentelemetry";
const version = core.SDK_VERSION;
const tracer = api.trace.getTracer(name, version);
this._tracer = tracer;
return tracer;
}
/**
* @inheritDoc
*/
async flush(timeout) {
const provider = this.traceProvider;
await provider?.forceFlush();
return super.flush(timeout);
}
}
return OpenTelemetryClient;
}
function getSpanKind(span) {
if (spanHasKind(span)) {
return span.kind;
}
return api.SpanKind.INTERNAL;
}
const SENTRY_TRACE_HEADER = "sentry-trace";
const SENTRY_BAGGAGE_HEADER = "baggage";
const SENTRY_TRACE_STATE_DSC = "sentry.dsc";
const SENTRY_TRACE_STATE_SAMPLED_NOT_RECORDING = "sentry.sampled_not_recording";
const SENTRY_TRACE_STATE_URL = "sentry.url";
const SENTRY_TRACE_STATE_SAMPLE_RAND = "sentry.sample_rand";
const SENTRY_TRACE_STATE_SAMPLE_RATE = "sentry.sample_rate";
const SENTRY_TRACE_STATE_CHILD_IGNORED = "sentry.ignored";
const SENTRY_TRACE_STATE_SEGMENT_IGNORED = "sentry.segment_ignored";
const SENTRY_SCOPES_CONTEXT_KEY = api.createContextKey("sentry_scopes");
const SENTRY_FORK_ISOLATION_SCOPE_CONTEXT_KEY = api.createContextKey("sentry_fork_isolation_scope");
const SENTRY_FORK_SET_SCOPE_CONTEXT_KEY = api.createContextKey("sentry_fork_set_scope");
const SENTRY_FORK_SET_ISOLATION_SCOPE_CONTEXT_KEY = api.createContextKey("sentry_fork_set_isolation_scope");
const SCOPE_CONTEXT_FIELD = "_scopeContext";
function getScopesFromContext(context) {
return context.getValue(SENTRY_SCOPES_CONTEXT_KEY);
}
function setScopesOnContext(context, scopes) {
return context.setValue(SENTRY_SCOPES_CONTEXT_KEY, scopes);
}
function setContextOnScope(scope, context) {
core.addNonEnumerableProperty(scope, SCOPE_CONTEXT_FIELD, core.makeWeakRef(context));
}
function getContextFromScope(scope) {
return core.derefWeakRef(scope[SCOPE_CONTEXT_FIELD]);
}
function isSentryRequestSpan(span) {
if (!spanHasAttributes(span)) {
return false;
}
const { attributes: attributes$1 } = span;
const httpUrl = attributes$1[attributes.HTTP_URL] || attributes$1[attributes.URL_FULL];
if (!httpUrl) {
return false;
}
return core.isSentryRequestUrl(httpUrl.toString(), core.getClient());
}
function getSamplingDecision(spanContext) {
const { traceFlags, traceState } = spanContext;
const sampledNotRecording = traceState ? traceState.get(SENTRY_TRACE_STATE_SAMPLED_NOT_RECORDING) === "1" : false;
if (traceFlags === api.TraceFlags.SAMPLED) {
return true;
}
if (sampledNotRecording) {
return false;
}
const dscString = traceState ? traceState.get(SENTRY_TRACE_STATE_DSC) : void 0;
const dsc = dscString ? core.baggageHeaderToDynamicSamplingContext(dscString) : void 0;
if (dsc?.sampled === "true") {
return true;
}
if (dsc?.sampled === "false") {
return false;
}
return void 0;
}
function inferSpanData(spanName, attributes$1, kind) {
const httpMethod = attributes$1[attributes.HTTP_REQUEST_METHOD] || attributes$1[attributes.HTTP_METHOD];
if (httpMethod) {
return descriptionForHttpMethod({ attributes: attributes$1, name: spanName, kind }, httpMethod);
}
const dbSystem = attributes$1[attributes.DB_SYSTEM_NAME] || attributes$1[attributes.DB_SYSTEM];
const opIsCache = typeof attributes$1[core.SEMANTIC_ATTRIBUTE_SENTRY_OP] === "string" && attributes$1[core.SEMANTIC_ATTRIBUTE_SENTRY_OP].startsWith("cache.");
if (dbSystem && !opIsCache) {
return descriptionForDbSystem({ attributes: attributes$1, name: spanName });
}
const customSourceOrRoute = attributes$1[core.SEMANTIC_ATTRIBUTE_SENTRY_SOURCE] === "custom" ? "custom" : "route";
const rpcService = attributes$1[attributes.RPC_SERVICE];
if (rpcService) {
return {
...getUserUpdatedNameAndSource(spanName, attributes$1, "route"),
op: "rpc"
};
}
const messagingSystem = attributes$1[attributes.MESSAGING_SYSTEM];
if (messagingSystem) {
return {
...getUserUpdatedNameAndSource(spanName, attributes$1, customSourceOrRoute),
op: "message"
};
}
const faasTrigger = attributes$1[attributes.FAAS_TRIGGER];
if (faasTrigger) {
return {
...getUserUpdatedNameAndSource(spanName, attributes$1, customSourceOrRoute),
op: faasTrigger.toString()
};
}
return { op: void 0, description: spanName, source: "custom" };
}
function parseSpanDescription(span) {
const attributes = spanHasAttributes(span) ? span.attributes : {};
const name = spanHasName(span) ? span.name : "<unknown>";
const kind = getSpanKind(span);
return inferSpanData(name, attributes, kind);
}
function descriptionForDbSystem({ attributes: attributes$1, name }) {
const userDefinedName = attributes$1[core.SEMANTIC_ATTRIBUTE_SENTRY_CUSTOM_SPAN_NAME];
if (typeof userDefinedName === "string") {
return {
op: "db",
description: userDefinedName,
source: attributes$1[core.SEMANTIC_ATTRIBUTE_SENTRY_SOURCE] || "custom"
};
}
if (attributes$1[core.SEMANTIC_ATTRIBUTE_SENTRY_SOURCE] === "custom") {
return { op: "db", description: name, source: "custom" };
}
const statement = attributes$1[attributes.DB_STATEMENT];
const description = statement ? statement.toString() : name;
return { op: "db", description, source: "task" };
}
function descriptionForHttpMethod({ name, kind, attributes }, httpMethod) {
const opParts = ["http"];
switch (kind) {
case api.SpanKind.CLIENT:
opParts.push("client");
break;
case api.SpanKind.SERVER:
opParts.push("server");
break;
}
if (attributes["sentry.http.prefetch"]) {
opParts.push("prefetch");
}
const { urlPath, url, query, fragment, hasRoute } = getSanitizedUrl(attributes, kind);
if (!urlPath) {
return { ...getUserUpdatedNameAndSource(name, attributes), op: opParts.join(".") };
}
const graphqlOperationsAttribute = attributes[SEMANTIC_ATTRIBUTE_SENTRY_GRAPHQL_OPERATION];
const baseDescription = `${httpMethod} ${urlPath}`;
const inferredDescription = graphqlOperationsAttribute ? `${baseDescription} (${getGraphqlOperationNamesFromAttribute(graphqlOperationsAttribute)})` : baseDescription;
const inferredSource = hasRoute || urlPath === "/" ? "route" : "url";
const data = {};
if (url) {
data.url = url;
}
if (query) {
data["http.query"] = query;
}
if (fragment) {
data["http.fragment"] = fragment;
}
const isClientOrServerKind = kind === api.SpanKind.CLIENT || kind === api.SpanKind.SERVER;
const origin = attributes[core.SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN] || "manual";
const isManualSpan = !`${origin}`.startsWith("auto");
const alreadyHasCustomSource = attributes[core.SEMANTIC_ATTRIBUTE_SENTRY_SOURCE] === "custom";
const customSpanName = attributes[core.SEMANTIC_ATTRIBUTE_SENTRY_CUSTOM_SPAN_NAME];
const useInferredDescription = !alreadyHasCustomSource && customSpanName == null && (isClientOrServerKind || !isManualSpan);
const { description, source } = useInferredDescription ? { description: inferredDescription, source: inferredSource } : getUserUpdatedNameAndSource(name, attributes);
return {
op: opParts.join("."),
description,
source,
data
};
}
function getGraphqlOperationNamesFromAttribute(attr) {
if (Array.isArray(attr)) {
const sorted = attr.slice().sort();
if (sorted.length <= 5) {
return sorted.join(", ");
} else {
return `${sorted.slice(0, 5).join(", ")}, +${sorted.length - 5}`;
}
}
return `${attr}`;
}
function getSanitizedUrl(attributes$1, kind) {
const httpTarget = attributes$1[attributes.HTTP_TARGET];
const httpUrl = attributes$1[attributes.HTTP_URL] || attributes$1[attributes.URL_FULL];
const httpRoute = attributes$1[attributes.HTTP_ROUTE];
const parsedUrl = typeof httpUrl === "string" ? core.parseUrl(httpUrl) : void 0;
const url = parsedUrl ? core.getSanitizedUrlString(parsedUrl) : void 0;
const query = parsedUrl?.search || void 0;
const fragment = parsedUrl?.hash || void 0;
if (typeof httpRoute === "string") {
return { urlPath: httpRoute, url, query, fragment, hasRoute: true };
}
if (kind === api.SpanKind.SERVER && typeof httpTarget === "string") {
return { urlPath: core.stripUrlQueryAndFragment(httpTarget), url, query, fragment, hasRoute: false };
}
if (parsedUrl) {
return { urlPath: url, url, query, fragment, hasRoute: false };
}
if (typeof httpTarget === "string") {
return { urlPath: core.stripUrlQueryAndFragment(httpTarget), url, query, fragment, hasRoute: false };
}
return { urlPath: void 0, url, query, fragment, hasRoute: false };
}
function getUserUpdatedNameAndSource(originalName, attributes, fallbackSource = "custom") {
const source = attributes[core.SEMANTIC_ATTRIBUTE_SENTRY_SOURCE] || fallbackSource;
const description = attributes[core.SEMANTIC_ATTRIBUTE_SENTRY_CUSTOM_SPAN_NAME];
if (description && typeof description === "string") {
return {
description,
source
};
}
return { description: originalName, source };
}
function enhanceDscWithOpenTelemetryRootSpanName(client) {
client.on("createDsc", (dsc, rootSpan) => {
if (!rootSpan) {
return;
}
const jsonSpan = core.spanToJSON(rootSpan);
const attributes = jsonSpan.data;
const source = attributes[core.SEMANTIC_ATTRIBUTE_SENTRY_SOURCE];
const { description } = spanHasName(rootSpan) ? parseSpanDescription(rootSpan) : { description: void 0 };
if (source !== "url" && description) {
dsc.transaction = description;
}
if (core.hasSpansEnabled()) {
const sampled = getSamplingDecision(rootSpan.spanContext());
dsc.sampled = sampled == void 0 ? void 0 : String(sampled);
}
});
}
function getActiveSpan() {
return api.trace.getActiveSpan();
}
const DEBUG_BUILD = (typeof __SENTRY_DEBUG__ === 'undefined' || __SENTRY_DEBUG__);
class TraceState {
constructor() {
this._internalState = /* @__PURE__ */ new Map();
}
/** @inheritDoc */
set(key, value) {
const next = this._clone();
if (next._internalState.has(key)) {
next._internalState.delete(key);
}
next._internalState.set(key, value);
return next;
}
/** @inheritDoc */
unset(key) {
const next = this._clone();
next._internalState.delete(key);
return next;
}
/** @inheritDoc */
get(key) {
return this._internalState.get(key);
}
/** @inheritDoc */
serialize() {
return Array.from(this._internalState.keys()).reverse().map((key) => `${key}=${this._internalState.get(key)}`).join(",");
}
_clone() {
const next = new TraceState();
next._internalState = new Map(this._internalState);
return next;
}
}
function makeTraceState({
dsc,
sampled
}) {
const dscString = dsc ? core.dynamicSamplingContextToSentryBaggageHeader(dsc) : void 0;
const traceStateBase = new TraceState();
const traceStateWithDsc = dscString ? traceStateBase.set(SENTRY_TRACE_STATE_DSC, dscString) : traceStateBase;
return sampled === false ? traceStateWithDsc.set(SENTRY_TRACE_STATE_SAMPLED_NOT_RECORDING, "1") : traceStateWithDsc;
}
const setupElements = /* @__PURE__ */ new Set();
function openTelemetrySetupCheck() {
return Array.from(setupElements);
}
function setIsSetup(element) {
setupElements.add(element);
}
class SentryPropagator extends core$1.W3CBaggagePropagator {
constructor() {
super();
setIsSetup("SentryPropagator");
this._urlMatchesTargetsMap = new core.LRUMap(100);
}
/**
* @inheritDoc
*/
inject(context2, carrier, setter) {
if (core$1.isTracingSuppressed(context2)) {
DEBUG_BUILD && core.debug.log("[Tracing] Not injecting trace data for url because tracing is suppressed.");
return;
}
const activeSpan = api.trace.getSpan(context2);
const url = activeSpan && getCurrentURL(activeSpan);
const { tracePropagationTargets, propagateTraceparent } = core.getClient()?.getOptions() || {};
if (!core.shouldPropagateTraceForUrl(url, tracePropagationTargets, this._urlMatchesTargetsMap)) {
DEBUG_BUILD && core.debug.log("[Tracing] Not injecting trace data for url because it does not match tracePropagationTargets:", url);
return;
}
const existingBaggageHeader = getExistingBaggage(carrier);
const existingSentryTraceHeader = getExistingSentryTrace(carrier);
let baggage = api.propagation.getBaggage(context2) || api.propagation.createBaggage({});
const { dynamicSamplingContext, traceId, spanId, sampled } = getInjectionData(context2);
if (existingBaggageHeader) {
const baggageEntries = core.parseBaggageHeader(existingBaggageHeader);
if (baggageEntries) {
Object.entries(baggageEntries).forEach(([key, value]) => {
if (!existingSentryTraceHeader && key.startsWith(core.SENTRY_BAGGAGE_KEY_PREFIX)) {
return;
}
baggage = baggage.setEntry(key, { value });
});
}
}
if (!existingSentryTraceHeader && dynamicSamplingContext) {
baggage = Object.entries(dynamicSamplingContext).reduce((b, [dscKey, dscValue]) => {
if (dscValue) {
return b.setEntry(`${core.SENTRY_BAGGAGE_KEY_PREFIX}${dscKey}`, { value: dscValue });
}
return b;
}, baggage);
}
if (!existingSentryTraceHeader && traceId && traceId !== api.INVALID_TRACEID) {
setter.set(carrier, SENTRY_TRACE_HEADER, core.generateSentryTraceHeader(traceId, spanId, sampled));
if (propagateTraceparent) {
setter.set(carrier, "traceparent", core.generateTraceparentHeader(traceId, spanId, sampled));
}
}
super.inject(api.propagation.setBaggage(context2, baggage), carrier, setter);
}
/**
* @inheritDoc
*/
extract(context2, carrier, getter) {
const maybeSentryTraceHeader = getter.get(carrier, SENTRY_TRACE_HEADER);
const baggage = getter.get(carrier, SENTRY_BAGGAGE_HEADER);
const sentryTrace = maybeSentryTraceHeader ? Array.isArray(maybeSentryTraceHeader) ? maybeSentryTraceHeader[0] : maybeSentryTraceHeader : void 0;
return ensureScopesOnContext(getContextWithRemoteActiveSpan(context2, { sentryTrace, baggage }));
}
/**
* @inheritDoc
*/
fields() {
return [SENTRY_TRACE_HEADER, SENTRY_BAGGAGE_HEADER, "traceparent"];
}
}
function getInjectionData(context2, options = {}) {
const span = api.trace.getSpan(context2);
if (span?.spanContext().isRemote) {
const spanContext = span.spanContext();
const dynamicSamplingContext2 = core.getDynamicSamplingContextFromSpan(span);
return {
dynamicSamplingContext: dynamicSamplingContext2,
traceId: spanContext.traceId,
spanId: void 0,
sampled: getSamplingDecision(spanContext)
// TODO: Do we need to change something here?
};
}
if (span) {
const spanContext = span.spanContext();
const dynamicSamplingContext2 = core.getDynamicSamplingContextFromSpan(span);
return {
dynamicSamplingContext: dynamicSamplingContext2,
traceId: spanContext.traceId,
spanId: spanContext.spanId,
sampled: getSamplingDecision(spanContext)
// TODO: Do we need to change something here?
};
}
const scope = options.scope || getScopesFromContext(context2)?.scope || core.getCurrentScope();
const client = options.client || core.getClient();
const propagationContext = scope.getPropagationContext();
const dynamicSamplingContext = client ? core.getDynamicSamplingContextFromScope(client, scope) : void 0;
return {
dynamicSamplingContext,
traceId: propagationContext.traceId,
spanId: propagationContext.propagationSpanId,
sampled: propagationContext.sampled
};
}
function getContextWithRemoteActiveSpan(ctx, { sentryTrace, baggage }) {
const propagationContext = core.propagationContextFromHeaders(sentryTrace, baggage);
const { traceId, parentSpanId, sampled, dsc } = propagationContext;
const client = core.getClient();
const incomingDsc = core.baggageHeaderToDynamicSamplingContext(baggage);
if (!parentSpanId || client && !core.shouldContinueTrace(client, incomingDsc?.org_id)) {
return ctx;
}
const spanContext = generateRemoteSpanContext({
traceId,
spanId: parentSpanId,
sampled,
dsc
});
return api.trace.setSpanContext(ctx, spanContext);
}
function continueTraceAsRemoteSpan(ctx, options, callback) {
const ctxWithSpanContext = ensureScopesOnContext(getContextWithRemoteActiveSpan(ctx, options));
return api.context.with(ctxWithSpanContext, callback);
}
function ensureScopesOnContext(ctx) {
const scopes = getScopesFromContext(ctx);
const newScopes = {
// If we have no scope here, this is most likely either the root context or a context manually derived from it
// In this case, we want to fork the current scope, to ensure we do not pollute the root scope
scope: scopes ? scopes.scope : core.getCurrentScope().clone(),
isolationScope: scopes ? scopes.isolationScope : core.getIsolationScope()
};
return setScopesOnContext(ctx, newScopes);
}
function getExistingBaggage(carrier) {
try {
const baggage = carrier[SENTRY_BAGGAGE_HEADER];
return Array.isArray(baggage) ? baggage.join(",") : baggage;
} catch {
return void 0;
}
}
function getExistingSentryTrace(carrier) {
try {
return carrier[SENTRY_TRACE_HEADER];
} catch {
return void 0;
}
}
function getCurrentURL(span) {
const spanData = core.spanToJSON(span).data;
const urlAttribute = spanData[attributes.HTTP_URL] || spanData[attributes.URL_FULL];
if (typeof urlAttribute === "string") {
return urlAttribute;
}
const urlTraceState = span.spanContext().traceState?.get(SENTRY_TRACE_STATE_URL);
if (urlTraceState) {
return urlTraceState;
}
return void 0;
}
function generateRemoteSpanContext({
spanId,
traceId,
sampled,
dsc
}) {
const traceState = makeTraceState({
dsc,
sampled
});
const spanContext = {
traceId,
spanId,
isRemote: true,
traceFlags: sampled ? api.TraceFlags.SAMPLED : api.TraceFlags.NONE,
traceState
};
return spanContext;
}
function _startSpan(options, callback, autoEnd) {
const tracer = getTracer();
const { name, parentSpan: customParentSpan } = options;
const wrapper = getActiveSpanWrapper(customParentSpan);
return wrapper(() => {
const activeCtx = getContext(options.scope, options.forceTransaction);
const missingRequiredParent = options.onlyIfParent && !api.trace.getSpan(activeCtx);
const ctx = missingRequiredParent ? core$1.suppressTracing(activeCtx) : activeCtx;
if (missingRequiredParent) {
core.getClient()?.recordDroppedEvent("no_parent_span", "span");
}
const spanOptions = getSpanOptions(options);
if (!core.hasSpansEnabled()) {
const suppressedCtx = core$1.isTracingSuppressed(ctx) ? ctx : core$1.suppressTracing(ctx);
return api.context.with(suppressedCtx, () => {
return tracer.startActiveSpan(name, spanOptions, suppressedCtx, (span) => {
patchSpanEnd(span);
return api.context.with(activeCtx, () => {
return core.handleCallbackErrors(
() => callback(span),
() => {
if (core.spanToJSON(span).status === void 0) {
span.setStatus({ code: api.SpanStatusCode.ERROR });
}
},
autoEnd ? () => span.end() : void 0
);
});
});
});
}
return tracer.startActiveSpan(name, spanOptions, ctx, (span) => {
patchSpanEnd(span);
return core.handleCallbackErrors(
() => callback(span),
() => {
if (core.spanToJSON(span).status === void 0) {
span.setStatus({ code: api.SpanStatusCode.ERROR });
}
},
autoEnd ? () => span.end() : void 0
);
});
});
}
function startSpan(options, callback) {
return _startSpan(options, callback, true);
}
function startSpanManual(options, callback) {
return _startSpan(options, (span) => callback(span, () => span.end()), false);
}
function startInactiveSpan(options) {
const tracer = getTracer();
const { name, parentSpan: customParentSpan } = options;
const wrapper = getActiveSpanWrapper(customParentSpan);
return wrapper(() => {
const activeCtx = getContext(options.scope, options.forceTransaction);
const missingRequiredParent = options.onlyIfParent && !api.trace.getSpan(activeCtx);
let ctx = missingRequiredParent ? core$1.suppressTracing(activeCtx) : activeCtx;
if (missingRequiredParent) {
core.getClient()?.recordDroppedEvent("no_parent_span", "span");
}
const spanOptions = getSpanOptions(options);
if (!core.hasSpansEnabled()) {
ctx = core$1.isTracingSuppressed(ctx) ? ctx : core$1.suppressTracing(ctx);
}
const span = tracer.startSpan(name, spanOptions, ctx);
patchSpanEnd(span);
return span;
});
}
function withActiveSpan(span, callback) {
const newContextWithActiveSpan = span ? api.trace.setSpan(api.context.active(), span) : api.trace.deleteSpan(api.context.active());
return api.context.with(newContextWithActiveSpan, () => callback(core.getCurrentScope()));
}
function getTracer() {
const client = core.getClient();
return client?.tracer || api.trace.getTracer("@sentry/opentelemetry", core.SDK_VERSION);
}
function getSpanOptions(options) {
const { startTime, attributes, kind, op, links } = options;
const fixedStartTime = typeof startTime === "number" ? ensureTimestampInMilliseconds(startTime) : startTime;
return {
attributes: op ? {
[core.SEMANTIC_ATTRIBUTE_SENTRY_OP]: op,
...attributes
} : attributes,
kind,
links,
startTime: fixedStartTime
};
}
function ensureTimestampInMilliseconds(timestamp) {
const isMs = timestamp < 9999999999;
return isMs ? timestamp * 1e3 : timestamp;
}
function patchSpanEnd(span) {
const originalEnd = span.end.bind(span);
span.end = (endTime) => {
return originalEnd(typeof endTime === "number" ? ensureTimestampInMilliseconds(endTime) : endTime);
};
}
function getContext(scope, forceTransaction) {
const ctx = getContextForScope(scope);
const parentSpan = api.trace.getSpan(ctx);
if (!parentSpan) {
return ctx;
}
if (!forceTransaction) {
return ctx;
}
const ctxWithoutSpan = api.trace.deleteSpan(ctx);
const { spanId, traceId } = parentSpan.spanContext();
const sampled = getSamplingDecision(parentSpan.spanContext());
const rootSpan = core.getRootSpan(parentSpan);
const dsc = core.getDynamicSamplingContextFromSpan(rootSpan);
const traceState = makeTraceState({
dsc,
sampled
});
const spanOptions = {
traceId,
spanId,
isRemote: true,
traceFlags: sampled ? api.TraceFlags.SAMPLED : api.TraceFlags.NONE,
traceState
};
const ctxWithSpanContext = api.trace.setSpanContext(ctxWithoutSpan, spanOptions);
return ctxWithSpanContext;
}
function getContextForScope(scope) {
if (scope) {
const ctx = getContextFromScope(scope);
if (ctx) {
return ctx;
}
}
return api.context.active();
}
function continueTrace(options, callback) {
return continueTraceAsRemoteSpan(api.context.active(), options, callback);
}
function startNewTrace(callback) {
const traceId = core.generateTraceId();
const spanId = core.generateSpanId();
const spanContext = {
traceId,
spanId,
isRemote: true,
traceFlags: api.TraceFlags.NONE
};
const ctxWithTrace = api.trace.setSpanContext(api.context.active(), spanContext);
return api.context.with(ctxWithTrace, () => {
core.getCurrentScope().setPropagationContext({
traceId,
sampleRand: core._INTERNAL_safeMathRandom()
});
return callback();
});
}
function getTraceContextForScope(client, scope) {
const ctx = getContextFromScope(scope);
const span = ctx && api.trace.getSpan(ctx);
const traceContext = span ? core.spanToTraceContext(span) : core.getTraceContextFromScope(scope);
const dynamicSamplingContext = span ? core.getDynamicSamplingContextFromSpan(span) : core.getDynamicSamplingContextFromScope(client, scope);
return [dynamicSamplingContext, traceContext];
}
function getActiveSpanWrapper(parentSpan) {
return parentSpan !== void 0 ? (callback) => {
return withActiveSpan(parentSpan, callback);
} : (callback) => callback();
}
function suppressTracing(callback) {
const ctx = core$1.suppressTracing(api.context.active());
return api.context.with(ctx, callback);
}
function setupEventContextTrace(client) {
client.on("preprocessEvent", (event) => {
const span = getActiveSpan();
if (!span || event.type === "transaction") {
return;
}
event.contexts = {
trace: core.spanToTraceContext(span),
...event.contexts
};
const rootSpan = core.getRootSpan(span);
event.sdkProcessingMetadata = {
dynamicSamplingContext: core.getDynamicSamplingContextFromSpan(rootSpan),
...event.sdkProcessingMetadata
};
return event;
});
}
function getTraceData({
span,
scope,
client,
propagateTraceparent
} = {}) {
let ctx = (scope && getContextFromScope(scope)) ?? api.context.active();
if (span) {
const { scope: scope2 } = core.getCapturedScopesOnSpan(span);
ctx = scope2 && getContextFromScope(scope2) || api.trace.setSpan(api.context.active(), span);
}
const { traceId, spanId, sampled, dynamicSamplingContext } = getInjectionData(ctx, { scope, client });
const traceData = {
"sentry-trace": core.generateSentryTraceHeader(traceId, spanId, sampled),
baggage: core.dynamicSamplingContextToSentryBaggageHeader(dynamicSamplingContext)
};
if (propagateTraceparent) {
traceData.traceparent = core.generateTraceparentHeader(traceId, spanId, sampled);
}
return traceData;
}
function setOpenTelemetryContextAsyncContextStrategy() {
function getScopes() {
const ctx = api.context.active();
const scopes = getScopesFromContext(ctx);
if (scopes) {
return scopes;
}
return {
scope: core.getDefaultCurrentScope(),
isolationScope: core.getDefaultIsolationScope()
};
}
function withScope(callback) {
const ctx = api.context.active();
return api.context.with(ctx, () => {
return callback(getCurrentScope());
});
}
function withSetScope(scope, callback) {
const ctx = getContextFromScope(scope) || api.context.active();
return api.context.with(ctx.setValue(SENTRY_FORK_SET_SCOPE_CONTEXT_KEY, scope), () => {
return callback(scope);
});
}
function withIsolationScope(callback) {
const ctx = api.context.active();
return api.context.with(ctx.setValue(SENTRY_FORK_ISOLATION_SCOPE_CONTEXT_KEY, true), () => {
return callback(getIsolationScope());
});
}
function withSetIsolationScope(isolationScope, callback) {
const ctx = api.context.active();
return api.context.with(ctx.setValue(SENTRY_FORK_SET_ISOLATION_SCOPE_CONTEXT_KEY, isolationScope), () => {
return callback(getIsolationScope());
});
}
function getCurrentScope() {
return getScopes().scope;
}
function getIsolationScope() {
return getScopes().isolationScope;
}
core.setAsyncContextStrategy({
withScope,
withSetScope,
withSetIsolationScope,
withIsolationScope,
getCurrentScope,
getIsolationScope,
startSpan,
startSpanManual,
startInactiveSpan,
getActiveSpan,
suppressTracing,
getTraceData,
continueTrace,
startNewTrace,
// The types here don't fully align, because our own `Span` type is narrower
// than the OTEL one - but this is OK for here, as we now we'll only have OTEL spans passed around
withActiveSpan,
getTracingChannelBinding: () => {
try {
const contextManager = api.context._getContextManager();
const lookup = contextManager.getAsyncLocalStorageLookup();
return {
asyncLocalStorage: lookup.asyncLocalStorage,
getStoreWithActiveSpan: (span) => api.trace.setSpan(api.context.active(), span)
};
} catch {
return void 0;
}
}
});
}
function buildContextWithSentryScopes(context, activeContext) {
const span = api.trace.getSpan(context);
let effectiveContext;
if (span?.spanContext().traceState?.get(SENTRY_TRACE_STATE_CHILD_IGNORED) === "1") {
const contextWithoutSpan = api.trace.deleteSpan(context);
const parentSpan = api.trace.getSpan(activeContext);
effectiveContext = parentSpan ? api.trace.setSpan(contextWithoutSpan, parentSpan) : contextWithoutSpan;
} else {
effectiveContext = context;
}
const currentScopes = getScopesFromContext(effectiveContext);
const currentScope = currentScopes?.scope || core.getCurrentScope();
const currentIsolationScope = currentScopes?.isolationScope || core.getIsolationScope();
const shouldForkIsolationScope = effectiveContext.getValue(SENTRY_FORK_ISOLATION_SCOPE_CONTEXT_KEY) === true;
const scope = effectiveContext.getValue(SENTRY_FORK_SET_SCOPE_CONTEXT_KEY);
const isolationScope = effectiveContext.getValue(SENTRY_FORK_SET_ISOLATION_SCOPE_CONTEXT_KEY);
const newCurrentScope = scope || currentScope.clone();
const newIsolationScope = isolationScope || (shouldForkIsolationScope ? currentIsolationScope.clone() : currentIsolationScope);
const scopes = { scope: newCurrentScope, isolationScope: newIsolationScope };
const ctx1 = setScopesOnContext(effectiveContext, scopes);
const ctx2 = ctx1.deleteValue(SENTRY_FORK_ISOLATION_SCOPE_CONTEXT_KEY).deleteValue(SENTRY_FORK_SET_SCOPE_CONTEXT_KEY).deleteValue(SENTRY_FORK_SET_ISOLATION_SCOPE_CONTEXT_KEY);
setContextOnScope(newCurrentScope, ctx2);
return ctx2;
}
function wrapContextManagerClass(ContextManagerClass) {
class SentryContextManager extends ContextManagerClass {
constructor(...args) {
super(...args);
setIsSetup("SentryContextManager");
}
/**
* Overwrite with() of the original AsyncLocalStorageContextManager
* to ensure we also create new scopes per context.
*/
with(context, fn, thisArg, ...args) {
const ctx2 = buildContextWithSentryScopes(context, this.active());
return super.with(ctx2, fn, thisArg, ...args);
}
/**
* Gets underlying AsyncLocalStorage and symbol to allow lookup of scope.
*/
getAsyncLocalStorageLookup() {
return {
// @ts-expect-error This is on the base class, but not part of the interface
asyncLocalStorage: this._asyncLocalStorage,
contextSymbol: SENTRY_SCOPES_CONTEXT_KEY
};
}
}
return SentryContextManager;
}
function groupSpansWithParents(spans) {
const nodeMap = /* @__PURE__ */ new Map();
for (const span of spans) {
createOrUpdateSpanNodeAndRefs(nodeMap, span);
}
return Array.from(nodeMap, function([_id, spanNode]) {
return spanNode;
});
}
function getLocalParentId(span) {
const parentIsRemote = span.attributes[SEMANTIC_ATTRIBUTE_SENTRY_PARENT_IS_REMOTE] === true;
return !parentIsRemote ? getParentSpanId(span) : void 0;
}
function createOrUpdateSpanNodeAndRefs(nodeMap, span) {
const id = span.spanContext().spanId;
const parentId = getLocalParentId(span);
if (!parentId) {
createOrUpdateNode(nodeMap, { id, span, children: [] });
return;
}
const parentNode = createOrGetParentNode(nodeMap, parentId);
const node = createOrUpdateNode(nodeMap, { id, span, parentNode, children: [] });
parentNode.children.push(node);
}
function createOrGetParentNode(nodeMap, id) {
const existing = nodeMap.get(id);
if (existing) {
return existing;
}
return createOrUpdateNode(nodeMap, { id, children: [] });
}
function createOrUpdateNode(nodeMap, spanNode) {
const existing = nodeMap.get(spanNode.id);
if (existing?.span) {
return existing;
}
if (existing && !existing.span) {
existing.span = spanNode.span;
existing.parentNode = spanNode.parentNode;
return existing;
}
nodeMap.set(spanNode.id, spanNode);
return spanNode;
}
const canonicalGrpcErrorCodesMap = {
"1": "cancelled",
"2": "unknown_error",
"3": "invalid_argument",
"4": "deadline_exceeded",
"5": "not_found",
"6": "already_exists",
"7": "permission_denied",
"8": "resource_exhausted",
"9": "failed_precondition",
"10": "aborted",
"11": "out_of_range",
"12": "unimplemented",
"13": "internal_error",
"14": "unavailable",
"15": "data_loss",
"16": "unauthenticated"
};
const isStatusErrorMessageValid = (message) => {
return Object.values(canonicalGrpcErrorCodesMap).includes(message);
};
function mapStatus(span) {
const attributes = spanHasAttributes(span) ? span.attributes : {};
const status = spanHasStatus(span) ? span.status : void 0;
if (status) {
if (status.code === api.SpanStatusCode.OK) {
return { code: core.SPAN_STATUS_OK };
} else if (status.code === api.SpanStatusCode.ERROR) {
if (typeof status.message === "undefined") {
const inferredStatus2 = inferStatusFromAttributes(attributes);
if (inferredStatus2) {
return inferredStatus2;
}
}
if (status.message && isStatusErrorMessageValid(status.message)) {
return { code: core.SPAN_STATUS_ERROR, message: status.message };
} else {
return { code: core.SPAN_STATUS_ERROR, message: "internal_error" };
}
}
}
const inferredStatus = inferStatusFromAttributes(attributes);
if (inferredStatus) {
return inferredStatus;
}
if (status?.code === api.SpanStatusCode.UNSET) {
return { code: core.SPAN_STATUS_OK };
} else {
return { code: core.SPAN_STATUS_ERROR, message: "unknown_error" };
}
}
function inferStatusFromAttributes(attributes$1) {
const httpCodeAttribute = attributes$1[attributes.HTTP_RESPONSE_STATUS_CODE] || attributes$1[attributes.HTTP_STATUS_CODE];
const grpcCodeAttribute = attributes$1[attributes.RPC_GRPC_STATUS_CODE];
const numberHttpCode = typeof httpCodeAttribute === "number" ? httpCodeAttribute : typeof httpCodeAttribute === "string" ? parseInt(httpCodeAttribute) : void 0;
if (typeof numberHttpCode === "number") {
return core.getSpanStatusFromHttpCode(numberHttpCode);
}
if (typeof grpcCodeAttribute === "string") {
return { code: core.SPAN_STATUS_ERROR, message: canonicalGrpcErrorCodesMap[grpcCodeAttribute] || "unknown_error" };
}
return void 0;
}
const MAX_SPAN_COUNT = 1e3;
const DEFAULT_TIMEOUT = 300;
const SENT_SPANS_MAX_SIZE = 1e4;
class SentrySpanExporter {
constructor(options) {
this._finishedSpanBucketSize = options?.timeout || DEFAULT_TIMEOUT;
this._finishedSpanBuckets = new Array(this._finishedSpanBucketSize).fill(void 0);
this._lastCleanupTimestampInS = Math.floor(core._INTERNAL_safeDateNow() / 1e3);
this._spansToBucketEntry = /* @__PURE__ */ new WeakMap();
this._sentSpans = new core.LRUMap(SENT_SPANS_MAX_SIZE);
this._debouncedFlush = core.debounce(this.flush.bind(this), 1, { maxWait: 100 });
}
/**
* Export a single span.
* This is called by the span processor whenever a span is ended.
*/
export(span) {
const currentTimestampInS = Math.floor(core._INTERNAL_safeDateNow() / 1e3);
if (this._lastCleanupTimestampInS !== currentTimestampInS) {
let droppedSpanCount = 0;
this._finishedSpanBuckets.forEach((bucket, i) => {
if (bucket && bucket.timestampInS <= currentTimestampInS - this._finishedSpanBucketSize) {
droppedSpanCount += bucket.spans.size;
this._finishedSpanBuckets[i] = void 0;
}
});
if (droppedSpanCount > 0) {
DEBUG_BUILD && core.debug.log(
`SpanExporter dropped ${droppedSpanCount} spans because they were pending for more than ${this._finishedSpanBucketSize} seconds.`
);
}
this._lastCleanupTimestampInS = currentTimestampInS;
}
const currentBucketIndex = currentTimestampInS % this._finishedSpanBucketSize;
const currentBucket = this._finishedSpanBuckets[currentBucketIndex] || {
timestampInS: currentTimestampInS,
spans: /* @__PURE__ */ new Set()
};
this._finishedSpanBuckets[currentBucketIndex] = currentBucket;
currentBucket.spans.add(span);
this._spansToBucketEntry.set(span, currentBucket);
const localParentId = getLocalParentId(span);
if (!localParentId || this._sentSpans.get(localParentId)) {
this._debouncedFlush();
}
}
/**
* Try to flush any pending spans immediately.
* This is called internally by the exporter (via _debouncedFlush),
* but can also be triggered externally if we force-flush.
*/
flush() {
const finishedSpans = this._finishedSpanBuckets.flatMap((bucket) => bucket ? Array.from(bucket.spans) : []);
const sentSpans = this._maybeSend(finishedSpans);
const sentSpanCount = sentSpans.size;
const remainingOpenSpanCount = finishedSpans.length - sentSpanCount;
DEBUG_BUILD && core.debug.log(
`SpanExporter exported ${sentSpanCount} spans, ${remainingOpenSpanCount} spans are waiting for their parent spans to finish`
);
for (const span of sentSpans) {
this._sentSpans.set(span.spanContext().spanId, 1);
const bucketEntry = this._spansToBucketEntry.get(span);
if (bucketEntry) {
bucketEntry.spans.delete(span);
}
}
this._debouncedFlush.cancel();
}
/**
* Clear the exporter.
* This is called when the span processor is shut down.
*/
clear() {
this._finishedSpanBuckets = this._finishedSpanBuckets.fill(void 0);
this._sentSpans.clear();
this._debouncedFlush.cancel();
}
/**
* Send the given spans, but only if they are part of a finished transaction.
*
* Returns the sent spans.
* Spans remain unsent when their parent span is not yet finished.
* This will happen regularly, as child spans are generally finished before their parents.
* But it _could_ also happen because, for whatever reason, a parent span was lost.
* In this case, we'll eventually need to clean this up.
*/
_maybeSend(spans) {
const grouped = groupSpansWithParents(spans);
const sentSpans = /* @__PURE__ */ new Set();
const rootNodes = this._getCompletedRootNodes(grouped);
for (const root of rootNodes) {
const span = root.span;
sentSpans.add(span);
const transactionEvent = createTransactionForOtelSpan(span);
if (root.parentNode && this._sentSpans.get(root.parentNode.id)) {
const traceData = transactionEvent.contexts?.trace?.data;
if (traceData) {
traceData["sentry.parent_span_already_sent"] = true;
}
}
const spans2 = transactionEvent.spans || [];
let hasGenAiSpans = false;
for (const child of root.children) {
if (createAndFinishSpanForOtelSpan(child, spans2, sentSpans)) {
hasGenAiSpans = true;
}
}
transactionEvent.spans = spans2.length > MAX_SPAN_COUNT ? spans2.sort((a, b) => a.start_timestamp - b.start_timestamp).slice(0, MAX_SPAN_COUNT) : spans2;
if (hasGenAiSpans) {
transactionEvent.sdkProcessingMetadata = {
...transactionEvent.sdkProcessingMetadata,
hasGenAiSpans: true
};
}
const measurements = core.timedEventsToMeasurements(span.events);
if (measurements) {
transactionEvent.measurements = measurements;
}
core.captureEvent(transactionEvent);
}
return sentSpans;
}
/** Check if a node is a completed root node or a node whose parent has already been sent */
_nodeIsCompletedRootNodeOrHasSentParent(node) {
return !!node.span && (!node.parentNode || !!this._sentSpans.get(node.parentNode.id));
}
/** Get all completed root nodes from a list of nodes */
_getCompletedRootNodes(nodes) {
return nodes.filter((node) => this._nodeIsCompletedRootNodeOrHasSentParent(node));
}
}
function parseSpan(span) {
const attributes = span.attributes;
const origin = attributes[core.SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN];
const op = attributes[core.SEMANTIC_ATTRIBUTE_SENTRY_OP];
const source = attributes[core.SEMANTIC_ATTRIBUTE_SENTRY_SOURCE];
return { origin, op, source };
}
function createTransactionForOtelSpan(span) {
const { op, description, data, origin = "manual", source } = getSpanData(span);
const capturedSpanScopes = core.getCapturedScopesOnSpan(span);
const sampleRate = span.attributes[core.SEMANTIC_ATTRIBUTE_SENTRY_SAMPLE_RATE];
const attributes$1 = {
[core.SEMANTIC_ATTRIBUTE_SENTRY_SOURCE]: source,
[core.SEMANTIC_ATTRIBUTE_SENTRY_SAMPLE_RATE]: sampleRate,
[core.SEMANTIC_ATTRIBUTE_SENTRY_OP]: op,
[core.SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: origin,
...data,
...removeSentryAttributes(span.attributes)
};
const { links } = span;
const { traceId: trace_id, spanId: span_id } = span.spanContext();
const parent_span_id = getParentSpanId(span);
const status = mapStatus(span);
const traceContext = {
parent_span_id,
span_id,
trace_id,
data: attributes$1,
origin,
op,
status: core.getStatusMessage(status),
// As per protocol, span status is allowed to be undefined
links: core.convertSpanLinksForEnvelope(links)
};
const statusCode = attributes$1[attributes.HTTP_RESPONSE_STATUS_CODE];
const responseContext = typeof statusCode === "number" ? { response: { status_code: statusCode } } : void 0;
const transactionEvent = {
contexts: {
trace: traceContext,
otel: {
resource: span.resource.attributes
},
...responseContext
},
spans: [],
start_timestamp: core.spanTimeInputToSeconds(span.startTime),
timestamp: core.spanTimeInputToSeconds(span.endTime),
transaction: description,
type: "transaction",
sdkProcessingMetadata: {
capturedSpanScope: capturedSpanScopes.scope,
capturedSpanIsolationScope: capturedSpanScopes.isolationScope,
sampleRate,
dynamicSamplingContext: core.getDynamicSamplingContextFromSpan(span)
},
...source && {
transaction_info: {
source
}
}
};
return transactionEvent;
}
function createAndFinishSpanForOtelSpan(node, spans, sentSpans) {
const span = node.span;
if (span) {
sentSpans.add(span);
}
const shouldDrop = !span;
if (shouldDrop) {
let hasGenAiSpans2 = false;
node.children.forEach((child) => {
if (createAndFinishSpanForOtelSpan(child, spans, sentSpans)) {
hasGenAiSpans2 = true;
}
});
return hasGenAiSpans2;
}
const span_id = span.spanContext().spanId;
const trace_id = span.spanContext().traceId;
const parentSpanId = getParentSpanId(span);
const { attributes, startTime, endTime, links } = span;
const { op, description, data, origin = "manual" } = getSpanData(span);
const allData = {
[core.SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: origin,
[core.SEMANTIC_ATTRIBUTE_SENTRY_OP]: op,
...removeSentryAttributes(attributes),
...data
};
const status = mapStatus(span);
const spanJSON = {
span_id,
trace_id,
data: allData,
description,
parent_span_id: parentSpanId,
start_timestamp: core.spanTimeInputToSeconds(startTime),
// This is [0,0] by default in OTEL, in which case we want to interpret this as no end time
timestamp: core.spanTimeInputToSeconds(endTime) || void 0,
status: core.getStatusMessage(status),
// As per protocol, span status is allowed to be undefined
op,
origin,
measurements: core.timedEventsToMeasurements(span.events),
links: core.convertSpanLinksForEnvelope(links)
};
spans.push(spanJSON);
let hasGenAiSpans = !!op?.startsWith("gen_ai.");
node.children.forEach((child) => {
if (createAndFinishSpanForOtelSpan(child, spans, sentSpans)) {
hasGenAiSpans = true;
}
});
return hasGenAiSpans;
}
function getSpanData(span) {
const { op: definedOp, source: definedSource, origin } = parseSpan(span);
const { op: inferredOp, description, source: inferredSource, data: inferredData } = parseSpanDescription(span);
const op = definedOp || inferredOp;
const source = definedSource || inferredSource;
const data = { ...inferredData, ...getData(span) };
return {
op,
description,
source,
origin,
data
};
}
function removeSentryAttributes(data) {
const cleanedData = { ...data };
delete cleanedData[core.SEMANTIC_ATTRIBUTE_SENTRY_SAMPLE_RATE];
delete cleanedData[SEMANTIC_ATTRIBUTE_SENTRY_PARENT_IS_REMOTE];
delete cleanedData[core.SEMANTIC_ATTRIBUTE_SENTRY_CUSTOM_SPAN_NAME];
return cleanedData;
}
function getData(span) {
const attributes$1 = span.attributes;
const data = {};
if (span.kind !== api.SpanKind.INTERNAL) {
data["otel.kind"] = api.SpanKind[span.kind];
}
const maybeHttpStatusCodeAttribute = attributes$1[attributes.HTTP_STATUS_CODE];
if (maybeHttpStatusCodeAttribute) {
data[attributes.HTTP_RESPONSE_STATUS_CODE] = maybeHttpStatusCodeAttribute;
}
const requestData = getRequestSpanData(span);
if (requestData.url) {
data.url = requestData.url;
}
if (requestData["http.query"]) {
data["http.query"] = requestData["http.query"].slice(1);
}
if (requestData["http.fragment"]) {
data["http.fragment"] = requestData["http.fragment"].slice(1);
}
return data;
}
class SentrySpanProcessor {
constructor(options) {
this._unsubscribePreprocessSpan = void 0;
setIsSetup("SentrySpanProcessor");
this._exporter = new SentrySpanExporter(options);
this._client = options?.client ?? core.getClient();
if (this._client && core.hasSpanStreamingEnabled(this._client)) {
this._unsubscribePreprocessSpan = this._client.on("preprocessSpan", backfillStreamedSpanDataFromOtel);
}
}
/**
* @inheritDoc
*/
async forceFlush() {
this._exporter.flush();
}
/**
* @inheritDoc
*/
async shutdown() {
this._unsubscribePreprocessSpan?.();
this._exporter.clear();
}
/**
* @inheritDoc
*/
onStart(span, parentContext) {
const parentSpan = api.trace.getSpan(parentContext);
let scopes = getScopesFromContext(parentContext);
if (parentSpan && !parentSpan.spanContext().isRemote) {
core.addChildSpanToSpan(parentSpan, span);
}
if (parentSpan?.spanContext().isRemote) {
span.setAttribute(SEMANTIC_ATTRIBUTE_SENTRY_PARENT_IS_REMOTE, true);
}
if (parentContext === api.ROOT_CONTEXT) {
scopes = {
scope: core.getDefaultCurrentScope(),
isolationScope: core.getDefaultIsolationScope()
};
}
if (scopes) {
core.setCapturedScopesOnSpan(span, scopes.scope, scopes.isolationScope);
}
core.logSpanStart(span);
this._client?.emit("spanStart", span);
}
/** @inheritDoc */
onEnd(span) {
core.logSpanEnd(span);
this._client?.emit("spanEnd", span);
if (this._client && core.hasSpanStreamingEnabled(this._client)) {
this._client.emit("afterSpanEnd", span);
} else {
this._exporter.export(span);
}
}
}
function backfillStreamedSpanDataFromOtel(spanJSON, hint) {
const attributes = spanJSON.attributes;
if (!attributes) {
return;
}
const kind = hint?.spanKind ?? api.SpanKind.INTERNAL;
const { op, description, source, data } = inferSpanData(spanJSON.name, attributes, kind);
spanJSON.name = description;
core.safeSetSpanJSONAttributes(spanJSON, {
[core.SEMANTIC_ATTRIBUTE_SENTRY_OP]: op,
[core.SEMANTIC_ATTRIBUTE_SENTRY_SOURCE]: source,
...data
});
if (kind !== api.SpanKind.INTERNAL) {
core.safeSetSpanJSONAttributes(spanJSON, {
"otel.kind": api.SpanKind[kind]
});
}
}
class SentrySampler {
constructor(client) {
this._client = client;
this._isSpanStreaming = core.hasSpanStreamingEnabled(client);
setIsSetup("SentrySampler");
}
/** @inheritDoc */
shouldSample(context, traceId, spanName, spanKind, spanAttributes, _links) {
const options = this._client.getOptions();
const { ignoreSpans } = options;
const parentSpan = getValidSpan(context);
const parentContext = parentSpan?.spanContext();
if (!core.hasSpansEnabled(options)) {
return wrapSamplingDecision({ decision: void 0, context, spanAttributes });
}
const maybeSpanHttpMethod = spanAttributes[attributes.HTTP_METHOD] || spanAttributes[attributes.HTTP_REQUEST_METHOD];
if (spanKind === api.SpanKind.CLIENT && maybeSpanHttpMethod && (!parentSpan || parentContext?.isRemote)) {
if (!this._isSpanStreaming) {
this._client.recordDroppedEvent("no_parent_span", "span");
return wrapSamplingDecision({ decision: void 0, context, spanAttributes });
}
}
const parentSampled = parentSpan ? getParentSampled(parentSpan, traceId, spanName) : void 0;
const isRootSpan = !parentSpan || parentContext?.isRemote;
if (!isRootSpan) {
if (this._isSpanStreaming) {
if (parentSampled) {
if (ignoreSpans?.length) {
const { description: inferredChildName, op: childOp } = inferSpanData(spanName, spanAttributes, spanKind);
if (core.shouldIgnoreSpan(
{
description: inferredChildName,
op: spanAttributes[core.SEMANTIC_ATTRIBUTE_SENTRY_OP] ?? childOp,
attributes: spanAttributes
},
ignoreSpans
)) {
this._client.recordDroppedEvent("ignored", "span");
return wrapSamplingDecision({
decision: sdkTraceBase.SamplingDecision.NOT_RECORD,
context,
spanAttributes,
ignoredChildSpan: true
});
}
}
}
if (!parentSampled) {
const parentSegmentIgnored = parentContext?.traceState?.get(SENTRY_TRACE_STATE_SEGMENT_IGNORED) === "1";
this._client.recordDroppedEvent(parentSegmentIgnored ? "ignored" : "sample_rate", "span");
}
}
return wrapSamplingDecision({
decision: parentSampled ? sdkTraceBase.SamplingDecision.RECORD_AND_SAMPLED : sdkTraceBase.SamplingDecision.NOT_RECORD,
context,
spanAttributes
});
}
const {
description: inferredSpanName,
data: inferredAttributes,
op
} = inferSpanData(spanName, spanAttributes, spanKind);
const mergedAttributes = {
...inferredAttributes,
...spanAttributes
};
if (op) {
mergedAttributes[core.SEMANTIC_ATTRIBUTE_SENTRY_OP] = op;
}
if (this._isSpanStreaming && ignoreSpans?.length && core.shouldIgnoreSpan(
{
description: inferredSpanName,
op: mergedAttributes[core.SEMANTIC_ATTRIBUTE_SENTRY_OP] ?? op,
attributes: mergedAttributes
},
ignoreSpans
)) {
this._client.recordDroppedEvent("ignored", "span");
return wrapSamplingDecision({
decision: sdkTraceBase.SamplingDecision.NOT_RECORD,
context,
spanAttributes,
ignoredSegmentSpan: true
});
}
const mutableSamplingDecision = { decision: true };
this._client.emit(
"beforeSampling",
{
spanAttributes: mergedAttributes,
spanName: inferredSpanName,
parentSampled,
parentContext
},
mutableSamplingDecision
);
if (!mutableSamplingDecision.decision) {
return wrapSamplingDecision({ decision: void 0, context, spanAttributes });
}
const { isolationScope } = getScopesFromContext(context) ?? {};
const dscString = parentContext?.traceState ? parentContext.traceState.get(SENTRY_TRACE_STATE_DSC) : void 0;
const dsc = dscString ? core.baggageHeaderToDynamicSamplingContext(dscString) : void 0;
const sampleRand = core.parseSampleRate(dsc?.sample_rand) ?? core._INTERNAL_safeMathRandom();
const [sampled, sampleRate, localSampleRateWasApplied] = core.sampleSpan(
options,
{
name: inferredSpanName,
attributes: mergedAttributes,
normalizedRequest: isolationScope?.getScopeData().sdkProcessingMetadata.normalizedRequest,
parentSampled,
parentSampleRate: core.parseSampleRate(dsc?.sample_rate)
},
sampleRand
);
const method = `${maybeSpanHttpMethod}`.toUpperCase();
if (method === "OPTIONS" || method === "HEAD") {
DEBUG_BUILD && core.debug.log(`[Tracing] Not sampling span because HTTP method is '${method}' for ${spanName}`);
return wrapSamplingDecision({
decision: sdkTraceBase.SamplingDecision.NOT_RECORD,
context,
spanAttributes,
sampleRand,
downstreamTraceSampleRate: 0
// we don't want to sample anything in the downstream trace either
});
}
if (!sampled && // We check for `parentSampled === undefined` because we only want to record client reports for spans that are trace roots (ie. when there was incoming trace)
parentSampled === void 0) {
DEBUG_BUILD && core.debug.log("[Tracing] Discarding root span because its trace was not chosen to be sampled.");
this._client.recordDroppedEvent("sample_rate", this._isSpanStreaming ? "span" : "transaction");
}
return {
...wrapSamplingDecision({
decision: sampled ? sdkTraceBase.SamplingDecision.RECORD_AND_SAMPLED : sdkTraceBase.SamplingDecision.NOT_RECORD,
context,
spanAttributes,
sampleRand,
downstreamTraceSampleRate: localSampleRateWasApplied ? sampleRate : void 0
}),
attributes: {
// We set the sample rate on the span when a local sample rate was applied to better understand how traces were sampled in Sentry
[core.SEMANTIC_ATTRIBUTE_SENTRY_SAMPLE_RATE]: localSampleRateWasApplied ? sampleRate : void 0
}
};
}
/** Returns the sampler name or short description with the configuration. */
toString() {
return "SentrySampler";
}
}
function getParentSampled(parentSpan, traceId, spanName) {
const parentContext = parentSpan.spanContext();
if (api.isSpanContextValid(parentContext) && parentContext.traceId === traceId) {
if (parentContext.isRemote) {
const parentSampled2 = getSamplingDecision(parentSpan.spanContext());
DEBUG_BUILD && core.debug.log(`[Tracing] Inheriting remote parent's sampled decision for ${spanName}: ${parentSampled2}`);
return parentSampled2;
}
const parentSampled = getSamplingDecision(parentContext);
DEBUG_BUILD && core.debug.log(`[Tracing] Inheriting parent's sampled decision for ${spanName}: ${parentSampled}`);
return parentSampled;
}
return void 0;
}
function wrapSamplingDecision({
decision,
context,
spanAttributes,
sampleRand,
downstreamTraceSampleRate,
ignoredChildSpan,
ignoredSegmentSpan
}) {
let traceState = getBaseTraceState(context, spanAttributes);
if (downstreamTraceSampleRate !== void 0) {
traceState = traceState.set(SENTRY_TRACE_STATE_SAMPLE_RATE, `${downstreamTraceSampleRate}`);
}
if (sampleRand !== void 0) {
traceState = traceState.set(SENTRY_TRACE_STATE_SAMPLE_RAND, `${sampleRand}`);
}
if (ignoredChildSpan) {
traceState = traceState.set(SENTRY_TRACE_STATE_CHILD_IGNORED, "1");
}
if (ignoredSegmentSpan) {
traceState = traceState.set(SENTRY_TRACE_STATE_SEGMENT_IGNORED, "1");
}
if (decision == void 0) {
return { decision: sdkTraceBase.SamplingDecision.NOT_RECORD, traceState };
}
if (decision === sdkTraceBase.SamplingDecision.NOT_RECORD) {
return { decision, traceState: traceState.set(SENTRY_TRACE_STATE_SAMPLED_NOT_RECORDING, "1") };
}
return { decision, traceState };
}
function getBaseTraceState(context, spanAttributes) {
const parentSpan = api.trace.getSpan(context);
const parentContext = parentSpan?.spanContext();
let traceState = parentContext?.traceState || new TraceState();
const url = spanAttributes[attributes.HTTP_URL] || spanAttributes[attributes.URL_FULL];
if (url && typeof url === "string") {
traceState = traceState.set(SENTRY_TRACE_STATE_URL, url);
}
return traceState;
}
function getValidSpan(context) {
const span = api.trace.getSpan(context);
return span && api.isSpanContextValid(span.spanContext()) ? span : void 0;
}
const ATTR_TELEMETRY_SDK_LANGUAGE = "telemetry.sdk.language";
const ATTR_TELEMETRY_SDK_NAME = "telemetry.sdk.name";
const ATTR_TELEMETRY_SDK_VERSION = "telemetry.sdk.version";
const SEMRESATTRS_SERVICE_NAMESPACE = "service.namespace";
class SentryResource {
constructor(attributes) {
this._attributes = attributes;
}
get attributes() {
return this._attributes;
}
merge(other) {
if (!other) {
return this;
}
return new SentryResource({ ...this._attributes, ...other.attributes });
}
getRawAttributes() {
return Object.entries(this._attributes);
}
}
function parseOtelResourceAttributes(raw) {
if (!raw) {
return {};
}
const result = {};
for (const pair of raw.split(",")) {
const eq = pair.indexOf("=");
if (eq === -1) {
continue;
}
const key = pair.substring(0, eq).trim();
const value = pair.substring(eq + 1).trim();
if (key) {
try {
result[key] = decodeURIComponent(value);
} catch {
result[key] = value;
}
}
}
return result;
}
function getSentryResource(serviceNameFallback) {
const env = typeof process !== "undefined" ? process.env : {};
const otelServiceName = env.OTEL_SERVICE_NAME;
const otelResourceAttrs = parseOtelResourceAttributes(env.OTEL_RESOURCE_ATTRIBUTES);
return new SentryResource({
// Lowest priority: Sentry defaults
// eslint-disable-next-line typescript/no-deprecated
[SEMRESATTRS_SERVICE_NAMESPACE]: "sentry",
[attributes.SERVICE_NAME]: serviceNameFallback,
// OTEL_RESOURCE_ATTRIBUTES overrides defaults (including service.name and service.namespace)
...otelResourceAttrs,
// OTEL_SERVICE_NAME explicitly overrides service.name
...otelServiceName ? { [attributes.SERVICE_NAME]: otelServiceName } : {},
// Highest priority: Sentry SDK telemetry attrs (cannot be overridden by env vars)
[attributes.SERVICE_VERSION]: core.SDK_VERSION,
[ATTR_TELEMETRY_SDK_LANGUAGE]: core$1.SDK_INFO[ATTR_TELEMETRY_SDK_LANGUAGE],
[ATTR_TELEMETRY_SDK_NAME]: core$1.SDK_INFO[ATTR_TELEMETRY_SDK_NAME],
[ATTR_TELEMETRY_SDK_VERSION]: core$1.SDK_INFO[ATTR_TELEMETRY_SDK_VERSION]
});
}
exports.SEMANTIC_ATTRIBUTE_SENTRY_GRAPHQL_OPERATION = SEMANTIC_ATTRIBUTE_SENTRY_GRAPHQL_OPERATION;
exports.SENTRY_SCOPES_CONTEXT_KEY = SENTRY_SCOPES_CONTEXT_KEY;
exports.SentryPropagator = SentryPropagator;
exports.SentrySampler = SentrySampler;
exports.SentrySpanProcessor = SentrySpanProcessor;
exports.buildContextWithSentryScopes = buildContextWithSentryScopes;
exports.continueTrace = continueTrace;
exports.enhanceDscWithOpenTelemetryRootSpanName = enhanceDscWithOpenTelemetryRootSpanName;
exports.getActiveSpan = getActiveSpan;
exports.getRequestSpanData = getRequestSpanData;
exports.getScopesFromContext = getScopesFromContext;
exports.getSentryResource = getSentryResource;
exports.getSpanKind = getSpanKind;
exports.getTraceContextForScope = getTraceContextForScope;
exports.isSentryRequestSpan = isSentryRequestSpan;
exports.openTelemetrySetupCheck = openTelemetrySetupCheck;
exports.setIsSetup = setIsSetup;
exports.setOpenTelemetryContextAsyncContextStrategy = setOpenTelemetryContextAsyncContextStrategy;
exports.setupEventContextTrace = setupEventContextTrace;
exports.spanHasAttributes = spanHasAttributes;
exports.spanHasEvents = spanHasEvents;
exports.spanHasKind = spanHasKind;
exports.spanHasName = spanHasName;
exports.spanHasParentId = spanHasParentId;
exports.spanHasStatus = spanHasStatus;
exports.startInactiveSpan = startInactiveSpan;
exports.startSpan = startSpan;
exports.startSpanManual = startSpanManual;
exports.suppressTracing = suppressTracing;
exports.withActiveSpan = withActiveSpan;
exports.wrapClientClass = wrapClientClass;
exports.wrapContextManagerClass = wrapContextManagerClass;
exports.wrapSamplingDecision = wrapSamplingDecision;
//# sourceMappingURL=resource-PpJQa_6P.js.map

Sorry, the diff of this file is too big to display

import * as api from '@opentelemetry/api';
import { trace, SpanKind, createContextKey, TraceFlags, propagation, INVALID_TRACEID, context, SpanStatusCode, ROOT_CONTEXT, isSpanContextValid } from '@opentelemetry/api';
import { parseUrl, getSanitizedUrlString, SDK_VERSION, derefWeakRef, addNonEnumerableProperty, makeWeakRef, isSentryRequestUrl, getClient, baggageHeaderToDynamicSamplingContext, SEMANTIC_ATTRIBUTE_SENTRY_OP, SEMANTIC_ATTRIBUTE_SENTRY_SOURCE, SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN, SEMANTIC_ATTRIBUTE_SENTRY_CUSTOM_SPAN_NAME, stripUrlQueryAndFragment, spanToJSON, hasSpansEnabled, dynamicSamplingContextToSentryBaggageHeader, LRUMap, debug, shouldPropagateTraceForUrl, parseBaggageHeader, SENTRY_BAGGAGE_KEY_PREFIX, generateSentryTraceHeader, generateTraceparentHeader, getDynamicSamplingContextFromSpan, getCurrentScope, getDynamicSamplingContextFromScope, getIsolationScope, propagationContextFromHeaders, shouldContinueTrace, spanToTraceContext, getTraceContextFromScope, generateTraceId, generateSpanId, _INTERNAL_safeMathRandom, getRootSpan, handleCallbackErrors, getCapturedScopesOnSpan, setAsyncContextStrategy, getDefaultIsolationScope, getDefaultCurrentScope, SPAN_STATUS_OK, SPAN_STATUS_ERROR, getSpanStatusFromHttpCode, _INTERNAL_safeDateNow, debounce, timedEventsToMeasurements, captureEvent, SEMANTIC_ATTRIBUTE_SENTRY_SAMPLE_RATE, convertSpanLinksForEnvelope, getStatusMessage, spanTimeInputToSeconds, hasSpanStreamingEnabled, addChildSpanToSpan, setCapturedScopesOnSpan, logSpanStart, logSpanEnd, safeSetSpanJSONAttributes, shouldIgnoreSpan, parseSampleRate, sampleSpan } from '@sentry/core';
import { URL_FULL, HTTP_URL, HTTP_REQUEST_METHOD, HTTP_METHOD, DB_SYSTEM_NAME, DB_SYSTEM, RPC_SERVICE, MESSAGING_SYSTEM, FAAS_TRIGGER, DB_STATEMENT, HTTP_TARGET, HTTP_ROUTE, HTTP_RESPONSE_STATUS_CODE, HTTP_STATUS_CODE, RPC_GRPC_STATUS_CODE, SERVICE_VERSION, SERVICE_NAME } from '@sentry/conventions/attributes';
import { W3CBaggagePropagator, isTracingSuppressed, suppressTracing as suppressTracing$1, SDK_INFO } from '@opentelemetry/core';
import { SamplingDecision } from '@opentelemetry/sdk-trace-base';
const SEMANTIC_ATTRIBUTE_SENTRY_PARENT_IS_REMOTE = "sentry.parentIsRemote";
const SEMANTIC_ATTRIBUTE_SENTRY_GRAPHQL_OPERATION = "sentry.graphql.operation";
function getParentSpanId(span) {
if ("parentSpanId" in span) {
return span.parentSpanId;
} else if ("parentSpanContext" in span) {
return span.parentSpanContext?.spanId;
}
return void 0;
}
function spanHasAttributes(span) {
const castSpan = span;
return !!castSpan.attributes && typeof castSpan.attributes === "object";
}
function spanHasKind(span) {
const castSpan = span;
return typeof castSpan.kind === "number";
}
function spanHasStatus(span) {
const castSpan = span;
return !!castSpan.status;
}
function spanHasName(span) {
const castSpan = span;
return !!castSpan.name;
}
function spanHasParentId(span) {
const castSpan = span;
return !!getParentSpanId(castSpan);
}
function spanHasEvents(span) {
const castSpan = span;
return Array.isArray(castSpan.events);
}
function getRequestSpanData(span) {
if (!spanHasAttributes(span)) {
return {};
}
const maybeUrlAttribute = span.attributes[URL_FULL] || span.attributes[HTTP_URL];
const data = {
url: maybeUrlAttribute,
// eslint-disable-next-line typescript/no-deprecated
"http.method": span.attributes[HTTP_REQUEST_METHOD] || span.attributes[HTTP_METHOD]
};
if (!data["http.method"] && data.url) {
data["http.method"] = "GET";
}
try {
if (typeof maybeUrlAttribute === "string") {
const url = parseUrl(maybeUrlAttribute);
data.url = getSanitizedUrlString(url);
if (url.search) {
data["http.query"] = url.search;
}
if (url.hash) {
data["http.fragment"] = url.hash;
}
}
} catch {
}
return data;
}
function wrapClientClass(ClientClass) {
class OpenTelemetryClient extends ClientClass {
constructor(...args) {
super(...args);
}
/** Get the OTEL tracer. */
get tracer() {
if (this._tracer) {
return this._tracer;
}
const name = "@sentry/opentelemetry";
const version = SDK_VERSION;
const tracer = trace.getTracer(name, version);
this._tracer = tracer;
return tracer;
}
/**
* @inheritDoc
*/
async flush(timeout) {
const provider = this.traceProvider;
await provider?.forceFlush();
return super.flush(timeout);
}
}
return OpenTelemetryClient;
}
function getSpanKind(span) {
if (spanHasKind(span)) {
return span.kind;
}
return SpanKind.INTERNAL;
}
const SENTRY_TRACE_HEADER = "sentry-trace";
const SENTRY_BAGGAGE_HEADER = "baggage";
const SENTRY_TRACE_STATE_DSC = "sentry.dsc";
const SENTRY_TRACE_STATE_SAMPLED_NOT_RECORDING = "sentry.sampled_not_recording";
const SENTRY_TRACE_STATE_URL = "sentry.url";
const SENTRY_TRACE_STATE_SAMPLE_RAND = "sentry.sample_rand";
const SENTRY_TRACE_STATE_SAMPLE_RATE = "sentry.sample_rate";
const SENTRY_TRACE_STATE_CHILD_IGNORED = "sentry.ignored";
const SENTRY_TRACE_STATE_SEGMENT_IGNORED = "sentry.segment_ignored";
const SENTRY_SCOPES_CONTEXT_KEY = createContextKey("sentry_scopes");
const SENTRY_FORK_ISOLATION_SCOPE_CONTEXT_KEY = createContextKey("sentry_fork_isolation_scope");
const SENTRY_FORK_SET_SCOPE_CONTEXT_KEY = createContextKey("sentry_fork_set_scope");
const SENTRY_FORK_SET_ISOLATION_SCOPE_CONTEXT_KEY = createContextKey("sentry_fork_set_isolation_scope");
const SCOPE_CONTEXT_FIELD = "_scopeContext";
function getScopesFromContext(context) {
return context.getValue(SENTRY_SCOPES_CONTEXT_KEY);
}
function setScopesOnContext(context, scopes) {
return context.setValue(SENTRY_SCOPES_CONTEXT_KEY, scopes);
}
function setContextOnScope(scope, context) {
addNonEnumerableProperty(scope, SCOPE_CONTEXT_FIELD, makeWeakRef(context));
}
function getContextFromScope(scope) {
return derefWeakRef(scope[SCOPE_CONTEXT_FIELD]);
}
function isSentryRequestSpan(span) {
if (!spanHasAttributes(span)) {
return false;
}
const { attributes } = span;
const httpUrl = attributes[HTTP_URL] || attributes[URL_FULL];
if (!httpUrl) {
return false;
}
return isSentryRequestUrl(httpUrl.toString(), getClient());
}
function getSamplingDecision(spanContext) {
const { traceFlags, traceState } = spanContext;
const sampledNotRecording = traceState ? traceState.get(SENTRY_TRACE_STATE_SAMPLED_NOT_RECORDING) === "1" : false;
if (traceFlags === TraceFlags.SAMPLED) {
return true;
}
if (sampledNotRecording) {
return false;
}
const dscString = traceState ? traceState.get(SENTRY_TRACE_STATE_DSC) : void 0;
const dsc = dscString ? baggageHeaderToDynamicSamplingContext(dscString) : void 0;
if (dsc?.sampled === "true") {
return true;
}
if (dsc?.sampled === "false") {
return false;
}
return void 0;
}
function inferSpanData(spanName, attributes, kind) {
const httpMethod = attributes[HTTP_REQUEST_METHOD] || attributes[HTTP_METHOD];
if (httpMethod) {
return descriptionForHttpMethod({ attributes, name: spanName, kind }, httpMethod);
}
const dbSystem = attributes[DB_SYSTEM_NAME] || attributes[DB_SYSTEM];
const opIsCache = typeof attributes[SEMANTIC_ATTRIBUTE_SENTRY_OP] === "string" && attributes[SEMANTIC_ATTRIBUTE_SENTRY_OP].startsWith("cache.");
if (dbSystem && !opIsCache) {
return descriptionForDbSystem({ attributes, name: spanName });
}
const customSourceOrRoute = attributes[SEMANTIC_ATTRIBUTE_SENTRY_SOURCE] === "custom" ? "custom" : "route";
const rpcService = attributes[RPC_SERVICE];
if (rpcService) {
return {
...getUserUpdatedNameAndSource(spanName, attributes, "route"),
op: "rpc"
};
}
const messagingSystem = attributes[MESSAGING_SYSTEM];
if (messagingSystem) {
return {
...getUserUpdatedNameAndSource(spanName, attributes, customSourceOrRoute),
op: "message"
};
}
const faasTrigger = attributes[FAAS_TRIGGER];
if (faasTrigger) {
return {
...getUserUpdatedNameAndSource(spanName, attributes, customSourceOrRoute),
op: faasTrigger.toString()
};
}
return { op: void 0, description: spanName, source: "custom" };
}
function parseSpanDescription(span) {
const attributes = spanHasAttributes(span) ? span.attributes : {};
const name = spanHasName(span) ? span.name : "<unknown>";
const kind = getSpanKind(span);
return inferSpanData(name, attributes, kind);
}
function descriptionForDbSystem({ attributes, name }) {
const userDefinedName = attributes[SEMANTIC_ATTRIBUTE_SENTRY_CUSTOM_SPAN_NAME];
if (typeof userDefinedName === "string") {
return {
op: "db",
description: userDefinedName,
source: attributes[SEMANTIC_ATTRIBUTE_SENTRY_SOURCE] || "custom"
};
}
if (attributes[SEMANTIC_ATTRIBUTE_SENTRY_SOURCE] === "custom") {
return { op: "db", description: name, source: "custom" };
}
const statement = attributes[DB_STATEMENT];
const description = statement ? statement.toString() : name;
return { op: "db", description, source: "task" };
}
function descriptionForHttpMethod({ name, kind, attributes }, httpMethod) {
const opParts = ["http"];
switch (kind) {
case SpanKind.CLIENT:
opParts.push("client");
break;
case SpanKind.SERVER:
opParts.push("server");
break;
}
if (attributes["sentry.http.prefetch"]) {
opParts.push("prefetch");
}
const { urlPath, url, query, fragment, hasRoute } = getSanitizedUrl(attributes, kind);
if (!urlPath) {
return { ...getUserUpdatedNameAndSource(name, attributes), op: opParts.join(".") };
}
const graphqlOperationsAttribute = attributes[SEMANTIC_ATTRIBUTE_SENTRY_GRAPHQL_OPERATION];
const baseDescription = `${httpMethod} ${urlPath}`;
const inferredDescription = graphqlOperationsAttribute ? `${baseDescription} (${getGraphqlOperationNamesFromAttribute(graphqlOperationsAttribute)})` : baseDescription;
const inferredSource = hasRoute || urlPath === "/" ? "route" : "url";
const data = {};
if (url) {
data.url = url;
}
if (query) {
data["http.query"] = query;
}
if (fragment) {
data["http.fragment"] = fragment;
}
const isClientOrServerKind = kind === SpanKind.CLIENT || kind === SpanKind.SERVER;
const origin = attributes[SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN] || "manual";
const isManualSpan = !`${origin}`.startsWith("auto");
const alreadyHasCustomSource = attributes[SEMANTIC_ATTRIBUTE_SENTRY_SOURCE] === "custom";
const customSpanName = attributes[SEMANTIC_ATTRIBUTE_SENTRY_CUSTOM_SPAN_NAME];
const useInferredDescription = !alreadyHasCustomSource && customSpanName == null && (isClientOrServerKind || !isManualSpan);
const { description, source } = useInferredDescription ? { description: inferredDescription, source: inferredSource } : getUserUpdatedNameAndSource(name, attributes);
return {
op: opParts.join("."),
description,
source,
data
};
}
function getGraphqlOperationNamesFromAttribute(attr) {
if (Array.isArray(attr)) {
const sorted = attr.slice().sort();
if (sorted.length <= 5) {
return sorted.join(", ");
} else {
return `${sorted.slice(0, 5).join(", ")}, +${sorted.length - 5}`;
}
}
return `${attr}`;
}
function getSanitizedUrl(attributes, kind) {
const httpTarget = attributes[HTTP_TARGET];
const httpUrl = attributes[HTTP_URL] || attributes[URL_FULL];
const httpRoute = attributes[HTTP_ROUTE];
const parsedUrl = typeof httpUrl === "string" ? parseUrl(httpUrl) : void 0;
const url = parsedUrl ? getSanitizedUrlString(parsedUrl) : void 0;
const query = parsedUrl?.search || void 0;
const fragment = parsedUrl?.hash || void 0;
if (typeof httpRoute === "string") {
return { urlPath: httpRoute, url, query, fragment, hasRoute: true };
}
if (kind === SpanKind.SERVER && typeof httpTarget === "string") {
return { urlPath: stripUrlQueryAndFragment(httpTarget), url, query, fragment, hasRoute: false };
}
if (parsedUrl) {
return { urlPath: url, url, query, fragment, hasRoute: false };
}
if (typeof httpTarget === "string") {
return { urlPath: stripUrlQueryAndFragment(httpTarget), url, query, fragment, hasRoute: false };
}
return { urlPath: void 0, url, query, fragment, hasRoute: false };
}
function getUserUpdatedNameAndSource(originalName, attributes, fallbackSource = "custom") {
const source = attributes[SEMANTIC_ATTRIBUTE_SENTRY_SOURCE] || fallbackSource;
const description = attributes[SEMANTIC_ATTRIBUTE_SENTRY_CUSTOM_SPAN_NAME];
if (description && typeof description === "string") {
return {
description,
source
};
}
return { description: originalName, source };
}
function enhanceDscWithOpenTelemetryRootSpanName(client) {
client.on("createDsc", (dsc, rootSpan) => {
if (!rootSpan) {
return;
}
const jsonSpan = spanToJSON(rootSpan);
const attributes = jsonSpan.data;
const source = attributes[SEMANTIC_ATTRIBUTE_SENTRY_SOURCE];
const { description } = spanHasName(rootSpan) ? parseSpanDescription(rootSpan) : { description: void 0 };
if (source !== "url" && description) {
dsc.transaction = description;
}
if (hasSpansEnabled()) {
const sampled = getSamplingDecision(rootSpan.spanContext());
dsc.sampled = sampled == void 0 ? void 0 : String(sampled);
}
});
}
function getActiveSpan() {
return trace.getActiveSpan();
}
const DEBUG_BUILD = (typeof __SENTRY_DEBUG__ === 'undefined' || __SENTRY_DEBUG__);
class TraceState {
constructor() {
this._internalState = /* @__PURE__ */ new Map();
}
/** @inheritDoc */
set(key, value) {
const next = this._clone();
if (next._internalState.has(key)) {
next._internalState.delete(key);
}
next._internalState.set(key, value);
return next;
}
/** @inheritDoc */
unset(key) {
const next = this._clone();
next._internalState.delete(key);
return next;
}
/** @inheritDoc */
get(key) {
return this._internalState.get(key);
}
/** @inheritDoc */
serialize() {
return Array.from(this._internalState.keys()).reverse().map((key) => `${key}=${this._internalState.get(key)}`).join(",");
}
_clone() {
const next = new TraceState();
next._internalState = new Map(this._internalState);
return next;
}
}
function makeTraceState({
dsc,
sampled
}) {
const dscString = dsc ? dynamicSamplingContextToSentryBaggageHeader(dsc) : void 0;
const traceStateBase = new TraceState();
const traceStateWithDsc = dscString ? traceStateBase.set(SENTRY_TRACE_STATE_DSC, dscString) : traceStateBase;
return sampled === false ? traceStateWithDsc.set(SENTRY_TRACE_STATE_SAMPLED_NOT_RECORDING, "1") : traceStateWithDsc;
}
const setupElements = /* @__PURE__ */ new Set();
function openTelemetrySetupCheck() {
return Array.from(setupElements);
}
function setIsSetup(element) {
setupElements.add(element);
}
class SentryPropagator extends W3CBaggagePropagator {
constructor() {
super();
setIsSetup("SentryPropagator");
this._urlMatchesTargetsMap = new LRUMap(100);
}
/**
* @inheritDoc
*/
inject(context2, carrier, setter) {
if (isTracingSuppressed(context2)) {
DEBUG_BUILD && debug.log("[Tracing] Not injecting trace data for url because tracing is suppressed.");
return;
}
const activeSpan = trace.getSpan(context2);
const url = activeSpan && getCurrentURL(activeSpan);
const { tracePropagationTargets, propagateTraceparent } = getClient()?.getOptions() || {};
if (!shouldPropagateTraceForUrl(url, tracePropagationTargets, this._urlMatchesTargetsMap)) {
DEBUG_BUILD && debug.log("[Tracing] Not injecting trace data for url because it does not match tracePropagationTargets:", url);
return;
}
const existingBaggageHeader = getExistingBaggage(carrier);
const existingSentryTraceHeader = getExistingSentryTrace(carrier);
let baggage = propagation.getBaggage(context2) || propagation.createBaggage({});
const { dynamicSamplingContext, traceId, spanId, sampled } = getInjectionData(context2);
if (existingBaggageHeader) {
const baggageEntries = parseBaggageHeader(existingBaggageHeader);
if (baggageEntries) {
Object.entries(baggageEntries).forEach(([key, value]) => {
if (!existingSentryTraceHeader && key.startsWith(SENTRY_BAGGAGE_KEY_PREFIX)) {
return;
}
baggage = baggage.setEntry(key, { value });
});
}
}
if (!existingSentryTraceHeader && dynamicSamplingContext) {
baggage = Object.entries(dynamicSamplingContext).reduce((b, [dscKey, dscValue]) => {
if (dscValue) {
return b.setEntry(`${SENTRY_BAGGAGE_KEY_PREFIX}${dscKey}`, { value: dscValue });
}
return b;
}, baggage);
}
if (!existingSentryTraceHeader && traceId && traceId !== INVALID_TRACEID) {
setter.set(carrier, SENTRY_TRACE_HEADER, generateSentryTraceHeader(traceId, spanId, sampled));
if (propagateTraceparent) {
setter.set(carrier, "traceparent", generateTraceparentHeader(traceId, spanId, sampled));
}
}
super.inject(propagation.setBaggage(context2, baggage), carrier, setter);
}
/**
* @inheritDoc
*/
extract(context2, carrier, getter) {
const maybeSentryTraceHeader = getter.get(carrier, SENTRY_TRACE_HEADER);
const baggage = getter.get(carrier, SENTRY_BAGGAGE_HEADER);
const sentryTrace = maybeSentryTraceHeader ? Array.isArray(maybeSentryTraceHeader) ? maybeSentryTraceHeader[0] : maybeSentryTraceHeader : void 0;
return ensureScopesOnContext(getContextWithRemoteActiveSpan(context2, { sentryTrace, baggage }));
}
/**
* @inheritDoc
*/
fields() {
return [SENTRY_TRACE_HEADER, SENTRY_BAGGAGE_HEADER, "traceparent"];
}
}
function getInjectionData(context2, options = {}) {
const span = trace.getSpan(context2);
if (span?.spanContext().isRemote) {
const spanContext = span.spanContext();
const dynamicSamplingContext2 = getDynamicSamplingContextFromSpan(span);
return {
dynamicSamplingContext: dynamicSamplingContext2,
traceId: spanContext.traceId,
spanId: void 0,
sampled: getSamplingDecision(spanContext)
// TODO: Do we need to change something here?
};
}
if (span) {
const spanContext = span.spanContext();
const dynamicSamplingContext2 = getDynamicSamplingContextFromSpan(span);
return {
dynamicSamplingContext: dynamicSamplingContext2,
traceId: spanContext.traceId,
spanId: spanContext.spanId,
sampled: getSamplingDecision(spanContext)
// TODO: Do we need to change something here?
};
}
const scope = options.scope || getScopesFromContext(context2)?.scope || getCurrentScope();
const client = options.client || getClient();
const propagationContext = scope.getPropagationContext();
const dynamicSamplingContext = client ? getDynamicSamplingContextFromScope(client, scope) : void 0;
return {
dynamicSamplingContext,
traceId: propagationContext.traceId,
spanId: propagationContext.propagationSpanId,
sampled: propagationContext.sampled
};
}
function getContextWithRemoteActiveSpan(ctx, { sentryTrace, baggage }) {
const propagationContext = propagationContextFromHeaders(sentryTrace, baggage);
const { traceId, parentSpanId, sampled, dsc } = propagationContext;
const client = getClient();
const incomingDsc = baggageHeaderToDynamicSamplingContext(baggage);
if (!parentSpanId || client && !shouldContinueTrace(client, incomingDsc?.org_id)) {
return ctx;
}
const spanContext = generateRemoteSpanContext({
traceId,
spanId: parentSpanId,
sampled,
dsc
});
return trace.setSpanContext(ctx, spanContext);
}
function continueTraceAsRemoteSpan(ctx, options, callback) {
const ctxWithSpanContext = ensureScopesOnContext(getContextWithRemoteActiveSpan(ctx, options));
return context.with(ctxWithSpanContext, callback);
}
function ensureScopesOnContext(ctx) {
const scopes = getScopesFromContext(ctx);
const newScopes = {
// If we have no scope here, this is most likely either the root context or a context manually derived from it
// In this case, we want to fork the current scope, to ensure we do not pollute the root scope
scope: scopes ? scopes.scope : getCurrentScope().clone(),
isolationScope: scopes ? scopes.isolationScope : getIsolationScope()
};
return setScopesOnContext(ctx, newScopes);
}
function getExistingBaggage(carrier) {
try {
const baggage = carrier[SENTRY_BAGGAGE_HEADER];
return Array.isArray(baggage) ? baggage.join(",") : baggage;
} catch {
return void 0;
}
}
function getExistingSentryTrace(carrier) {
try {
return carrier[SENTRY_TRACE_HEADER];
} catch {
return void 0;
}
}
function getCurrentURL(span) {
const spanData = spanToJSON(span).data;
const urlAttribute = spanData[HTTP_URL] || spanData[URL_FULL];
if (typeof urlAttribute === "string") {
return urlAttribute;
}
const urlTraceState = span.spanContext().traceState?.get(SENTRY_TRACE_STATE_URL);
if (urlTraceState) {
return urlTraceState;
}
return void 0;
}
function generateRemoteSpanContext({
spanId,
traceId,
sampled,
dsc
}) {
const traceState = makeTraceState({
dsc,
sampled
});
const spanContext = {
traceId,
spanId,
isRemote: true,
traceFlags: sampled ? TraceFlags.SAMPLED : TraceFlags.NONE,
traceState
};
return spanContext;
}
function _startSpan(options, callback, autoEnd) {
const tracer = getTracer();
const { name, parentSpan: customParentSpan } = options;
const wrapper = getActiveSpanWrapper(customParentSpan);
return wrapper(() => {
const activeCtx = getContext(options.scope, options.forceTransaction);
const missingRequiredParent = options.onlyIfParent && !trace.getSpan(activeCtx);
const ctx = missingRequiredParent ? suppressTracing$1(activeCtx) : activeCtx;
if (missingRequiredParent) {
getClient()?.recordDroppedEvent("no_parent_span", "span");
}
const spanOptions = getSpanOptions(options);
if (!hasSpansEnabled()) {
const suppressedCtx = isTracingSuppressed(ctx) ? ctx : suppressTracing$1(ctx);
return context.with(suppressedCtx, () => {
return tracer.startActiveSpan(name, spanOptions, suppressedCtx, (span) => {
patchSpanEnd(span);
return context.with(activeCtx, () => {
return handleCallbackErrors(
() => callback(span),
() => {
if (spanToJSON(span).status === void 0) {
span.setStatus({ code: SpanStatusCode.ERROR });
}
},
autoEnd ? () => span.end() : void 0
);
});
});
});
}
return tracer.startActiveSpan(name, spanOptions, ctx, (span) => {
patchSpanEnd(span);
return handleCallbackErrors(
() => callback(span),
() => {
if (spanToJSON(span).status === void 0) {
span.setStatus({ code: SpanStatusCode.ERROR });
}
},
autoEnd ? () => span.end() : void 0
);
});
});
}
function startSpan(options, callback) {
return _startSpan(options, callback, true);
}
function startSpanManual(options, callback) {
return _startSpan(options, (span) => callback(span, () => span.end()), false);
}
function startInactiveSpan(options) {
const tracer = getTracer();
const { name, parentSpan: customParentSpan } = options;
const wrapper = getActiveSpanWrapper(customParentSpan);
return wrapper(() => {
const activeCtx = getContext(options.scope, options.forceTransaction);
const missingRequiredParent = options.onlyIfParent && !trace.getSpan(activeCtx);
let ctx = missingRequiredParent ? suppressTracing$1(activeCtx) : activeCtx;
if (missingRequiredParent) {
getClient()?.recordDroppedEvent("no_parent_span", "span");
}
const spanOptions = getSpanOptions(options);
if (!hasSpansEnabled()) {
ctx = isTracingSuppressed(ctx) ? ctx : suppressTracing$1(ctx);
}
const span = tracer.startSpan(name, spanOptions, ctx);
patchSpanEnd(span);
return span;
});
}
function withActiveSpan(span, callback) {
const newContextWithActiveSpan = span ? trace.setSpan(context.active(), span) : trace.deleteSpan(context.active());
return context.with(newContextWithActiveSpan, () => callback(getCurrentScope()));
}
function getTracer() {
const client = getClient();
return client?.tracer || trace.getTracer("@sentry/opentelemetry", SDK_VERSION);
}
function getSpanOptions(options) {
const { startTime, attributes, kind, op, links } = options;
const fixedStartTime = typeof startTime === "number" ? ensureTimestampInMilliseconds(startTime) : startTime;
return {
attributes: op ? {
[SEMANTIC_ATTRIBUTE_SENTRY_OP]: op,
...attributes
} : attributes,
kind,
links,
startTime: fixedStartTime
};
}
function ensureTimestampInMilliseconds(timestamp) {
const isMs = timestamp < 9999999999;
return isMs ? timestamp * 1e3 : timestamp;
}
function patchSpanEnd(span) {
const originalEnd = span.end.bind(span);
span.end = (endTime) => {
return originalEnd(typeof endTime === "number" ? ensureTimestampInMilliseconds(endTime) : endTime);
};
}
function getContext(scope, forceTransaction) {
const ctx = getContextForScope(scope);
const parentSpan = trace.getSpan(ctx);
if (!parentSpan) {
return ctx;
}
if (!forceTransaction) {
return ctx;
}
const ctxWithoutSpan = trace.deleteSpan(ctx);
const { spanId, traceId } = parentSpan.spanContext();
const sampled = getSamplingDecision(parentSpan.spanContext());
const rootSpan = getRootSpan(parentSpan);
const dsc = getDynamicSamplingContextFromSpan(rootSpan);
const traceState = makeTraceState({
dsc,
sampled
});
const spanOptions = {
traceId,
spanId,
isRemote: true,
traceFlags: sampled ? TraceFlags.SAMPLED : TraceFlags.NONE,
traceState
};
const ctxWithSpanContext = trace.setSpanContext(ctxWithoutSpan, spanOptions);
return ctxWithSpanContext;
}
function getContextForScope(scope) {
if (scope) {
const ctx = getContextFromScope(scope);
if (ctx) {
return ctx;
}
}
return context.active();
}
function continueTrace(options, callback) {
return continueTraceAsRemoteSpan(context.active(), options, callback);
}
function startNewTrace(callback) {
const traceId = generateTraceId();
const spanId = generateSpanId();
const spanContext = {
traceId,
spanId,
isRemote: true,
traceFlags: TraceFlags.NONE
};
const ctxWithTrace = trace.setSpanContext(context.active(), spanContext);
return context.with(ctxWithTrace, () => {
getCurrentScope().setPropagationContext({
traceId,
sampleRand: _INTERNAL_safeMathRandom()
});
return callback();
});
}
function getTraceContextForScope(client, scope) {
const ctx = getContextFromScope(scope);
const span = ctx && trace.getSpan(ctx);
const traceContext = span ? spanToTraceContext(span) : getTraceContextFromScope(scope);
const dynamicSamplingContext = span ? getDynamicSamplingContextFromSpan(span) : getDynamicSamplingContextFromScope(client, scope);
return [dynamicSamplingContext, traceContext];
}
function getActiveSpanWrapper(parentSpan) {
return parentSpan !== void 0 ? (callback) => {
return withActiveSpan(parentSpan, callback);
} : (callback) => callback();
}
function suppressTracing(callback) {
const ctx = suppressTracing$1(context.active());
return context.with(ctx, callback);
}
function setupEventContextTrace(client) {
client.on("preprocessEvent", (event) => {
const span = getActiveSpan();
if (!span || event.type === "transaction") {
return;
}
event.contexts = {
trace: spanToTraceContext(span),
...event.contexts
};
const rootSpan = getRootSpan(span);
event.sdkProcessingMetadata = {
dynamicSamplingContext: getDynamicSamplingContextFromSpan(rootSpan),
...event.sdkProcessingMetadata
};
return event;
});
}
function getTraceData({
span,
scope,
client,
propagateTraceparent
} = {}) {
let ctx = (scope && getContextFromScope(scope)) ?? api.context.active();
if (span) {
const { scope: scope2 } = getCapturedScopesOnSpan(span);
ctx = scope2 && getContextFromScope(scope2) || api.trace.setSpan(api.context.active(), span);
}
const { traceId, spanId, sampled, dynamicSamplingContext } = getInjectionData(ctx, { scope, client });
const traceData = {
"sentry-trace": generateSentryTraceHeader(traceId, spanId, sampled),
baggage: dynamicSamplingContextToSentryBaggageHeader(dynamicSamplingContext)
};
if (propagateTraceparent) {
traceData.traceparent = generateTraceparentHeader(traceId, spanId, sampled);
}
return traceData;
}
function setOpenTelemetryContextAsyncContextStrategy() {
function getScopes() {
const ctx = api.context.active();
const scopes = getScopesFromContext(ctx);
if (scopes) {
return scopes;
}
return {
scope: getDefaultCurrentScope(),
isolationScope: getDefaultIsolationScope()
};
}
function withScope(callback) {
const ctx = api.context.active();
return api.context.with(ctx, () => {
return callback(getCurrentScope());
});
}
function withSetScope(scope, callback) {
const ctx = getContextFromScope(scope) || api.context.active();
return api.context.with(ctx.setValue(SENTRY_FORK_SET_SCOPE_CONTEXT_KEY, scope), () => {
return callback(scope);
});
}
function withIsolationScope(callback) {
const ctx = api.context.active();
return api.context.with(ctx.setValue(SENTRY_FORK_ISOLATION_SCOPE_CONTEXT_KEY, true), () => {
return callback(getIsolationScope());
});
}
function withSetIsolationScope(isolationScope, callback) {
const ctx = api.context.active();
return api.context.with(ctx.setValue(SENTRY_FORK_SET_ISOLATION_SCOPE_CONTEXT_KEY, isolationScope), () => {
return callback(getIsolationScope());
});
}
function getCurrentScope() {
return getScopes().scope;
}
function getIsolationScope() {
return getScopes().isolationScope;
}
setAsyncContextStrategy({
withScope,
withSetScope,
withSetIsolationScope,
withIsolationScope,
getCurrentScope,
getIsolationScope,
startSpan,
startSpanManual,
startInactiveSpan,
getActiveSpan,
suppressTracing,
getTraceData,
continueTrace,
startNewTrace,
// The types here don't fully align, because our own `Span` type is narrower
// than the OTEL one - but this is OK for here, as we now we'll only have OTEL spans passed around
withActiveSpan,
getTracingChannelBinding: () => {
try {
const contextManager = api.context._getContextManager();
const lookup = contextManager.getAsyncLocalStorageLookup();
return {
asyncLocalStorage: lookup.asyncLocalStorage,
getStoreWithActiveSpan: (span) => api.trace.setSpan(api.context.active(), span)
};
} catch {
return void 0;
}
}
});
}
function buildContextWithSentryScopes(context, activeContext) {
const span = trace.getSpan(context);
let effectiveContext;
if (span?.spanContext().traceState?.get(SENTRY_TRACE_STATE_CHILD_IGNORED) === "1") {
const contextWithoutSpan = trace.deleteSpan(context);
const parentSpan = trace.getSpan(activeContext);
effectiveContext = parentSpan ? trace.setSpan(contextWithoutSpan, parentSpan) : contextWithoutSpan;
} else {
effectiveContext = context;
}
const currentScopes = getScopesFromContext(effectiveContext);
const currentScope = currentScopes?.scope || getCurrentScope();
const currentIsolationScope = currentScopes?.isolationScope || getIsolationScope();
const shouldForkIsolationScope = effectiveContext.getValue(SENTRY_FORK_ISOLATION_SCOPE_CONTEXT_KEY) === true;
const scope = effectiveContext.getValue(SENTRY_FORK_SET_SCOPE_CONTEXT_KEY);
const isolationScope = effectiveContext.getValue(SENTRY_FORK_SET_ISOLATION_SCOPE_CONTEXT_KEY);
const newCurrentScope = scope || currentScope.clone();
const newIsolationScope = isolationScope || (shouldForkIsolationScope ? currentIsolationScope.clone() : currentIsolationScope);
const scopes = { scope: newCurrentScope, isolationScope: newIsolationScope };
const ctx1 = setScopesOnContext(effectiveContext, scopes);
const ctx2 = ctx1.deleteValue(SENTRY_FORK_ISOLATION_SCOPE_CONTEXT_KEY).deleteValue(SENTRY_FORK_SET_SCOPE_CONTEXT_KEY).deleteValue(SENTRY_FORK_SET_ISOLATION_SCOPE_CONTEXT_KEY);
setContextOnScope(newCurrentScope, ctx2);
return ctx2;
}
function wrapContextManagerClass(ContextManagerClass) {
class SentryContextManager extends ContextManagerClass {
constructor(...args) {
super(...args);
setIsSetup("SentryContextManager");
}
/**
* Overwrite with() of the original AsyncLocalStorageContextManager
* to ensure we also create new scopes per context.
*/
with(context, fn, thisArg, ...args) {
const ctx2 = buildContextWithSentryScopes(context, this.active());
return super.with(ctx2, fn, thisArg, ...args);
}
/**
* Gets underlying AsyncLocalStorage and symbol to allow lookup of scope.
*/
getAsyncLocalStorageLookup() {
return {
// @ts-expect-error This is on the base class, but not part of the interface
asyncLocalStorage: this._asyncLocalStorage,
contextSymbol: SENTRY_SCOPES_CONTEXT_KEY
};
}
}
return SentryContextManager;
}
function groupSpansWithParents(spans) {
const nodeMap = /* @__PURE__ */ new Map();
for (const span of spans) {
createOrUpdateSpanNodeAndRefs(nodeMap, span);
}
return Array.from(nodeMap, function([_id, spanNode]) {
return spanNode;
});
}
function getLocalParentId(span) {
const parentIsRemote = span.attributes[SEMANTIC_ATTRIBUTE_SENTRY_PARENT_IS_REMOTE] === true;
return !parentIsRemote ? getParentSpanId(span) : void 0;
}
function createOrUpdateSpanNodeAndRefs(nodeMap, span) {
const id = span.spanContext().spanId;
const parentId = getLocalParentId(span);
if (!parentId) {
createOrUpdateNode(nodeMap, { id, span, children: [] });
return;
}
const parentNode = createOrGetParentNode(nodeMap, parentId);
const node = createOrUpdateNode(nodeMap, { id, span, parentNode, children: [] });
parentNode.children.push(node);
}
function createOrGetParentNode(nodeMap, id) {
const existing = nodeMap.get(id);
if (existing) {
return existing;
}
return createOrUpdateNode(nodeMap, { id, children: [] });
}
function createOrUpdateNode(nodeMap, spanNode) {
const existing = nodeMap.get(spanNode.id);
if (existing?.span) {
return existing;
}
if (existing && !existing.span) {
existing.span = spanNode.span;
existing.parentNode = spanNode.parentNode;
return existing;
}
nodeMap.set(spanNode.id, spanNode);
return spanNode;
}
const canonicalGrpcErrorCodesMap = {
"1": "cancelled",
"2": "unknown_error",
"3": "invalid_argument",
"4": "deadline_exceeded",
"5": "not_found",
"6": "already_exists",
"7": "permission_denied",
"8": "resource_exhausted",
"9": "failed_precondition",
"10": "aborted",
"11": "out_of_range",
"12": "unimplemented",
"13": "internal_error",
"14": "unavailable",
"15": "data_loss",
"16": "unauthenticated"
};
const isStatusErrorMessageValid = (message) => {
return Object.values(canonicalGrpcErrorCodesMap).includes(message);
};
function mapStatus(span) {
const attributes = spanHasAttributes(span) ? span.attributes : {};
const status = spanHasStatus(span) ? span.status : void 0;
if (status) {
if (status.code === SpanStatusCode.OK) {
return { code: SPAN_STATUS_OK };
} else if (status.code === SpanStatusCode.ERROR) {
if (typeof status.message === "undefined") {
const inferredStatus2 = inferStatusFromAttributes(attributes);
if (inferredStatus2) {
return inferredStatus2;
}
}
if (status.message && isStatusErrorMessageValid(status.message)) {
return { code: SPAN_STATUS_ERROR, message: status.message };
} else {
return { code: SPAN_STATUS_ERROR, message: "internal_error" };
}
}
}
const inferredStatus = inferStatusFromAttributes(attributes);
if (inferredStatus) {
return inferredStatus;
}
if (status?.code === SpanStatusCode.UNSET) {
return { code: SPAN_STATUS_OK };
} else {
return { code: SPAN_STATUS_ERROR, message: "unknown_error" };
}
}
function inferStatusFromAttributes(attributes) {
const httpCodeAttribute = attributes[HTTP_RESPONSE_STATUS_CODE] || attributes[HTTP_STATUS_CODE];
const grpcCodeAttribute = attributes[RPC_GRPC_STATUS_CODE];
const numberHttpCode = typeof httpCodeAttribute === "number" ? httpCodeAttribute : typeof httpCodeAttribute === "string" ? parseInt(httpCodeAttribute) : void 0;
if (typeof numberHttpCode === "number") {
return getSpanStatusFromHttpCode(numberHttpCode);
}
if (typeof grpcCodeAttribute === "string") {
return { code: SPAN_STATUS_ERROR, message: canonicalGrpcErrorCodesMap[grpcCodeAttribute] || "unknown_error" };
}
return void 0;
}
const MAX_SPAN_COUNT = 1e3;
const DEFAULT_TIMEOUT = 300;
const SENT_SPANS_MAX_SIZE = 1e4;
class SentrySpanExporter {
constructor(options) {
this._finishedSpanBucketSize = options?.timeout || DEFAULT_TIMEOUT;
this._finishedSpanBuckets = new Array(this._finishedSpanBucketSize).fill(void 0);
this._lastCleanupTimestampInS = Math.floor(_INTERNAL_safeDateNow() / 1e3);
this._spansToBucketEntry = /* @__PURE__ */ new WeakMap();
this._sentSpans = new LRUMap(SENT_SPANS_MAX_SIZE);
this._debouncedFlush = debounce(this.flush.bind(this), 1, { maxWait: 100 });
}
/**
* Export a single span.
* This is called by the span processor whenever a span is ended.
*/
export(span) {
const currentTimestampInS = Math.floor(_INTERNAL_safeDateNow() / 1e3);
if (this._lastCleanupTimestampInS !== currentTimestampInS) {
let droppedSpanCount = 0;
this._finishedSpanBuckets.forEach((bucket, i) => {
if (bucket && bucket.timestampInS <= currentTimestampInS - this._finishedSpanBucketSize) {
droppedSpanCount += bucket.spans.size;
this._finishedSpanBuckets[i] = void 0;
}
});
if (droppedSpanCount > 0) {
DEBUG_BUILD && debug.log(
`SpanExporter dropped ${droppedSpanCount} spans because they were pending for more than ${this._finishedSpanBucketSize} seconds.`
);
}
this._lastCleanupTimestampInS = currentTimestampInS;
}
const currentBucketIndex = currentTimestampInS % this._finishedSpanBucketSize;
const currentBucket = this._finishedSpanBuckets[currentBucketIndex] || {
timestampInS: currentTimestampInS,
spans: /* @__PURE__ */ new Set()
};
this._finishedSpanBuckets[currentBucketIndex] = currentBucket;
currentBucket.spans.add(span);
this._spansToBucketEntry.set(span, currentBucket);
const localParentId = getLocalParentId(span);
if (!localParentId || this._sentSpans.get(localParentId)) {
this._debouncedFlush();
}
}
/**
* Try to flush any pending spans immediately.
* This is called internally by the exporter (via _debouncedFlush),
* but can also be triggered externally if we force-flush.
*/
flush() {
const finishedSpans = this._finishedSpanBuckets.flatMap((bucket) => bucket ? Array.from(bucket.spans) : []);
const sentSpans = this._maybeSend(finishedSpans);
const sentSpanCount = sentSpans.size;
const remainingOpenSpanCount = finishedSpans.length - sentSpanCount;
DEBUG_BUILD && debug.log(
`SpanExporter exported ${sentSpanCount} spans, ${remainingOpenSpanCount} spans are waiting for their parent spans to finish`
);
for (const span of sentSpans) {
this._sentSpans.set(span.spanContext().spanId, 1);
const bucketEntry = this._spansToBucketEntry.get(span);
if (bucketEntry) {
bucketEntry.spans.delete(span);
}
}
this._debouncedFlush.cancel();
}
/**
* Clear the exporter.
* This is called when the span processor is shut down.
*/
clear() {
this._finishedSpanBuckets = this._finishedSpanBuckets.fill(void 0);
this._sentSpans.clear();
this._debouncedFlush.cancel();
}
/**
* Send the given spans, but only if they are part of a finished transaction.
*
* Returns the sent spans.
* Spans remain unsent when their parent span is not yet finished.
* This will happen regularly, as child spans are generally finished before their parents.
* But it _could_ also happen because, for whatever reason, a parent span was lost.
* In this case, we'll eventually need to clean this up.
*/
_maybeSend(spans) {
const grouped = groupSpansWithParents(spans);
const sentSpans = /* @__PURE__ */ new Set();
const rootNodes = this._getCompletedRootNodes(grouped);
for (const root of rootNodes) {
const span = root.span;
sentSpans.add(span);
const transactionEvent = createTransactionForOtelSpan(span);
if (root.parentNode && this._sentSpans.get(root.parentNode.id)) {
const traceData = transactionEvent.contexts?.trace?.data;
if (traceData) {
traceData["sentry.parent_span_already_sent"] = true;
}
}
const spans2 = transactionEvent.spans || [];
let hasGenAiSpans = false;
for (const child of root.children) {
if (createAndFinishSpanForOtelSpan(child, spans2, sentSpans)) {
hasGenAiSpans = true;
}
}
transactionEvent.spans = spans2.length > MAX_SPAN_COUNT ? spans2.sort((a, b) => a.start_timestamp - b.start_timestamp).slice(0, MAX_SPAN_COUNT) : spans2;
if (hasGenAiSpans) {
transactionEvent.sdkProcessingMetadata = {
...transactionEvent.sdkProcessingMetadata,
hasGenAiSpans: true
};
}
const measurements = timedEventsToMeasurements(span.events);
if (measurements) {
transactionEvent.measurements = measurements;
}
captureEvent(transactionEvent);
}
return sentSpans;
}
/** Check if a node is a completed root node or a node whose parent has already been sent */
_nodeIsCompletedRootNodeOrHasSentParent(node) {
return !!node.span && (!node.parentNode || !!this._sentSpans.get(node.parentNode.id));
}
/** Get all completed root nodes from a list of nodes */
_getCompletedRootNodes(nodes) {
return nodes.filter((node) => this._nodeIsCompletedRootNodeOrHasSentParent(node));
}
}
function parseSpan(span) {
const attributes = span.attributes;
const origin = attributes[SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN];
const op = attributes[SEMANTIC_ATTRIBUTE_SENTRY_OP];
const source = attributes[SEMANTIC_ATTRIBUTE_SENTRY_SOURCE];
return { origin, op, source };
}
function createTransactionForOtelSpan(span) {
const { op, description, data, origin = "manual", source } = getSpanData(span);
const capturedSpanScopes = getCapturedScopesOnSpan(span);
const sampleRate = span.attributes[SEMANTIC_ATTRIBUTE_SENTRY_SAMPLE_RATE];
const attributes = {
[SEMANTIC_ATTRIBUTE_SENTRY_SOURCE]: source,
[SEMANTIC_ATTRIBUTE_SENTRY_SAMPLE_RATE]: sampleRate,
[SEMANTIC_ATTRIBUTE_SENTRY_OP]: op,
[SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: origin,
...data,
...removeSentryAttributes(span.attributes)
};
const { links } = span;
const { traceId: trace_id, spanId: span_id } = span.spanContext();
const parent_span_id = getParentSpanId(span);
const status = mapStatus(span);
const traceContext = {
parent_span_id,
span_id,
trace_id,
data: attributes,
origin,
op,
status: getStatusMessage(status),
// As per protocol, span status is allowed to be undefined
links: convertSpanLinksForEnvelope(links)
};
const statusCode = attributes[HTTP_RESPONSE_STATUS_CODE];
const responseContext = typeof statusCode === "number" ? { response: { status_code: statusCode } } : void 0;
const transactionEvent = {
contexts: {
trace: traceContext,
otel: {
resource: span.resource.attributes
},
...responseContext
},
spans: [],
start_timestamp: spanTimeInputToSeconds(span.startTime),
timestamp: spanTimeInputToSeconds(span.endTime),
transaction: description,
type: "transaction",
sdkProcessingMetadata: {
capturedSpanScope: capturedSpanScopes.scope,
capturedSpanIsolationScope: capturedSpanScopes.isolationScope,
sampleRate,
dynamicSamplingContext: getDynamicSamplingContextFromSpan(span)
},
...source && {
transaction_info: {
source
}
}
};
return transactionEvent;
}
function createAndFinishSpanForOtelSpan(node, spans, sentSpans) {
const span = node.span;
if (span) {
sentSpans.add(span);
}
const shouldDrop = !span;
if (shouldDrop) {
let hasGenAiSpans2 = false;
node.children.forEach((child) => {
if (createAndFinishSpanForOtelSpan(child, spans, sentSpans)) {
hasGenAiSpans2 = true;
}
});
return hasGenAiSpans2;
}
const span_id = span.spanContext().spanId;
const trace_id = span.spanContext().traceId;
const parentSpanId = getParentSpanId(span);
const { attributes, startTime, endTime, links } = span;
const { op, description, data, origin = "manual" } = getSpanData(span);
const allData = {
[SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: origin,
[SEMANTIC_ATTRIBUTE_SENTRY_OP]: op,
...removeSentryAttributes(attributes),
...data
};
const status = mapStatus(span);
const spanJSON = {
span_id,
trace_id,
data: allData,
description,
parent_span_id: parentSpanId,
start_timestamp: spanTimeInputToSeconds(startTime),
// This is [0,0] by default in OTEL, in which case we want to interpret this as no end time
timestamp: spanTimeInputToSeconds(endTime) || void 0,
status: getStatusMessage(status),
// As per protocol, span status is allowed to be undefined
op,
origin,
measurements: timedEventsToMeasurements(span.events),
links: convertSpanLinksForEnvelope(links)
};
spans.push(spanJSON);
let hasGenAiSpans = !!op?.startsWith("gen_ai.");
node.children.forEach((child) => {
if (createAndFinishSpanForOtelSpan(child, spans, sentSpans)) {
hasGenAiSpans = true;
}
});
return hasGenAiSpans;
}
function getSpanData(span) {
const { op: definedOp, source: definedSource, origin } = parseSpan(span);
const { op: inferredOp, description, source: inferredSource, data: inferredData } = parseSpanDescription(span);
const op = definedOp || inferredOp;
const source = definedSource || inferredSource;
const data = { ...inferredData, ...getData(span) };
return {
op,
description,
source,
origin,
data
};
}
function removeSentryAttributes(data) {
const cleanedData = { ...data };
delete cleanedData[SEMANTIC_ATTRIBUTE_SENTRY_SAMPLE_RATE];
delete cleanedData[SEMANTIC_ATTRIBUTE_SENTRY_PARENT_IS_REMOTE];
delete cleanedData[SEMANTIC_ATTRIBUTE_SENTRY_CUSTOM_SPAN_NAME];
return cleanedData;
}
function getData(span) {
const attributes = span.attributes;
const data = {};
if (span.kind !== SpanKind.INTERNAL) {
data["otel.kind"] = SpanKind[span.kind];
}
const maybeHttpStatusCodeAttribute = attributes[HTTP_STATUS_CODE];
if (maybeHttpStatusCodeAttribute) {
data[HTTP_RESPONSE_STATUS_CODE] = maybeHttpStatusCodeAttribute;
}
const requestData = getRequestSpanData(span);
if (requestData.url) {
data.url = requestData.url;
}
if (requestData["http.query"]) {
data["http.query"] = requestData["http.query"].slice(1);
}
if (requestData["http.fragment"]) {
data["http.fragment"] = requestData["http.fragment"].slice(1);
}
return data;
}
class SentrySpanProcessor {
constructor(options) {
this._unsubscribePreprocessSpan = void 0;
setIsSetup("SentrySpanProcessor");
this._exporter = new SentrySpanExporter(options);
this._client = options?.client ?? getClient();
if (this._client && hasSpanStreamingEnabled(this._client)) {
this._unsubscribePreprocessSpan = this._client.on("preprocessSpan", backfillStreamedSpanDataFromOtel);
}
}
/**
* @inheritDoc
*/
async forceFlush() {
this._exporter.flush();
}
/**
* @inheritDoc
*/
async shutdown() {
this._unsubscribePreprocessSpan?.();
this._exporter.clear();
}
/**
* @inheritDoc
*/
onStart(span, parentContext) {
const parentSpan = trace.getSpan(parentContext);
let scopes = getScopesFromContext(parentContext);
if (parentSpan && !parentSpan.spanContext().isRemote) {
addChildSpanToSpan(parentSpan, span);
}
if (parentSpan?.spanContext().isRemote) {
span.setAttribute(SEMANTIC_ATTRIBUTE_SENTRY_PARENT_IS_REMOTE, true);
}
if (parentContext === ROOT_CONTEXT) {
scopes = {
scope: getDefaultCurrentScope(),
isolationScope: getDefaultIsolationScope()
};
}
if (scopes) {
setCapturedScopesOnSpan(span, scopes.scope, scopes.isolationScope);
}
logSpanStart(span);
this._client?.emit("spanStart", span);
}
/** @inheritDoc */
onEnd(span) {
logSpanEnd(span);
this._client?.emit("spanEnd", span);
if (this._client && hasSpanStreamingEnabled(this._client)) {
this._client.emit("afterSpanEnd", span);
} else {
this._exporter.export(span);
}
}
}
function backfillStreamedSpanDataFromOtel(spanJSON, hint) {
const attributes = spanJSON.attributes;
if (!attributes) {
return;
}
const kind = hint?.spanKind ?? SpanKind.INTERNAL;
const { op, description, source, data } = inferSpanData(spanJSON.name, attributes, kind);
spanJSON.name = description;
safeSetSpanJSONAttributes(spanJSON, {
[SEMANTIC_ATTRIBUTE_SENTRY_OP]: op,
[SEMANTIC_ATTRIBUTE_SENTRY_SOURCE]: source,
...data
});
if (kind !== SpanKind.INTERNAL) {
safeSetSpanJSONAttributes(spanJSON, {
"otel.kind": SpanKind[kind]
});
}
}
class SentrySampler {
constructor(client) {
this._client = client;
this._isSpanStreaming = hasSpanStreamingEnabled(client);
setIsSetup("SentrySampler");
}
/** @inheritDoc */
shouldSample(context, traceId, spanName, spanKind, spanAttributes, _links) {
const options = this._client.getOptions();
const { ignoreSpans } = options;
const parentSpan = getValidSpan(context);
const parentContext = parentSpan?.spanContext();
if (!hasSpansEnabled(options)) {
return wrapSamplingDecision({ decision: void 0, context, spanAttributes });
}
const maybeSpanHttpMethod = spanAttributes[HTTP_METHOD] || spanAttributes[HTTP_REQUEST_METHOD];
if (spanKind === SpanKind.CLIENT && maybeSpanHttpMethod && (!parentSpan || parentContext?.isRemote)) {
if (!this._isSpanStreaming) {
this._client.recordDroppedEvent("no_parent_span", "span");
return wrapSamplingDecision({ decision: void 0, context, spanAttributes });
}
}
const parentSampled = parentSpan ? getParentSampled(parentSpan, traceId, spanName) : void 0;
const isRootSpan = !parentSpan || parentContext?.isRemote;
if (!isRootSpan) {
if (this._isSpanStreaming) {
if (parentSampled) {
if (ignoreSpans?.length) {
const { description: inferredChildName, op: childOp } = inferSpanData(spanName, spanAttributes, spanKind);
if (shouldIgnoreSpan(
{
description: inferredChildName,
op: spanAttributes[SEMANTIC_ATTRIBUTE_SENTRY_OP] ?? childOp,
attributes: spanAttributes
},
ignoreSpans
)) {
this._client.recordDroppedEvent("ignored", "span");
return wrapSamplingDecision({
decision: SamplingDecision.NOT_RECORD,
context,
spanAttributes,
ignoredChildSpan: true
});
}
}
}
if (!parentSampled) {
const parentSegmentIgnored = parentContext?.traceState?.get(SENTRY_TRACE_STATE_SEGMENT_IGNORED) === "1";
this._client.recordDroppedEvent(parentSegmentIgnored ? "ignored" : "sample_rate", "span");
}
}
return wrapSamplingDecision({
decision: parentSampled ? SamplingDecision.RECORD_AND_SAMPLED : SamplingDecision.NOT_RECORD,
context,
spanAttributes
});
}
const {
description: inferredSpanName,
data: inferredAttributes,
op
} = inferSpanData(spanName, spanAttributes, spanKind);
const mergedAttributes = {
...inferredAttributes,
...spanAttributes
};
if (op) {
mergedAttributes[SEMANTIC_ATTRIBUTE_SENTRY_OP] = op;
}
if (this._isSpanStreaming && ignoreSpans?.length && shouldIgnoreSpan(
{
description: inferredSpanName,
op: mergedAttributes[SEMANTIC_ATTRIBUTE_SENTRY_OP] ?? op,
attributes: mergedAttributes
},
ignoreSpans
)) {
this._client.recordDroppedEvent("ignored", "span");
return wrapSamplingDecision({
decision: SamplingDecision.NOT_RECORD,
context,
spanAttributes,
ignoredSegmentSpan: true
});
}
const mutableSamplingDecision = { decision: true };
this._client.emit(
"beforeSampling",
{
spanAttributes: mergedAttributes,
spanName: inferredSpanName,
parentSampled,
parentContext
},
mutableSamplingDecision
);
if (!mutableSamplingDecision.decision) {
return wrapSamplingDecision({ decision: void 0, context, spanAttributes });
}
const { isolationScope } = getScopesFromContext(context) ?? {};
const dscString = parentContext?.traceState ? parentContext.traceState.get(SENTRY_TRACE_STATE_DSC) : void 0;
const dsc = dscString ? baggageHeaderToDynamicSamplingContext(dscString) : void 0;
const sampleRand = parseSampleRate(dsc?.sample_rand) ?? _INTERNAL_safeMathRandom();
const [sampled, sampleRate, localSampleRateWasApplied] = sampleSpan(
options,
{
name: inferredSpanName,
attributes: mergedAttributes,
normalizedRequest: isolationScope?.getScopeData().sdkProcessingMetadata.normalizedRequest,
parentSampled,
parentSampleRate: parseSampleRate(dsc?.sample_rate)
},
sampleRand
);
const method = `${maybeSpanHttpMethod}`.toUpperCase();
if (method === "OPTIONS" || method === "HEAD") {
DEBUG_BUILD && debug.log(`[Tracing] Not sampling span because HTTP method is '${method}' for ${spanName}`);
return wrapSamplingDecision({
decision: SamplingDecision.NOT_RECORD,
context,
spanAttributes,
sampleRand,
downstreamTraceSampleRate: 0
// we don't want to sample anything in the downstream trace either
});
}
if (!sampled && // We check for `parentSampled === undefined` because we only want to record client reports for spans that are trace roots (ie. when there was incoming trace)
parentSampled === void 0) {
DEBUG_BUILD && debug.log("[Tracing] Discarding root span because its trace was not chosen to be sampled.");
this._client.recordDroppedEvent("sample_rate", this._isSpanStreaming ? "span" : "transaction");
}
return {
...wrapSamplingDecision({
decision: sampled ? SamplingDecision.RECORD_AND_SAMPLED : SamplingDecision.NOT_RECORD,
context,
spanAttributes,
sampleRand,
downstreamTraceSampleRate: localSampleRateWasApplied ? sampleRate : void 0
}),
attributes: {
// We set the sample rate on the span when a local sample rate was applied to better understand how traces were sampled in Sentry
[SEMANTIC_ATTRIBUTE_SENTRY_SAMPLE_RATE]: localSampleRateWasApplied ? sampleRate : void 0
}
};
}
/** Returns the sampler name or short description with the configuration. */
toString() {
return "SentrySampler";
}
}
function getParentSampled(parentSpan, traceId, spanName) {
const parentContext = parentSpan.spanContext();
if (isSpanContextValid(parentContext) && parentContext.traceId === traceId) {
if (parentContext.isRemote) {
const parentSampled2 = getSamplingDecision(parentSpan.spanContext());
DEBUG_BUILD && debug.log(`[Tracing] Inheriting remote parent's sampled decision for ${spanName}: ${parentSampled2}`);
return parentSampled2;
}
const parentSampled = getSamplingDecision(parentContext);
DEBUG_BUILD && debug.log(`[Tracing] Inheriting parent's sampled decision for ${spanName}: ${parentSampled}`);
return parentSampled;
}
return void 0;
}
function wrapSamplingDecision({
decision,
context,
spanAttributes,
sampleRand,
downstreamTraceSampleRate,
ignoredChildSpan,
ignoredSegmentSpan
}) {
let traceState = getBaseTraceState(context, spanAttributes);
if (downstreamTraceSampleRate !== void 0) {
traceState = traceState.set(SENTRY_TRACE_STATE_SAMPLE_RATE, `${downstreamTraceSampleRate}`);
}
if (sampleRand !== void 0) {
traceState = traceState.set(SENTRY_TRACE_STATE_SAMPLE_RAND, `${sampleRand}`);
}
if (ignoredChildSpan) {
traceState = traceState.set(SENTRY_TRACE_STATE_CHILD_IGNORED, "1");
}
if (ignoredSegmentSpan) {
traceState = traceState.set(SENTRY_TRACE_STATE_SEGMENT_IGNORED, "1");
}
if (decision == void 0) {
return { decision: SamplingDecision.NOT_RECORD, traceState };
}
if (decision === SamplingDecision.NOT_RECORD) {
return { decision, traceState: traceState.set(SENTRY_TRACE_STATE_SAMPLED_NOT_RECORDING, "1") };
}
return { decision, traceState };
}
function getBaseTraceState(context, spanAttributes) {
const parentSpan = trace.getSpan(context);
const parentContext = parentSpan?.spanContext();
let traceState = parentContext?.traceState || new TraceState();
const url = spanAttributes[HTTP_URL] || spanAttributes[URL_FULL];
if (url && typeof url === "string") {
traceState = traceState.set(SENTRY_TRACE_STATE_URL, url);
}
return traceState;
}
function getValidSpan(context) {
const span = trace.getSpan(context);
return span && isSpanContextValid(span.spanContext()) ? span : void 0;
}
const ATTR_TELEMETRY_SDK_LANGUAGE = "telemetry.sdk.language";
const ATTR_TELEMETRY_SDK_NAME = "telemetry.sdk.name";
const ATTR_TELEMETRY_SDK_VERSION = "telemetry.sdk.version";
const SEMRESATTRS_SERVICE_NAMESPACE = "service.namespace";
class SentryResource {
constructor(attributes) {
this._attributes = attributes;
}
get attributes() {
return this._attributes;
}
merge(other) {
if (!other) {
return this;
}
return new SentryResource({ ...this._attributes, ...other.attributes });
}
getRawAttributes() {
return Object.entries(this._attributes);
}
}
function parseOtelResourceAttributes(raw) {
if (!raw) {
return {};
}
const result = {};
for (const pair of raw.split(",")) {
const eq = pair.indexOf("=");
if (eq === -1) {
continue;
}
const key = pair.substring(0, eq).trim();
const value = pair.substring(eq + 1).trim();
if (key) {
try {
result[key] = decodeURIComponent(value);
} catch {
result[key] = value;
}
}
}
return result;
}
function getSentryResource(serviceNameFallback) {
const env = typeof process !== "undefined" ? process.env : {};
const otelServiceName = env.OTEL_SERVICE_NAME;
const otelResourceAttrs = parseOtelResourceAttributes(env.OTEL_RESOURCE_ATTRIBUTES);
return new SentryResource({
// Lowest priority: Sentry defaults
// eslint-disable-next-line typescript/no-deprecated
[SEMRESATTRS_SERVICE_NAMESPACE]: "sentry",
[SERVICE_NAME]: serviceNameFallback,
// OTEL_RESOURCE_ATTRIBUTES overrides defaults (including service.name and service.namespace)
...otelResourceAttrs,
// OTEL_SERVICE_NAME explicitly overrides service.name
...otelServiceName ? { [SERVICE_NAME]: otelServiceName } : {},
// Highest priority: Sentry SDK telemetry attrs (cannot be overridden by env vars)
[SERVICE_VERSION]: SDK_VERSION,
[ATTR_TELEMETRY_SDK_LANGUAGE]: SDK_INFO[ATTR_TELEMETRY_SDK_LANGUAGE],
[ATTR_TELEMETRY_SDK_NAME]: SDK_INFO[ATTR_TELEMETRY_SDK_NAME],
[ATTR_TELEMETRY_SDK_VERSION]: SDK_INFO[ATTR_TELEMETRY_SDK_VERSION]
});
}
export { startSpanManual as A, suppressTracing as B, withActiveSpan as C, wrapClientClass as D, wrapContextManagerClass as E, wrapSamplingDecision as F, SEMANTIC_ATTRIBUTE_SENTRY_GRAPHQL_OPERATION as S, SENTRY_SCOPES_CONTEXT_KEY as a, SentryPropagator as b, SentrySampler as c, SentrySpanProcessor as d, buildContextWithSentryScopes as e, continueTrace as f, enhanceDscWithOpenTelemetryRootSpanName as g, getActiveSpan as h, getRequestSpanData as i, getScopesFromContext as j, getSentryResource as k, getSpanKind as l, getTraceContextForScope as m, isSentryRequestSpan as n, openTelemetrySetupCheck as o, setOpenTelemetryContextAsyncContextStrategy as p, setupEventContextTrace as q, spanHasAttributes as r, setIsSetup as s, spanHasEvents as t, spanHasKind as u, spanHasName as v, spanHasParentId as w, spanHasStatus as x, startInactiveSpan as y, startSpan as z };
//# sourceMappingURL=resource-CB9ITx8O.js.map

Sorry, the diff of this file is too big to display

+1
-2
Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
const core = require('@sentry/core');
const resource = require('./resource-DEULI4zI.js');
const resource = require('./resource-PpJQa_6P.js');
require('@opentelemetry/api');
require('@sentry/conventions/attributes');
require('@opentelemetry/core');
require('./debug-build-CQngOfDt.js');
require('@opentelemetry/sdk-trace-base');

@@ -10,0 +9,0 @@

@@ -1,1 +0,1 @@

{"version":3,"file":"index.browser.js","sources":["../../src/index.browser.ts"],"sourcesContent":["import { consoleSandbox } from '@sentry/core';\n\nexport * from './exports';\n\n// Stubs for node-specific exports\nexport class SentryAsyncLocalStorageContextManager {\n public constructor() {\n consoleSandbox(() => {\n // oxlint-disable-next-line no-console\n console.error('SentryAsyncLocalStorageContextManager is not supported in the browser');\n });\n }\n}\n\nexport type AsyncLocalStorageLookup = {\n asyncLocalStorage: unknown;\n contextSymbol: symbol;\n};\n"],"names":["consoleSandbox"],"mappings":";;;;;;;;;;AAKO,MAAM,qCAAA,CAAsC;AAAA,EAC1C,WAAA,GAAc;AACnB,IAAAA,mBAAA,CAAe,MAAM;AAEnB,MAAA,OAAA,CAAQ,MAAM,uEAAuE,CAAA;AAAA,IACvF,CAAC,CAAA;AAAA,EACH;AACF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
{"version":3,"file":"index.browser.js","sources":["../../src/index.browser.ts"],"sourcesContent":["import { consoleSandbox } from '@sentry/core';\n\nexport * from './exports';\n\n// Stubs for node-specific exports\nexport class SentryAsyncLocalStorageContextManager {\n public constructor() {\n consoleSandbox(() => {\n // oxlint-disable-next-line no-console\n console.error('SentryAsyncLocalStorageContextManager is not supported in the browser');\n });\n }\n}\n\nexport type AsyncLocalStorageLookup = {\n asyncLocalStorage: unknown;\n contextSymbol: symbol;\n};\n"],"names":["consoleSandbox"],"mappings":";;;;;;;;;AAKO,MAAM,qCAAA,CAAsC;AAAA,EAC1C,WAAA,GAAc;AACnB,IAAAA,mBAAA,CAAe,MAAM;AAEnB,MAAA,OAAA,CAAQ,MAAM,uEAAuE,CAAA;AAAA,IACvF,CAAC,CAAA;AAAA,EACH;AACF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
const resource = require('./resource-DEULI4zI.js');
const resource = require('./resource-PpJQa_6P.js');
const core = require('@sentry/core');

@@ -10,3 +10,2 @@ const api = require('@opentelemetry/api');

require('@opentelemetry/core');
require('./debug-build-CQngOfDt.js');
require('@opentelemetry/sdk-trace-base');

@@ -13,0 +12,0 @@

@@ -1,1 +0,1 @@

{"version":3,"file":"index.js","sources":["../../src/asyncLocalStorageContextManager.ts"],"sourcesContent":["/*\n * Copyright The OpenTelemetry Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * NOTICE from the Sentry authors:\n * This implementation follows the behavior of OpenTelemetry’s `@opentelemetry/context-async-hooks`\n * package, combining logic that upstream splits across:\n * - https://github.com/open-telemetry/opentelemetry-js/blob/main/packages/opentelemetry-context-async-hooks/src/AbstractAsyncHooksContextManager.ts\n * - https://github.com/open-telemetry/opentelemetry-js/blob/main/packages/opentelemetry-context-async-hooks/src/AsyncLocalStorageContextManager.ts\n * It is a single-class re-implementation for Sentry (not a verbatim copy of those files).\n */\n\nimport type { Context, ContextManager } from '@opentelemetry/api';\nimport { ROOT_CONTEXT } from '@opentelemetry/api';\nimport { AsyncLocalStorage } from 'node:async_hooks';\nimport { EventEmitter } from 'node:events';\nimport { SENTRY_SCOPES_CONTEXT_KEY } from './constants';\nimport type { AsyncLocalStorageLookup } from './contextManager';\nimport { buildContextWithSentryScopes } from './utils/buildContextWithSentryScopes';\nimport { setIsSetup } from './utils/setupCheck';\n\ntype ListenerFn = (...args: unknown[]) => unknown;\n\n/**\n * Per-event map from user listeners to context-bound listeners.\n */\ntype PatchMap = Record<string, WeakMap<ListenerFn, ListenerFn>>;\n\nconst ADD_LISTENER_METHODS = ['addListener', 'on', 'once', 'prependListener', 'prependOnceListener'] as const;\n\n/**\n * OpenTelemetry-compatible context manager using Node.js `AsyncLocalStorage`.\n * Semantics match `@opentelemetry/context-async-hooks` (function `bind` + `EventEmitter` patching).\n */\nexport class SentryAsyncLocalStorageContextManager implements ContextManager {\n protected readonly _asyncLocalStorage = new AsyncLocalStorage<Context>();\n\n private readonly _kOtListeners = Symbol('OtListeners');\n private _wrapped = false;\n\n public constructor() {\n setIsSetup('SentryContextManager');\n }\n\n public active(): Context {\n return this._asyncLocalStorage.getStore() ?? ROOT_CONTEXT;\n }\n\n public with<A extends unknown[], F extends (...args: A) => ReturnType<F>>(\n context: Context,\n fn: F,\n thisArg?: ThisParameterType<F>,\n ...args: A\n ): ReturnType<F> {\n const ctx2 = buildContextWithSentryScopes(context, this.active());\n const cb = thisArg == null ? fn : fn.bind(thisArg);\n return this._asyncLocalStorage.run(ctx2, cb as never, ...args);\n }\n\n public enable(): this {\n return this;\n }\n\n public disable(): this {\n this._asyncLocalStorage.disable();\n return this;\n }\n\n public bind<T>(context: Context, target: T): T {\n if (target instanceof EventEmitter) {\n return this._bindEventEmitter(context, target);\n }\n if (typeof target === 'function') {\n return this._bindFunction(context, target as unknown as ListenerFn) as T;\n }\n return target;\n }\n\n /**\n * Gets underlying AsyncLocalStorage and symbol to allow lookup of scope.\n * This is Sentry-specific.\n */\n public getAsyncLocalStorageLookup(): AsyncLocalStorageLookup {\n return {\n asyncLocalStorage: this._asyncLocalStorage,\n contextSymbol: SENTRY_SCOPES_CONTEXT_KEY,\n };\n }\n\n private _bindFunction(context: Context, target: ListenerFn): ListenerFn {\n const managerWith = this.with.bind(this);\n const contextWrapper = function (this: never, ...args: unknown[]) {\n return managerWith(context, () => target.apply(this, args));\n };\n Object.defineProperty(contextWrapper, 'length', {\n enumerable: false,\n configurable: true,\n writable: false,\n value: target.length,\n });\n return contextWrapper;\n }\n\n private _bindEventEmitter<T extends EventEmitter>(context: Context, ee: T): T {\n if (this._getPatchMap(ee) !== undefined) {\n return ee;\n }\n this._createPatchMap(ee);\n\n for (const methodName of ADD_LISTENER_METHODS) {\n if (ee[methodName] === undefined) continue;\n ee[methodName] = this._patchAddListener(\n ee,\n ee[methodName] as unknown as (...args: unknown[]) => unknown,\n context,\n );\n }\n if (typeof ee.removeListener === 'function') {\n // oxlint-disable-next-line @typescript-eslint/unbound-method -- patched like upstream OTel context manager\n ee.removeListener = this._patchRemoveListener(ee, ee.removeListener as (...args: unknown[]) => unknown);\n }\n if (typeof ee.off === 'function') {\n // oxlint-disable-next-line @typescript-eslint/unbound-method\n ee.off = this._patchRemoveListener(ee, ee.off as (...args: unknown[]) => unknown);\n }\n if (typeof ee.removeAllListeners === 'function') {\n ee.removeAllListeners = this._patchRemoveAllListeners(\n ee,\n // oxlint-disable-next-line @typescript-eslint/unbound-method\n ee.removeAllListeners as (...args: unknown[]) => unknown,\n );\n }\n return ee;\n }\n\n private _patchRemoveListener(ee: EventEmitter, original: (...args: unknown[]) => unknown) {\n // oxlint-disable-next-line @typescript-eslint/no-this-alias\n const contextManager = this;\n return function (this: unknown, event: string, listener: ListenerFn) {\n const events = contextManager._getPatchMap(ee)?.[event];\n if (events === undefined) {\n return original.call(this, event, listener);\n }\n const patchedListener = events.get(listener);\n return original.call(this, event, patchedListener || listener);\n };\n }\n\n private _patchRemoveAllListeners(ee: EventEmitter, original: (...args: unknown[]) => unknown) {\n // oxlint-disable-next-line @typescript-eslint/no-this-alias\n const contextManager = this;\n return function (this: unknown, event?: string) {\n const map = contextManager._getPatchMap(ee);\n if (map !== undefined) {\n if (arguments.length === 0) {\n contextManager._createPatchMap(ee);\n } else if (event !== undefined && map[event] !== undefined) {\n // oxlint-disable-next-line @typescript-eslint/no-dynamic-delete -- event-keyed listener map\n delete map[event];\n }\n }\n return original.apply(this, arguments);\n };\n }\n\n private _patchAddListener(ee: EventEmitter, original: (...args: unknown[]) => unknown, context: Context) {\n // oxlint-disable-next-line @typescript-eslint/no-this-alias\n const contextManager = this;\n return function (this: unknown, event: string, listener: ListenerFn) {\n if (contextManager._wrapped) {\n return original.call(this, event, listener);\n }\n let map = contextManager._getPatchMap(ee);\n if (map === undefined) {\n map = contextManager._createPatchMap(ee);\n }\n let listeners = map[event];\n if (listeners === undefined) {\n listeners = new WeakMap();\n map[event] = listeners;\n }\n const patchedListener = contextManager.bind(context, listener);\n listeners.set(listener, patchedListener);\n\n contextManager._wrapped = true;\n try {\n return original.call(this, event, patchedListener);\n } finally {\n contextManager._wrapped = false;\n }\n };\n }\n\n private _createPatchMap(ee: EventEmitter): PatchMap {\n const map = Object.create(null) as PatchMap;\n (ee as unknown as Record<symbol, PatchMap>)[this._kOtListeners] = map;\n return map;\n }\n\n private _getPatchMap(ee: EventEmitter): PatchMap | undefined {\n return (ee as unknown as Record<symbol, PatchMap | undefined>)[this._kOtListeners];\n }\n}\n"],"names":["AsyncLocalStorage","setIsSetup","ROOT_CONTEXT","buildContextWithSentryScopes","EventEmitter","SENTRY_SCOPES_CONTEXT_KEY"],"mappings":"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"}
{"version":3,"file":"index.js","sources":["../../src/asyncLocalStorageContextManager.ts"],"sourcesContent":["/*\n * Copyright The OpenTelemetry Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * NOTICE from the Sentry authors:\n * This implementation follows the behavior of OpenTelemetry’s `@opentelemetry/context-async-hooks`\n * package, combining logic that upstream splits across:\n * - https://github.com/open-telemetry/opentelemetry-js/blob/main/packages/opentelemetry-context-async-hooks/src/AbstractAsyncHooksContextManager.ts\n * - https://github.com/open-telemetry/opentelemetry-js/blob/main/packages/opentelemetry-context-async-hooks/src/AsyncLocalStorageContextManager.ts\n * It is a single-class re-implementation for Sentry (not a verbatim copy of those files).\n */\n\nimport type { Context, ContextManager } from '@opentelemetry/api';\nimport { ROOT_CONTEXT } from '@opentelemetry/api';\nimport { AsyncLocalStorage } from 'node:async_hooks';\nimport { EventEmitter } from 'node:events';\nimport { SENTRY_SCOPES_CONTEXT_KEY } from './constants';\nimport type { AsyncLocalStorageLookup } from './contextManager';\nimport { buildContextWithSentryScopes } from './utils/buildContextWithSentryScopes';\nimport { setIsSetup } from './utils/setupCheck';\n\ntype ListenerFn = (...args: unknown[]) => unknown;\n\n/**\n * Per-event map from user listeners to context-bound listeners.\n */\ntype PatchMap = Record<string, WeakMap<ListenerFn, ListenerFn>>;\n\nconst ADD_LISTENER_METHODS = ['addListener', 'on', 'once', 'prependListener', 'prependOnceListener'] as const;\n\n/**\n * OpenTelemetry-compatible context manager using Node.js `AsyncLocalStorage`.\n * Semantics match `@opentelemetry/context-async-hooks` (function `bind` + `EventEmitter` patching).\n */\nexport class SentryAsyncLocalStorageContextManager implements ContextManager {\n protected readonly _asyncLocalStorage = new AsyncLocalStorage<Context>();\n\n private readonly _kOtListeners = Symbol('OtListeners');\n private _wrapped = false;\n\n public constructor() {\n setIsSetup('SentryContextManager');\n }\n\n public active(): Context {\n return this._asyncLocalStorage.getStore() ?? ROOT_CONTEXT;\n }\n\n public with<A extends unknown[], F extends (...args: A) => ReturnType<F>>(\n context: Context,\n fn: F,\n thisArg?: ThisParameterType<F>,\n ...args: A\n ): ReturnType<F> {\n const ctx2 = buildContextWithSentryScopes(context, this.active());\n const cb = thisArg == null ? fn : fn.bind(thisArg);\n return this._asyncLocalStorage.run(ctx2, cb as never, ...args);\n }\n\n public enable(): this {\n return this;\n }\n\n public disable(): this {\n this._asyncLocalStorage.disable();\n return this;\n }\n\n public bind<T>(context: Context, target: T): T {\n if (target instanceof EventEmitter) {\n return this._bindEventEmitter(context, target);\n }\n if (typeof target === 'function') {\n return this._bindFunction(context, target as unknown as ListenerFn) as T;\n }\n return target;\n }\n\n /**\n * Gets underlying AsyncLocalStorage and symbol to allow lookup of scope.\n * This is Sentry-specific.\n */\n public getAsyncLocalStorageLookup(): AsyncLocalStorageLookup {\n return {\n asyncLocalStorage: this._asyncLocalStorage,\n contextSymbol: SENTRY_SCOPES_CONTEXT_KEY,\n };\n }\n\n private _bindFunction(context: Context, target: ListenerFn): ListenerFn {\n const managerWith = this.with.bind(this);\n const contextWrapper = function (this: never, ...args: unknown[]) {\n return managerWith(context, () => target.apply(this, args));\n };\n Object.defineProperty(contextWrapper, 'length', {\n enumerable: false,\n configurable: true,\n writable: false,\n value: target.length,\n });\n return contextWrapper;\n }\n\n private _bindEventEmitter<T extends EventEmitter>(context: Context, ee: T): T {\n if (this._getPatchMap(ee) !== undefined) {\n return ee;\n }\n this._createPatchMap(ee);\n\n for (const methodName of ADD_LISTENER_METHODS) {\n if (ee[methodName] === undefined) continue;\n ee[methodName] = this._patchAddListener(\n ee,\n ee[methodName] as unknown as (...args: unknown[]) => unknown,\n context,\n );\n }\n if (typeof ee.removeListener === 'function') {\n // oxlint-disable-next-line @typescript-eslint/unbound-method -- patched like upstream OTel context manager\n ee.removeListener = this._patchRemoveListener(ee, ee.removeListener as (...args: unknown[]) => unknown);\n }\n if (typeof ee.off === 'function') {\n // oxlint-disable-next-line @typescript-eslint/unbound-method\n ee.off = this._patchRemoveListener(ee, ee.off as (...args: unknown[]) => unknown);\n }\n if (typeof ee.removeAllListeners === 'function') {\n ee.removeAllListeners = this._patchRemoveAllListeners(\n ee,\n // oxlint-disable-next-line @typescript-eslint/unbound-method\n ee.removeAllListeners as (...args: unknown[]) => unknown,\n );\n }\n return ee;\n }\n\n private _patchRemoveListener(ee: EventEmitter, original: (...args: unknown[]) => unknown) {\n // oxlint-disable-next-line @typescript-eslint/no-this-alias\n const contextManager = this;\n return function (this: unknown, event: string, listener: ListenerFn) {\n const events = contextManager._getPatchMap(ee)?.[event];\n if (events === undefined) {\n return original.call(this, event, listener);\n }\n const patchedListener = events.get(listener);\n return original.call(this, event, patchedListener || listener);\n };\n }\n\n private _patchRemoveAllListeners(ee: EventEmitter, original: (...args: unknown[]) => unknown) {\n // oxlint-disable-next-line @typescript-eslint/no-this-alias\n const contextManager = this;\n return function (this: unknown, event?: string) {\n const map = contextManager._getPatchMap(ee);\n if (map !== undefined) {\n if (arguments.length === 0) {\n contextManager._createPatchMap(ee);\n } else if (event !== undefined && map[event] !== undefined) {\n // oxlint-disable-next-line @typescript-eslint/no-dynamic-delete -- event-keyed listener map\n delete map[event];\n }\n }\n return original.apply(this, arguments);\n };\n }\n\n private _patchAddListener(ee: EventEmitter, original: (...args: unknown[]) => unknown, context: Context) {\n // oxlint-disable-next-line @typescript-eslint/no-this-alias\n const contextManager = this;\n return function (this: unknown, event: string, listener: ListenerFn) {\n if (contextManager._wrapped) {\n return original.call(this, event, listener);\n }\n let map = contextManager._getPatchMap(ee);\n if (map === undefined) {\n map = contextManager._createPatchMap(ee);\n }\n let listeners = map[event];\n if (listeners === undefined) {\n listeners = new WeakMap();\n map[event] = listeners;\n }\n const patchedListener = contextManager.bind(context, listener);\n listeners.set(listener, patchedListener);\n\n contextManager._wrapped = true;\n try {\n return original.call(this, event, patchedListener);\n } finally {\n contextManager._wrapped = false;\n }\n };\n }\n\n private _createPatchMap(ee: EventEmitter): PatchMap {\n const map = Object.create(null) as PatchMap;\n (ee as unknown as Record<symbol, PatchMap>)[this._kOtListeners] = map;\n return map;\n }\n\n private _getPatchMap(ee: EventEmitter): PatchMap | undefined {\n return (ee as unknown as Record<symbol, PatchMap | undefined>)[this._kOtListeners];\n }\n}\n"],"names":["AsyncLocalStorage","setIsSetup","ROOT_CONTEXT","buildContextWithSentryScopes","EventEmitter","SENTRY_SCOPES_CONTEXT_KEY"],"mappings":"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"}
import { consoleSandbox } from '@sentry/core';
export { getClient, getDynamicSamplingContextFromSpan, shouldPropagateTraceForUrl, withStreamedSpan } from '@sentry/core';
export { S as SEMANTIC_ATTRIBUTE_SENTRY_GRAPHQL_OPERATION, b as SentryPropagator, c as SentrySampler, d as SentrySpanProcessor, f as continueTrace, g as enhanceDscWithOpenTelemetryRootSpanName, h as getActiveSpan, i as getRequestSpanData, j as getScopesFromContext, k as getSentryResource, l as getSpanKind, m as getTraceContextForScope, n as isSentryRequestSpan, o as openTelemetrySetupCheck, p as setOpenTelemetryContextAsyncContextStrategy, q as setupEventContextTrace, r as spanHasAttributes, t as spanHasEvents, u as spanHasKind, v as spanHasName, w as spanHasParentId, x as spanHasStatus, y as startInactiveSpan, z as startSpan, A as startSpanManual, B as suppressTracing, C as withActiveSpan, D as wrapClientClass, E as wrapContextManagerClass, F as wrapSamplingDecision } from './resource-PMlHXvcP.js';
export { S as SEMANTIC_ATTRIBUTE_SENTRY_GRAPHQL_OPERATION, b as SentryPropagator, c as SentrySampler, d as SentrySpanProcessor, f as continueTrace, g as enhanceDscWithOpenTelemetryRootSpanName, h as getActiveSpan, i as getRequestSpanData, j as getScopesFromContext, k as getSentryResource, l as getSpanKind, m as getTraceContextForScope, n as isSentryRequestSpan, o as openTelemetrySetupCheck, p as setOpenTelemetryContextAsyncContextStrategy, q as setupEventContextTrace, r as spanHasAttributes, t as spanHasEvents, u as spanHasKind, v as spanHasName, w as spanHasParentId, x as spanHasStatus, y as startInactiveSpan, z as startSpan, A as startSpanManual, B as suppressTracing, C as withActiveSpan, D as wrapClientClass, E as wrapContextManagerClass, F as wrapSamplingDecision } from './resource-CB9ITx8O.js';
import '@opentelemetry/api';
import '@sentry/conventions/attributes';
import '@opentelemetry/core';
import './debug-build-B98wrZ1j.js';
import '@opentelemetry/sdk-trace-base';

@@ -9,0 +8,0 @@

@@ -1,1 +0,1 @@

{"version":3,"file":"index.browser.js","sources":["../../src/index.browser.ts"],"sourcesContent":["import { consoleSandbox } from '@sentry/core';\n\nexport * from './exports';\n\n// Stubs for node-specific exports\nexport class SentryAsyncLocalStorageContextManager {\n public constructor() {\n consoleSandbox(() => {\n // oxlint-disable-next-line no-console\n console.error('SentryAsyncLocalStorageContextManager is not supported in the browser');\n });\n }\n}\n\nexport type AsyncLocalStorageLookup = {\n asyncLocalStorage: unknown;\n contextSymbol: symbol;\n};\n"],"names":[],"mappings":";;;;;;;;;AAKO,MAAM,qCAAA,CAAsC;AAAA,EAC1C,WAAA,GAAc;AACnB,IAAA,cAAA,CAAe,MAAM;AAEnB,MAAA,OAAA,CAAQ,MAAM,uEAAuE,CAAA;AAAA,IACvF,CAAC,CAAA;AAAA,EACH;AACF;;;;"}
{"version":3,"file":"index.browser.js","sources":["../../src/index.browser.ts"],"sourcesContent":["import { consoleSandbox } from '@sentry/core';\n\nexport * from './exports';\n\n// Stubs for node-specific exports\nexport class SentryAsyncLocalStorageContextManager {\n public constructor() {\n consoleSandbox(() => {\n // oxlint-disable-next-line no-console\n console.error('SentryAsyncLocalStorageContextManager is not supported in the browser');\n });\n }\n}\n\nexport type AsyncLocalStorageLookup = {\n asyncLocalStorage: unknown;\n contextSymbol: symbol;\n};\n"],"names":[],"mappings":";;;;;;;;AAKO,MAAM,qCAAA,CAAsC;AAAA,EAC1C,WAAA,GAAc;AACnB,IAAA,cAAA,CAAe,MAAM;AAEnB,MAAA,OAAA,CAAQ,MAAM,uEAAuE,CAAA;AAAA,IACvF,CAAC,CAAA;AAAA,EACH;AACF;;;;"}

@@ -1,3 +0,3 @@

import { s as setIsSetup, e as buildContextWithSentryScopes, a as SENTRY_SCOPES_CONTEXT_KEY } from './resource-PMlHXvcP.js';
export { S as SEMANTIC_ATTRIBUTE_SENTRY_GRAPHQL_OPERATION, b as SentryPropagator, c as SentrySampler, d as SentrySpanProcessor, f as continueTrace, g as enhanceDscWithOpenTelemetryRootSpanName, h as getActiveSpan, i as getRequestSpanData, j as getScopesFromContext, k as getSentryResource, l as getSpanKind, m as getTraceContextForScope, n as isSentryRequestSpan, o as openTelemetrySetupCheck, p as setOpenTelemetryContextAsyncContextStrategy, q as setupEventContextTrace, r as spanHasAttributes, t as spanHasEvents, u as spanHasKind, v as spanHasName, w as spanHasParentId, x as spanHasStatus, y as startInactiveSpan, z as startSpan, A as startSpanManual, B as suppressTracing, C as withActiveSpan, D as wrapClientClass, E as wrapContextManagerClass, F as wrapSamplingDecision } from './resource-PMlHXvcP.js';
import { s as setIsSetup, e as buildContextWithSentryScopes, a as SENTRY_SCOPES_CONTEXT_KEY } from './resource-CB9ITx8O.js';
export { S as SEMANTIC_ATTRIBUTE_SENTRY_GRAPHQL_OPERATION, b as SentryPropagator, c as SentrySampler, d as SentrySpanProcessor, f as continueTrace, g as enhanceDscWithOpenTelemetryRootSpanName, h as getActiveSpan, i as getRequestSpanData, j as getScopesFromContext, k as getSentryResource, l as getSpanKind, m as getTraceContextForScope, n as isSentryRequestSpan, o as openTelemetrySetupCheck, p as setOpenTelemetryContextAsyncContextStrategy, q as setupEventContextTrace, r as spanHasAttributes, t as spanHasEvents, u as spanHasKind, v as spanHasName, w as spanHasParentId, x as spanHasStatus, y as startInactiveSpan, z as startSpan, A as startSpanManual, B as suppressTracing, C as withActiveSpan, D as wrapClientClass, E as wrapContextManagerClass, F as wrapSamplingDecision } from './resource-CB9ITx8O.js';
export { getClient, getDynamicSamplingContextFromSpan, shouldPropagateTraceForUrl, withStreamedSpan } from '@sentry/core';

@@ -9,3 +9,2 @@ import { ROOT_CONTEXT } from '@opentelemetry/api';

import '@opentelemetry/core';
import './debug-build-B98wrZ1j.js';
import '@opentelemetry/sdk-trace-base';

@@ -12,0 +11,0 @@

@@ -1,1 +0,1 @@

{"version":3,"file":"index.js","sources":["../../src/asyncLocalStorageContextManager.ts"],"sourcesContent":["/*\n * Copyright The OpenTelemetry Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * NOTICE from the Sentry authors:\n * This implementation follows the behavior of OpenTelemetry’s `@opentelemetry/context-async-hooks`\n * package, combining logic that upstream splits across:\n * - https://github.com/open-telemetry/opentelemetry-js/blob/main/packages/opentelemetry-context-async-hooks/src/AbstractAsyncHooksContextManager.ts\n * - https://github.com/open-telemetry/opentelemetry-js/blob/main/packages/opentelemetry-context-async-hooks/src/AsyncLocalStorageContextManager.ts\n * It is a single-class re-implementation for Sentry (not a verbatim copy of those files).\n */\n\nimport type { Context, ContextManager } from '@opentelemetry/api';\nimport { ROOT_CONTEXT } from '@opentelemetry/api';\nimport { AsyncLocalStorage } from 'node:async_hooks';\nimport { EventEmitter } from 'node:events';\nimport { SENTRY_SCOPES_CONTEXT_KEY } from './constants';\nimport type { AsyncLocalStorageLookup } from './contextManager';\nimport { buildContextWithSentryScopes } from './utils/buildContextWithSentryScopes';\nimport { setIsSetup } from './utils/setupCheck';\n\ntype ListenerFn = (...args: unknown[]) => unknown;\n\n/**\n * Per-event map from user listeners to context-bound listeners.\n */\ntype PatchMap = Record<string, WeakMap<ListenerFn, ListenerFn>>;\n\nconst ADD_LISTENER_METHODS = ['addListener', 'on', 'once', 'prependListener', 'prependOnceListener'] as const;\n\n/**\n * OpenTelemetry-compatible context manager using Node.js `AsyncLocalStorage`.\n * Semantics match `@opentelemetry/context-async-hooks` (function `bind` + `EventEmitter` patching).\n */\nexport class SentryAsyncLocalStorageContextManager implements ContextManager {\n protected readonly _asyncLocalStorage = new AsyncLocalStorage<Context>();\n\n private readonly _kOtListeners = Symbol('OtListeners');\n private _wrapped = false;\n\n public constructor() {\n setIsSetup('SentryContextManager');\n }\n\n public active(): Context {\n return this._asyncLocalStorage.getStore() ?? ROOT_CONTEXT;\n }\n\n public with<A extends unknown[], F extends (...args: A) => ReturnType<F>>(\n context: Context,\n fn: F,\n thisArg?: ThisParameterType<F>,\n ...args: A\n ): ReturnType<F> {\n const ctx2 = buildContextWithSentryScopes(context, this.active());\n const cb = thisArg == null ? fn : fn.bind(thisArg);\n return this._asyncLocalStorage.run(ctx2, cb as never, ...args);\n }\n\n public enable(): this {\n return this;\n }\n\n public disable(): this {\n this._asyncLocalStorage.disable();\n return this;\n }\n\n public bind<T>(context: Context, target: T): T {\n if (target instanceof EventEmitter) {\n return this._bindEventEmitter(context, target);\n }\n if (typeof target === 'function') {\n return this._bindFunction(context, target as unknown as ListenerFn) as T;\n }\n return target;\n }\n\n /**\n * Gets underlying AsyncLocalStorage and symbol to allow lookup of scope.\n * This is Sentry-specific.\n */\n public getAsyncLocalStorageLookup(): AsyncLocalStorageLookup {\n return {\n asyncLocalStorage: this._asyncLocalStorage,\n contextSymbol: SENTRY_SCOPES_CONTEXT_KEY,\n };\n }\n\n private _bindFunction(context: Context, target: ListenerFn): ListenerFn {\n const managerWith = this.with.bind(this);\n const contextWrapper = function (this: never, ...args: unknown[]) {\n return managerWith(context, () => target.apply(this, args));\n };\n Object.defineProperty(contextWrapper, 'length', {\n enumerable: false,\n configurable: true,\n writable: false,\n value: target.length,\n });\n return contextWrapper;\n }\n\n private _bindEventEmitter<T extends EventEmitter>(context: Context, ee: T): T {\n if (this._getPatchMap(ee) !== undefined) {\n return ee;\n }\n this._createPatchMap(ee);\n\n for (const methodName of ADD_LISTENER_METHODS) {\n if (ee[methodName] === undefined) continue;\n ee[methodName] = this._patchAddListener(\n ee,\n ee[methodName] as unknown as (...args: unknown[]) => unknown,\n context,\n );\n }\n if (typeof ee.removeListener === 'function') {\n // oxlint-disable-next-line @typescript-eslint/unbound-method -- patched like upstream OTel context manager\n ee.removeListener = this._patchRemoveListener(ee, ee.removeListener as (...args: unknown[]) => unknown);\n }\n if (typeof ee.off === 'function') {\n // oxlint-disable-next-line @typescript-eslint/unbound-method\n ee.off = this._patchRemoveListener(ee, ee.off as (...args: unknown[]) => unknown);\n }\n if (typeof ee.removeAllListeners === 'function') {\n ee.removeAllListeners = this._patchRemoveAllListeners(\n ee,\n // oxlint-disable-next-line @typescript-eslint/unbound-method\n ee.removeAllListeners as (...args: unknown[]) => unknown,\n );\n }\n return ee;\n }\n\n private _patchRemoveListener(ee: EventEmitter, original: (...args: unknown[]) => unknown) {\n // oxlint-disable-next-line @typescript-eslint/no-this-alias\n const contextManager = this;\n return function (this: unknown, event: string, listener: ListenerFn) {\n const events = contextManager._getPatchMap(ee)?.[event];\n if (events === undefined) {\n return original.call(this, event, listener);\n }\n const patchedListener = events.get(listener);\n return original.call(this, event, patchedListener || listener);\n };\n }\n\n private _patchRemoveAllListeners(ee: EventEmitter, original: (...args: unknown[]) => unknown) {\n // oxlint-disable-next-line @typescript-eslint/no-this-alias\n const contextManager = this;\n return function (this: unknown, event?: string) {\n const map = contextManager._getPatchMap(ee);\n if (map !== undefined) {\n if (arguments.length === 0) {\n contextManager._createPatchMap(ee);\n } else if (event !== undefined && map[event] !== undefined) {\n // oxlint-disable-next-line @typescript-eslint/no-dynamic-delete -- event-keyed listener map\n delete map[event];\n }\n }\n return original.apply(this, arguments);\n };\n }\n\n private _patchAddListener(ee: EventEmitter, original: (...args: unknown[]) => unknown, context: Context) {\n // oxlint-disable-next-line @typescript-eslint/no-this-alias\n const contextManager = this;\n return function (this: unknown, event: string, listener: ListenerFn) {\n if (contextManager._wrapped) {\n return original.call(this, event, listener);\n }\n let map = contextManager._getPatchMap(ee);\n if (map === undefined) {\n map = contextManager._createPatchMap(ee);\n }\n let listeners = map[event];\n if (listeners === undefined) {\n listeners = new WeakMap();\n map[event] = listeners;\n }\n const patchedListener = contextManager.bind(context, listener);\n listeners.set(listener, patchedListener);\n\n contextManager._wrapped = true;\n try {\n return original.call(this, event, patchedListener);\n } finally {\n contextManager._wrapped = false;\n }\n };\n }\n\n private _createPatchMap(ee: EventEmitter): PatchMap {\n const map = Object.create(null) as PatchMap;\n (ee as unknown as Record<symbol, PatchMap>)[this._kOtListeners] = map;\n return map;\n }\n\n private _getPatchMap(ee: EventEmitter): PatchMap | undefined {\n return (ee as unknown as Record<symbol, PatchMap | undefined>)[this._kOtListeners];\n }\n}\n"],"names":[],"mappings":"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"}
{"version":3,"file":"index.js","sources":["../../src/asyncLocalStorageContextManager.ts"],"sourcesContent":["/*\n * Copyright The OpenTelemetry Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * NOTICE from the Sentry authors:\n * This implementation follows the behavior of OpenTelemetry’s `@opentelemetry/context-async-hooks`\n * package, combining logic that upstream splits across:\n * - https://github.com/open-telemetry/opentelemetry-js/blob/main/packages/opentelemetry-context-async-hooks/src/AbstractAsyncHooksContextManager.ts\n * - https://github.com/open-telemetry/opentelemetry-js/blob/main/packages/opentelemetry-context-async-hooks/src/AsyncLocalStorageContextManager.ts\n * It is a single-class re-implementation for Sentry (not a verbatim copy of those files).\n */\n\nimport type { Context, ContextManager } from '@opentelemetry/api';\nimport { ROOT_CONTEXT } from '@opentelemetry/api';\nimport { AsyncLocalStorage } from 'node:async_hooks';\nimport { EventEmitter } from 'node:events';\nimport { SENTRY_SCOPES_CONTEXT_KEY } from './constants';\nimport type { AsyncLocalStorageLookup } from './contextManager';\nimport { buildContextWithSentryScopes } from './utils/buildContextWithSentryScopes';\nimport { setIsSetup } from './utils/setupCheck';\n\ntype ListenerFn = (...args: unknown[]) => unknown;\n\n/**\n * Per-event map from user listeners to context-bound listeners.\n */\ntype PatchMap = Record<string, WeakMap<ListenerFn, ListenerFn>>;\n\nconst ADD_LISTENER_METHODS = ['addListener', 'on', 'once', 'prependListener', 'prependOnceListener'] as const;\n\n/**\n * OpenTelemetry-compatible context manager using Node.js `AsyncLocalStorage`.\n * Semantics match `@opentelemetry/context-async-hooks` (function `bind` + `EventEmitter` patching).\n */\nexport class SentryAsyncLocalStorageContextManager implements ContextManager {\n protected readonly _asyncLocalStorage = new AsyncLocalStorage<Context>();\n\n private readonly _kOtListeners = Symbol('OtListeners');\n private _wrapped = false;\n\n public constructor() {\n setIsSetup('SentryContextManager');\n }\n\n public active(): Context {\n return this._asyncLocalStorage.getStore() ?? ROOT_CONTEXT;\n }\n\n public with<A extends unknown[], F extends (...args: A) => ReturnType<F>>(\n context: Context,\n fn: F,\n thisArg?: ThisParameterType<F>,\n ...args: A\n ): ReturnType<F> {\n const ctx2 = buildContextWithSentryScopes(context, this.active());\n const cb = thisArg == null ? fn : fn.bind(thisArg);\n return this._asyncLocalStorage.run(ctx2, cb as never, ...args);\n }\n\n public enable(): this {\n return this;\n }\n\n public disable(): this {\n this._asyncLocalStorage.disable();\n return this;\n }\n\n public bind<T>(context: Context, target: T): T {\n if (target instanceof EventEmitter) {\n return this._bindEventEmitter(context, target);\n }\n if (typeof target === 'function') {\n return this._bindFunction(context, target as unknown as ListenerFn) as T;\n }\n return target;\n }\n\n /**\n * Gets underlying AsyncLocalStorage and symbol to allow lookup of scope.\n * This is Sentry-specific.\n */\n public getAsyncLocalStorageLookup(): AsyncLocalStorageLookup {\n return {\n asyncLocalStorage: this._asyncLocalStorage,\n contextSymbol: SENTRY_SCOPES_CONTEXT_KEY,\n };\n }\n\n private _bindFunction(context: Context, target: ListenerFn): ListenerFn {\n const managerWith = this.with.bind(this);\n const contextWrapper = function (this: never, ...args: unknown[]) {\n return managerWith(context, () => target.apply(this, args));\n };\n Object.defineProperty(contextWrapper, 'length', {\n enumerable: false,\n configurable: true,\n writable: false,\n value: target.length,\n });\n return contextWrapper;\n }\n\n private _bindEventEmitter<T extends EventEmitter>(context: Context, ee: T): T {\n if (this._getPatchMap(ee) !== undefined) {\n return ee;\n }\n this._createPatchMap(ee);\n\n for (const methodName of ADD_LISTENER_METHODS) {\n if (ee[methodName] === undefined) continue;\n ee[methodName] = this._patchAddListener(\n ee,\n ee[methodName] as unknown as (...args: unknown[]) => unknown,\n context,\n );\n }\n if (typeof ee.removeListener === 'function') {\n // oxlint-disable-next-line @typescript-eslint/unbound-method -- patched like upstream OTel context manager\n ee.removeListener = this._patchRemoveListener(ee, ee.removeListener as (...args: unknown[]) => unknown);\n }\n if (typeof ee.off === 'function') {\n // oxlint-disable-next-line @typescript-eslint/unbound-method\n ee.off = this._patchRemoveListener(ee, ee.off as (...args: unknown[]) => unknown);\n }\n if (typeof ee.removeAllListeners === 'function') {\n ee.removeAllListeners = this._patchRemoveAllListeners(\n ee,\n // oxlint-disable-next-line @typescript-eslint/unbound-method\n ee.removeAllListeners as (...args: unknown[]) => unknown,\n );\n }\n return ee;\n }\n\n private _patchRemoveListener(ee: EventEmitter, original: (...args: unknown[]) => unknown) {\n // oxlint-disable-next-line @typescript-eslint/no-this-alias\n const contextManager = this;\n return function (this: unknown, event: string, listener: ListenerFn) {\n const events = contextManager._getPatchMap(ee)?.[event];\n if (events === undefined) {\n return original.call(this, event, listener);\n }\n const patchedListener = events.get(listener);\n return original.call(this, event, patchedListener || listener);\n };\n }\n\n private _patchRemoveAllListeners(ee: EventEmitter, original: (...args: unknown[]) => unknown) {\n // oxlint-disable-next-line @typescript-eslint/no-this-alias\n const contextManager = this;\n return function (this: unknown, event?: string) {\n const map = contextManager._getPatchMap(ee);\n if (map !== undefined) {\n if (arguments.length === 0) {\n contextManager._createPatchMap(ee);\n } else if (event !== undefined && map[event] !== undefined) {\n // oxlint-disable-next-line @typescript-eslint/no-dynamic-delete -- event-keyed listener map\n delete map[event];\n }\n }\n return original.apply(this, arguments);\n };\n }\n\n private _patchAddListener(ee: EventEmitter, original: (...args: unknown[]) => unknown, context: Context) {\n // oxlint-disable-next-line @typescript-eslint/no-this-alias\n const contextManager = this;\n return function (this: unknown, event: string, listener: ListenerFn) {\n if (contextManager._wrapped) {\n return original.call(this, event, listener);\n }\n let map = contextManager._getPatchMap(ee);\n if (map === undefined) {\n map = contextManager._createPatchMap(ee);\n }\n let listeners = map[event];\n if (listeners === undefined) {\n listeners = new WeakMap();\n map[event] = listeners;\n }\n const patchedListener = contextManager.bind(context, listener);\n listeners.set(listener, patchedListener);\n\n contextManager._wrapped = true;\n try {\n return original.call(this, event, patchedListener);\n } finally {\n contextManager._wrapped = false;\n }\n };\n }\n\n private _createPatchMap(ee: EventEmitter): PatchMap {\n const map = Object.create(null) as PatchMap;\n (ee as unknown as Record<symbol, PatchMap>)[this._kOtListeners] = map;\n return map;\n }\n\n private _getPatchMap(ee: EventEmitter): PatchMap | undefined {\n return (ee as unknown as Record<symbol, PatchMap | undefined>)[this._kOtListeners];\n }\n}\n"],"names":[],"mappings":"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"}

@@ -1,1 +0,1 @@

{"type":"module","version":"10.60.0","sideEffects":false}
{"type":"module","version":"10.61.0","sideEffects":false}

@@ -1,1 +0,1 @@

{"version":3,"file":"asyncContextStrategy.d.ts","sourceRoot":"","sources":["../../src/asyncContextStrategy.ts"],"names":[],"mappings":"AAeA;;;GAGG;AACH,wBAAgB,2CAA2C,IAAI,IAAI,CA4FlE"}
{"version":3,"file":"asyncContextStrategy.d.ts","sourceRoot":"","sources":["../../src/asyncContextStrategy.ts"],"names":[],"mappings":"AAuBA;;;GAGG;AACH,wBAAgB,2CAA2C,IAAI,IAAI,CAyGlE"}
{
"name": "@sentry/opentelemetry",
"version": "10.60.0",
"version": "10.61.0",
"description": "Official Sentry utilities for OpenTelemetry",

@@ -45,12 +45,2 @@ "repository": "git://github.com/getsentry/sentry-javascript.git",

}
},
"./tracing-channel": {
"import": {
"types": "./build/types/tracingChannel.d.ts",
"default": "./build/esm/tracingChannel.js"
},
"require": {
"types": "./build/types/tracingChannel.d.ts",
"default": "./build/cjs/tracingChannel.js"
}
}

@@ -70,3 +60,3 @@ },

"@sentry/conventions": "^0.12.0",
"@sentry/core": "10.60.0"
"@sentry/core": "10.61.0"
},

@@ -73,0 +63,0 @@ "peerDependencies": {

const DEBUG_BUILD = (typeof __SENTRY_DEBUG__ === 'undefined' || __SENTRY_DEBUG__);
exports.DEBUG_BUILD = DEBUG_BUILD;
//# sourceMappingURL=debug-build-CQngOfDt.js.map
{"version":3,"file":"debug-build-CQngOfDt.js","sources":["../../src/debug-build.ts"],"sourcesContent":["declare const __DEBUG_BUILD__: boolean;\n\n/**\n * This serves as a build time flag that will be true by default, but false in non-debug builds or if users replace `__SENTRY_DEBUG__` in their generated code.\n *\n * ATTENTION: This constant must never cross package boundaries (i.e. be exported) to guarantee that it can be used for tree shaking.\n */\nexport const DEBUG_BUILD = __DEBUG_BUILD__;\n"],"names":[],"mappings":"AAOO,MAAM,WAAA,IAAc,OAAA,gBAAA,KAAA,WAAA,IAAA,gBAAA;;;;"}
const api = require('@opentelemetry/api');
const core = require('@sentry/core');
const attributes = require('@sentry/conventions/attributes');
const core$1 = require('@opentelemetry/core');
const debugBuild = require('./debug-build-CQngOfDt.js');
const sdkTraceBase = require('@opentelemetry/sdk-trace-base');
const SEMANTIC_ATTRIBUTE_SENTRY_PARENT_IS_REMOTE = "sentry.parentIsRemote";
const SEMANTIC_ATTRIBUTE_SENTRY_GRAPHQL_OPERATION = "sentry.graphql.operation";
function getParentSpanId(span) {
if ("parentSpanId" in span) {
return span.parentSpanId;
} else if ("parentSpanContext" in span) {
return span.parentSpanContext?.spanId;
}
return void 0;
}
function spanHasAttributes(span) {
const castSpan = span;
return !!castSpan.attributes && typeof castSpan.attributes === "object";
}
function spanHasKind(span) {
const castSpan = span;
return typeof castSpan.kind === "number";
}
function spanHasStatus(span) {
const castSpan = span;
return !!castSpan.status;
}
function spanHasName(span) {
const castSpan = span;
return !!castSpan.name;
}
function spanHasParentId(span) {
const castSpan = span;
return !!getParentSpanId(castSpan);
}
function spanHasEvents(span) {
const castSpan = span;
return Array.isArray(castSpan.events);
}
function getRequestSpanData(span) {
if (!spanHasAttributes(span)) {
return {};
}
const maybeUrlAttribute = span.attributes[attributes.URL_FULL] || span.attributes[attributes.HTTP_URL];
const data = {
url: maybeUrlAttribute,
// eslint-disable-next-line typescript/no-deprecated
"http.method": span.attributes[attributes.HTTP_REQUEST_METHOD] || span.attributes[attributes.HTTP_METHOD]
};
if (!data["http.method"] && data.url) {
data["http.method"] = "GET";
}
try {
if (typeof maybeUrlAttribute === "string") {
const url = core.parseUrl(maybeUrlAttribute);
data.url = core.getSanitizedUrlString(url);
if (url.search) {
data["http.query"] = url.search;
}
if (url.hash) {
data["http.fragment"] = url.hash;
}
}
} catch {
}
return data;
}
function wrapClientClass(ClientClass) {
class OpenTelemetryClient extends ClientClass {
constructor(...args) {
super(...args);
}
/** Get the OTEL tracer. */
get tracer() {
if (this._tracer) {
return this._tracer;
}
const name = "@sentry/opentelemetry";
const version = core.SDK_VERSION;
const tracer = api.trace.getTracer(name, version);
this._tracer = tracer;
return tracer;
}
/**
* @inheritDoc
*/
async flush(timeout) {
const provider = this.traceProvider;
await provider?.forceFlush();
return super.flush(timeout);
}
}
return OpenTelemetryClient;
}
function getSpanKind(span) {
if (spanHasKind(span)) {
return span.kind;
}
return api.SpanKind.INTERNAL;
}
const SENTRY_TRACE_HEADER = "sentry-trace";
const SENTRY_BAGGAGE_HEADER = "baggage";
const SENTRY_TRACE_STATE_DSC = "sentry.dsc";
const SENTRY_TRACE_STATE_SAMPLED_NOT_RECORDING = "sentry.sampled_not_recording";
const SENTRY_TRACE_STATE_URL = "sentry.url";
const SENTRY_TRACE_STATE_SAMPLE_RAND = "sentry.sample_rand";
const SENTRY_TRACE_STATE_SAMPLE_RATE = "sentry.sample_rate";
const SENTRY_TRACE_STATE_CHILD_IGNORED = "sentry.ignored";
const SENTRY_TRACE_STATE_SEGMENT_IGNORED = "sentry.segment_ignored";
const SENTRY_SCOPES_CONTEXT_KEY = api.createContextKey("sentry_scopes");
const SENTRY_FORK_ISOLATION_SCOPE_CONTEXT_KEY = api.createContextKey("sentry_fork_isolation_scope");
const SENTRY_FORK_SET_SCOPE_CONTEXT_KEY = api.createContextKey("sentry_fork_set_scope");
const SENTRY_FORK_SET_ISOLATION_SCOPE_CONTEXT_KEY = api.createContextKey("sentry_fork_set_isolation_scope");
const SCOPE_CONTEXT_FIELD = "_scopeContext";
function getScopesFromContext(context) {
return context.getValue(SENTRY_SCOPES_CONTEXT_KEY);
}
function setScopesOnContext(context, scopes) {
return context.setValue(SENTRY_SCOPES_CONTEXT_KEY, scopes);
}
function setContextOnScope(scope, context) {
core.addNonEnumerableProperty(scope, SCOPE_CONTEXT_FIELD, core.makeWeakRef(context));
}
function getContextFromScope(scope) {
return core.derefWeakRef(scope[SCOPE_CONTEXT_FIELD]);
}
function isSentryRequestSpan(span) {
if (!spanHasAttributes(span)) {
return false;
}
const { attributes: attributes$1 } = span;
const httpUrl = attributes$1[attributes.HTTP_URL] || attributes$1[attributes.URL_FULL];
if (!httpUrl) {
return false;
}
return core.isSentryRequestUrl(httpUrl.toString(), core.getClient());
}
function getSamplingDecision(spanContext) {
const { traceFlags, traceState } = spanContext;
const sampledNotRecording = traceState ? traceState.get(SENTRY_TRACE_STATE_SAMPLED_NOT_RECORDING) === "1" : false;
if (traceFlags === api.TraceFlags.SAMPLED) {
return true;
}
if (sampledNotRecording) {
return false;
}
const dscString = traceState ? traceState.get(SENTRY_TRACE_STATE_DSC) : void 0;
const dsc = dscString ? core.baggageHeaderToDynamicSamplingContext(dscString) : void 0;
if (dsc?.sampled === "true") {
return true;
}
if (dsc?.sampled === "false") {
return false;
}
return void 0;
}
function inferSpanData(spanName, attributes$1, kind) {
const httpMethod = attributes$1[attributes.HTTP_REQUEST_METHOD] || attributes$1[attributes.HTTP_METHOD];
if (httpMethod) {
return descriptionForHttpMethod({ attributes: attributes$1, name: spanName, kind }, httpMethod);
}
const dbSystem = attributes$1[attributes.DB_SYSTEM_NAME] || attributes$1[attributes.DB_SYSTEM];
const opIsCache = typeof attributes$1[core.SEMANTIC_ATTRIBUTE_SENTRY_OP] === "string" && attributes$1[core.SEMANTIC_ATTRIBUTE_SENTRY_OP].startsWith("cache.");
if (dbSystem && !opIsCache) {
return descriptionForDbSystem({ attributes: attributes$1, name: spanName });
}
const customSourceOrRoute = attributes$1[core.SEMANTIC_ATTRIBUTE_SENTRY_SOURCE] === "custom" ? "custom" : "route";
const rpcService = attributes$1[attributes.RPC_SERVICE];
if (rpcService) {
return {
...getUserUpdatedNameAndSource(spanName, attributes$1, "route"),
op: "rpc"
};
}
const messagingSystem = attributes$1[attributes.MESSAGING_SYSTEM];
if (messagingSystem) {
return {
...getUserUpdatedNameAndSource(spanName, attributes$1, customSourceOrRoute),
op: "message"
};
}
const faasTrigger = attributes$1[attributes.FAAS_TRIGGER];
if (faasTrigger) {
return {
...getUserUpdatedNameAndSource(spanName, attributes$1, customSourceOrRoute),
op: faasTrigger.toString()
};
}
return { op: void 0, description: spanName, source: "custom" };
}
function parseSpanDescription(span) {
const attributes = spanHasAttributes(span) ? span.attributes : {};
const name = spanHasName(span) ? span.name : "<unknown>";
const kind = getSpanKind(span);
return inferSpanData(name, attributes, kind);
}
function descriptionForDbSystem({ attributes: attributes$1, name }) {
const userDefinedName = attributes$1[core.SEMANTIC_ATTRIBUTE_SENTRY_CUSTOM_SPAN_NAME];
if (typeof userDefinedName === "string") {
return {
op: "db",
description: userDefinedName,
source: attributes$1[core.SEMANTIC_ATTRIBUTE_SENTRY_SOURCE] || "custom"
};
}
if (attributes$1[core.SEMANTIC_ATTRIBUTE_SENTRY_SOURCE] === "custom") {
return { op: "db", description: name, source: "custom" };
}
const statement = attributes$1[attributes.DB_STATEMENT];
const description = statement ? statement.toString() : name;
return { op: "db", description, source: "task" };
}
function descriptionForHttpMethod({ name, kind, attributes }, httpMethod) {
const opParts = ["http"];
switch (kind) {
case api.SpanKind.CLIENT:
opParts.push("client");
break;
case api.SpanKind.SERVER:
opParts.push("server");
break;
}
if (attributes["sentry.http.prefetch"]) {
opParts.push("prefetch");
}
const { urlPath, url, query, fragment, hasRoute } = getSanitizedUrl(attributes, kind);
if (!urlPath) {
return { ...getUserUpdatedNameAndSource(name, attributes), op: opParts.join(".") };
}
const graphqlOperationsAttribute = attributes[SEMANTIC_ATTRIBUTE_SENTRY_GRAPHQL_OPERATION];
const baseDescription = `${httpMethod} ${urlPath}`;
const inferredDescription = graphqlOperationsAttribute ? `${baseDescription} (${getGraphqlOperationNamesFromAttribute(graphqlOperationsAttribute)})` : baseDescription;
const inferredSource = hasRoute || urlPath === "/" ? "route" : "url";
const data = {};
if (url) {
data.url = url;
}
if (query) {
data["http.query"] = query;
}
if (fragment) {
data["http.fragment"] = fragment;
}
const isClientOrServerKind = kind === api.SpanKind.CLIENT || kind === api.SpanKind.SERVER;
const origin = attributes[core.SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN] || "manual";
const isManualSpan = !`${origin}`.startsWith("auto");
const alreadyHasCustomSource = attributes[core.SEMANTIC_ATTRIBUTE_SENTRY_SOURCE] === "custom";
const customSpanName = attributes[core.SEMANTIC_ATTRIBUTE_SENTRY_CUSTOM_SPAN_NAME];
const useInferredDescription = !alreadyHasCustomSource && customSpanName == null && (isClientOrServerKind || !isManualSpan);
const { description, source } = useInferredDescription ? { description: inferredDescription, source: inferredSource } : getUserUpdatedNameAndSource(name, attributes);
return {
op: opParts.join("."),
description,
source,
data
};
}
function getGraphqlOperationNamesFromAttribute(attr) {
if (Array.isArray(attr)) {
const sorted = attr.slice().sort();
if (sorted.length <= 5) {
return sorted.join(", ");
} else {
return `${sorted.slice(0, 5).join(", ")}, +${sorted.length - 5}`;
}
}
return `${attr}`;
}
function getSanitizedUrl(attributes$1, kind) {
const httpTarget = attributes$1[attributes.HTTP_TARGET];
const httpUrl = attributes$1[attributes.HTTP_URL] || attributes$1[attributes.URL_FULL];
const httpRoute = attributes$1[attributes.HTTP_ROUTE];
const parsedUrl = typeof httpUrl === "string" ? core.parseUrl(httpUrl) : void 0;
const url = parsedUrl ? core.getSanitizedUrlString(parsedUrl) : void 0;
const query = parsedUrl?.search || void 0;
const fragment = parsedUrl?.hash || void 0;
if (typeof httpRoute === "string") {
return { urlPath: httpRoute, url, query, fragment, hasRoute: true };
}
if (kind === api.SpanKind.SERVER && typeof httpTarget === "string") {
return { urlPath: core.stripUrlQueryAndFragment(httpTarget), url, query, fragment, hasRoute: false };
}
if (parsedUrl) {
return { urlPath: url, url, query, fragment, hasRoute: false };
}
if (typeof httpTarget === "string") {
return { urlPath: core.stripUrlQueryAndFragment(httpTarget), url, query, fragment, hasRoute: false };
}
return { urlPath: void 0, url, query, fragment, hasRoute: false };
}
function getUserUpdatedNameAndSource(originalName, attributes, fallbackSource = "custom") {
const source = attributes[core.SEMANTIC_ATTRIBUTE_SENTRY_SOURCE] || fallbackSource;
const description = attributes[core.SEMANTIC_ATTRIBUTE_SENTRY_CUSTOM_SPAN_NAME];
if (description && typeof description === "string") {
return {
description,
source
};
}
return { description: originalName, source };
}
function enhanceDscWithOpenTelemetryRootSpanName(client) {
client.on("createDsc", (dsc, rootSpan) => {
if (!rootSpan) {
return;
}
const jsonSpan = core.spanToJSON(rootSpan);
const attributes = jsonSpan.data;
const source = attributes[core.SEMANTIC_ATTRIBUTE_SENTRY_SOURCE];
const { description } = spanHasName(rootSpan) ? parseSpanDescription(rootSpan) : { description: void 0 };
if (source !== "url" && description) {
dsc.transaction = description;
}
if (core.hasSpansEnabled()) {
const sampled = getSamplingDecision(rootSpan.spanContext());
dsc.sampled = sampled == void 0 ? void 0 : String(sampled);
}
});
}
function getActiveSpan() {
return api.trace.getActiveSpan();
}
class TraceState {
constructor() {
this._internalState = /* @__PURE__ */ new Map();
}
/** @inheritDoc */
set(key, value) {
const next = this._clone();
if (next._internalState.has(key)) {
next._internalState.delete(key);
}
next._internalState.set(key, value);
return next;
}
/** @inheritDoc */
unset(key) {
const next = this._clone();
next._internalState.delete(key);
return next;
}
/** @inheritDoc */
get(key) {
return this._internalState.get(key);
}
/** @inheritDoc */
serialize() {
return Array.from(this._internalState.keys()).reverse().map((key) => `${key}=${this._internalState.get(key)}`).join(",");
}
_clone() {
const next = new TraceState();
next._internalState = new Map(this._internalState);
return next;
}
}
function makeTraceState({
dsc,
sampled
}) {
const dscString = dsc ? core.dynamicSamplingContextToSentryBaggageHeader(dsc) : void 0;
const traceStateBase = new TraceState();
const traceStateWithDsc = dscString ? traceStateBase.set(SENTRY_TRACE_STATE_DSC, dscString) : traceStateBase;
return sampled === false ? traceStateWithDsc.set(SENTRY_TRACE_STATE_SAMPLED_NOT_RECORDING, "1") : traceStateWithDsc;
}
const setupElements = /* @__PURE__ */ new Set();
function openTelemetrySetupCheck() {
return Array.from(setupElements);
}
function setIsSetup(element) {
setupElements.add(element);
}
class SentryPropagator extends core$1.W3CBaggagePropagator {
constructor() {
super();
setIsSetup("SentryPropagator");
this._urlMatchesTargetsMap = new core.LRUMap(100);
}
/**
* @inheritDoc
*/
inject(context2, carrier, setter) {
if (core$1.isTracingSuppressed(context2)) {
debugBuild.DEBUG_BUILD && core.debug.log("[Tracing] Not injecting trace data for url because tracing is suppressed.");
return;
}
const activeSpan = api.trace.getSpan(context2);
const url = activeSpan && getCurrentURL(activeSpan);
const { tracePropagationTargets, propagateTraceparent } = core.getClient()?.getOptions() || {};
if (!core.shouldPropagateTraceForUrl(url, tracePropagationTargets, this._urlMatchesTargetsMap)) {
debugBuild.DEBUG_BUILD && core.debug.log("[Tracing] Not injecting trace data for url because it does not match tracePropagationTargets:", url);
return;
}
const existingBaggageHeader = getExistingBaggage(carrier);
const existingSentryTraceHeader = getExistingSentryTrace(carrier);
let baggage = api.propagation.getBaggage(context2) || api.propagation.createBaggage({});
const { dynamicSamplingContext, traceId, spanId, sampled } = getInjectionData(context2);
if (existingBaggageHeader) {
const baggageEntries = core.parseBaggageHeader(existingBaggageHeader);
if (baggageEntries) {
Object.entries(baggageEntries).forEach(([key, value]) => {
if (!existingSentryTraceHeader && key.startsWith(core.SENTRY_BAGGAGE_KEY_PREFIX)) {
return;
}
baggage = baggage.setEntry(key, { value });
});
}
}
if (!existingSentryTraceHeader && dynamicSamplingContext) {
baggage = Object.entries(dynamicSamplingContext).reduce((b, [dscKey, dscValue]) => {
if (dscValue) {
return b.setEntry(`${core.SENTRY_BAGGAGE_KEY_PREFIX}${dscKey}`, { value: dscValue });
}
return b;
}, baggage);
}
if (!existingSentryTraceHeader && traceId && traceId !== api.INVALID_TRACEID) {
setter.set(carrier, SENTRY_TRACE_HEADER, core.generateSentryTraceHeader(traceId, spanId, sampled));
if (propagateTraceparent) {
setter.set(carrier, "traceparent", core.generateTraceparentHeader(traceId, spanId, sampled));
}
}
super.inject(api.propagation.setBaggage(context2, baggage), carrier, setter);
}
/**
* @inheritDoc
*/
extract(context2, carrier, getter) {
const maybeSentryTraceHeader = getter.get(carrier, SENTRY_TRACE_HEADER);
const baggage = getter.get(carrier, SENTRY_BAGGAGE_HEADER);
const sentryTrace = maybeSentryTraceHeader ? Array.isArray(maybeSentryTraceHeader) ? maybeSentryTraceHeader[0] : maybeSentryTraceHeader : void 0;
return ensureScopesOnContext(getContextWithRemoteActiveSpan(context2, { sentryTrace, baggage }));
}
/**
* @inheritDoc
*/
fields() {
return [SENTRY_TRACE_HEADER, SENTRY_BAGGAGE_HEADER, "traceparent"];
}
}
function getInjectionData(context2, options = {}) {
const span = api.trace.getSpan(context2);
if (span?.spanContext().isRemote) {
const spanContext = span.spanContext();
const dynamicSamplingContext2 = core.getDynamicSamplingContextFromSpan(span);
return {
dynamicSamplingContext: dynamicSamplingContext2,
traceId: spanContext.traceId,
spanId: void 0,
sampled: getSamplingDecision(spanContext)
// TODO: Do we need to change something here?
};
}
if (span) {
const spanContext = span.spanContext();
const dynamicSamplingContext2 = core.getDynamicSamplingContextFromSpan(span);
return {
dynamicSamplingContext: dynamicSamplingContext2,
traceId: spanContext.traceId,
spanId: spanContext.spanId,
sampled: getSamplingDecision(spanContext)
// TODO: Do we need to change something here?
};
}
const scope = options.scope || getScopesFromContext(context2)?.scope || core.getCurrentScope();
const client = options.client || core.getClient();
const propagationContext = scope.getPropagationContext();
const dynamicSamplingContext = client ? core.getDynamicSamplingContextFromScope(client, scope) : void 0;
return {
dynamicSamplingContext,
traceId: propagationContext.traceId,
spanId: propagationContext.propagationSpanId,
sampled: propagationContext.sampled
};
}
function getContextWithRemoteActiveSpan(ctx, { sentryTrace, baggage }) {
const propagationContext = core.propagationContextFromHeaders(sentryTrace, baggage);
const { traceId, parentSpanId, sampled, dsc } = propagationContext;
const client = core.getClient();
const incomingDsc = core.baggageHeaderToDynamicSamplingContext(baggage);
if (!parentSpanId || client && !core.shouldContinueTrace(client, incomingDsc?.org_id)) {
return ctx;
}
const spanContext = generateRemoteSpanContext({
traceId,
spanId: parentSpanId,
sampled,
dsc
});
return api.trace.setSpanContext(ctx, spanContext);
}
function continueTraceAsRemoteSpan(ctx, options, callback) {
const ctxWithSpanContext = ensureScopesOnContext(getContextWithRemoteActiveSpan(ctx, options));
return api.context.with(ctxWithSpanContext, callback);
}
function ensureScopesOnContext(ctx) {
const scopes = getScopesFromContext(ctx);
const newScopes = {
// If we have no scope here, this is most likely either the root context or a context manually derived from it
// In this case, we want to fork the current scope, to ensure we do not pollute the root scope
scope: scopes ? scopes.scope : core.getCurrentScope().clone(),
isolationScope: scopes ? scopes.isolationScope : core.getIsolationScope()
};
return setScopesOnContext(ctx, newScopes);
}
function getExistingBaggage(carrier) {
try {
const baggage = carrier[SENTRY_BAGGAGE_HEADER];
return Array.isArray(baggage) ? baggage.join(",") : baggage;
} catch {
return void 0;
}
}
function getExistingSentryTrace(carrier) {
try {
return carrier[SENTRY_TRACE_HEADER];
} catch {
return void 0;
}
}
function getCurrentURL(span) {
const spanData = core.spanToJSON(span).data;
const urlAttribute = spanData[attributes.HTTP_URL] || spanData[attributes.URL_FULL];
if (typeof urlAttribute === "string") {
return urlAttribute;
}
const urlTraceState = span.spanContext().traceState?.get(SENTRY_TRACE_STATE_URL);
if (urlTraceState) {
return urlTraceState;
}
return void 0;
}
function generateRemoteSpanContext({
spanId,
traceId,
sampled,
dsc
}) {
const traceState = makeTraceState({
dsc,
sampled
});
const spanContext = {
traceId,
spanId,
isRemote: true,
traceFlags: sampled ? api.TraceFlags.SAMPLED : api.TraceFlags.NONE,
traceState
};
return spanContext;
}
function _startSpan(options, callback, autoEnd) {
const tracer = getTracer();
const { name, parentSpan: customParentSpan } = options;
const wrapper = getActiveSpanWrapper(customParentSpan);
return wrapper(() => {
const activeCtx = getContext(options.scope, options.forceTransaction);
const missingRequiredParent = options.onlyIfParent && !api.trace.getSpan(activeCtx);
const ctx = missingRequiredParent ? core$1.suppressTracing(activeCtx) : activeCtx;
if (missingRequiredParent) {
core.getClient()?.recordDroppedEvent("no_parent_span", "span");
}
const spanOptions = getSpanOptions(options);
if (!core.hasSpansEnabled()) {
const suppressedCtx = core$1.isTracingSuppressed(ctx) ? ctx : core$1.suppressTracing(ctx);
return api.context.with(suppressedCtx, () => {
return tracer.startActiveSpan(name, spanOptions, suppressedCtx, (span) => {
patchSpanEnd(span);
return api.context.with(activeCtx, () => {
return core.handleCallbackErrors(
() => callback(span),
() => {
if (core.spanToJSON(span).status === void 0) {
span.setStatus({ code: api.SpanStatusCode.ERROR });
}
},
autoEnd ? () => span.end() : void 0
);
});
});
});
}
return tracer.startActiveSpan(name, spanOptions, ctx, (span) => {
patchSpanEnd(span);
return core.handleCallbackErrors(
() => callback(span),
() => {
if (core.spanToJSON(span).status === void 0) {
span.setStatus({ code: api.SpanStatusCode.ERROR });
}
},
autoEnd ? () => span.end() : void 0
);
});
});
}
function startSpan(options, callback) {
return _startSpan(options, callback, true);
}
function startSpanManual(options, callback) {
return _startSpan(options, (span) => callback(span, () => span.end()), false);
}
function startInactiveSpan(options) {
const tracer = getTracer();
const { name, parentSpan: customParentSpan } = options;
const wrapper = getActiveSpanWrapper(customParentSpan);
return wrapper(() => {
const activeCtx = getContext(options.scope, options.forceTransaction);
const missingRequiredParent = options.onlyIfParent && !api.trace.getSpan(activeCtx);
let ctx = missingRequiredParent ? core$1.suppressTracing(activeCtx) : activeCtx;
if (missingRequiredParent) {
core.getClient()?.recordDroppedEvent("no_parent_span", "span");
}
const spanOptions = getSpanOptions(options);
if (!core.hasSpansEnabled()) {
ctx = core$1.isTracingSuppressed(ctx) ? ctx : core$1.suppressTracing(ctx);
}
const span = tracer.startSpan(name, spanOptions, ctx);
patchSpanEnd(span);
return span;
});
}
function withActiveSpan(span, callback) {
const newContextWithActiveSpan = span ? api.trace.setSpan(api.context.active(), span) : api.trace.deleteSpan(api.context.active());
return api.context.with(newContextWithActiveSpan, () => callback(core.getCurrentScope()));
}
function getTracer() {
const client = core.getClient();
return client?.tracer || api.trace.getTracer("@sentry/opentelemetry", core.SDK_VERSION);
}
function getSpanOptions(options) {
const { startTime, attributes, kind, op, links } = options;
const fixedStartTime = typeof startTime === "number" ? ensureTimestampInMilliseconds(startTime) : startTime;
return {
attributes: op ? {
[core.SEMANTIC_ATTRIBUTE_SENTRY_OP]: op,
...attributes
} : attributes,
kind,
links,
startTime: fixedStartTime
};
}
function ensureTimestampInMilliseconds(timestamp) {
const isMs = timestamp < 9999999999;
return isMs ? timestamp * 1e3 : timestamp;
}
function patchSpanEnd(span) {
const originalEnd = span.end.bind(span);
span.end = (endTime) => {
return originalEnd(typeof endTime === "number" ? ensureTimestampInMilliseconds(endTime) : endTime);
};
}
function getContext(scope, forceTransaction) {
const ctx = getContextForScope(scope);
const parentSpan = api.trace.getSpan(ctx);
if (!parentSpan) {
return ctx;
}
if (!forceTransaction) {
return ctx;
}
const ctxWithoutSpan = api.trace.deleteSpan(ctx);
const { spanId, traceId } = parentSpan.spanContext();
const sampled = getSamplingDecision(parentSpan.spanContext());
const rootSpan = core.getRootSpan(parentSpan);
const dsc = core.getDynamicSamplingContextFromSpan(rootSpan);
const traceState = makeTraceState({
dsc,
sampled
});
const spanOptions = {
traceId,
spanId,
isRemote: true,
traceFlags: sampled ? api.TraceFlags.SAMPLED : api.TraceFlags.NONE,
traceState
};
const ctxWithSpanContext = api.trace.setSpanContext(ctxWithoutSpan, spanOptions);
return ctxWithSpanContext;
}
function getContextForScope(scope) {
if (scope) {
const ctx = getContextFromScope(scope);
if (ctx) {
return ctx;
}
}
return api.context.active();
}
function continueTrace(options, callback) {
return continueTraceAsRemoteSpan(api.context.active(), options, callback);
}
function startNewTrace(callback) {
const traceId = core.generateTraceId();
const spanId = core.generateSpanId();
const spanContext = {
traceId,
spanId,
isRemote: true,
traceFlags: api.TraceFlags.NONE
};
const ctxWithTrace = api.trace.setSpanContext(api.context.active(), spanContext);
return api.context.with(ctxWithTrace, () => {
core.getCurrentScope().setPropagationContext({
traceId,
sampleRand: core._INTERNAL_safeMathRandom()
});
return callback();
});
}
function getTraceContextForScope(client, scope) {
const ctx = getContextFromScope(scope);
const span = ctx && api.trace.getSpan(ctx);
const traceContext = span ? core.spanToTraceContext(span) : core.getTraceContextFromScope(scope);
const dynamicSamplingContext = span ? core.getDynamicSamplingContextFromSpan(span) : core.getDynamicSamplingContextFromScope(client, scope);
return [dynamicSamplingContext, traceContext];
}
function getActiveSpanWrapper(parentSpan) {
return parentSpan !== void 0 ? (callback) => {
return withActiveSpan(parentSpan, callback);
} : (callback) => callback();
}
function suppressTracing(callback) {
const ctx = core$1.suppressTracing(api.context.active());
return api.context.with(ctx, callback);
}
function setupEventContextTrace(client) {
client.on("preprocessEvent", (event) => {
const span = getActiveSpan();
if (!span || event.type === "transaction") {
return;
}
event.contexts = {
trace: core.spanToTraceContext(span),
...event.contexts
};
const rootSpan = core.getRootSpan(span);
event.sdkProcessingMetadata = {
dynamicSamplingContext: core.getDynamicSamplingContextFromSpan(rootSpan),
...event.sdkProcessingMetadata
};
return event;
});
}
function getTraceData({
span,
scope,
client,
propagateTraceparent
} = {}) {
let ctx = (scope && getContextFromScope(scope)) ?? api.context.active();
if (span) {
const { scope: scope2 } = core.getCapturedScopesOnSpan(span);
ctx = scope2 && getContextFromScope(scope2) || api.trace.setSpan(api.context.active(), span);
}
const { traceId, spanId, sampled, dynamicSamplingContext } = getInjectionData(ctx, { scope, client });
const traceData = {
"sentry-trace": core.generateSentryTraceHeader(traceId, spanId, sampled),
baggage: core.dynamicSamplingContextToSentryBaggageHeader(dynamicSamplingContext)
};
if (propagateTraceparent) {
traceData.traceparent = core.generateTraceparentHeader(traceId, spanId, sampled);
}
return traceData;
}
function setOpenTelemetryContextAsyncContextStrategy() {
function getScopes() {
const ctx = api.context.active();
const scopes = getScopesFromContext(ctx);
if (scopes) {
return scopes;
}
return {
scope: core.getDefaultCurrentScope(),
isolationScope: core.getDefaultIsolationScope()
};
}
function withScope(callback) {
const ctx = api.context.active();
return api.context.with(ctx, () => {
return callback(getCurrentScope());
});
}
function withSetScope(scope, callback) {
const ctx = getContextFromScope(scope) || api.context.active();
return api.context.with(ctx.setValue(SENTRY_FORK_SET_SCOPE_CONTEXT_KEY, scope), () => {
return callback(scope);
});
}
function withIsolationScope(callback) {
const ctx = api.context.active();
return api.context.with(ctx.setValue(SENTRY_FORK_ISOLATION_SCOPE_CONTEXT_KEY, true), () => {
return callback(getIsolationScope());
});
}
function withSetIsolationScope(isolationScope, callback) {
const ctx = api.context.active();
return api.context.with(ctx.setValue(SENTRY_FORK_SET_ISOLATION_SCOPE_CONTEXT_KEY, isolationScope), () => {
return callback(getIsolationScope());
});
}
function getCurrentScope() {
return getScopes().scope;
}
function getIsolationScope() {
return getScopes().isolationScope;
}
core.setAsyncContextStrategy({
withScope,
withSetScope,
withSetIsolationScope,
withIsolationScope,
getCurrentScope,
getIsolationScope,
startSpan,
startSpanManual,
startInactiveSpan,
getActiveSpan,
suppressTracing,
getTraceData,
continueTrace,
startNewTrace,
// The types here don't fully align, because our own `Span` type is narrower
// than the OTEL one - but this is OK for here, as we now we'll only have OTEL spans passed around
withActiveSpan
});
}
function buildContextWithSentryScopes(context, activeContext) {
const span = api.trace.getSpan(context);
let effectiveContext;
if (span?.spanContext().traceState?.get(SENTRY_TRACE_STATE_CHILD_IGNORED) === "1") {
const contextWithoutSpan = api.trace.deleteSpan(context);
const parentSpan = api.trace.getSpan(activeContext);
effectiveContext = parentSpan ? api.trace.setSpan(contextWithoutSpan, parentSpan) : contextWithoutSpan;
} else {
effectiveContext = context;
}
const currentScopes = getScopesFromContext(effectiveContext);
const currentScope = currentScopes?.scope || core.getCurrentScope();
const currentIsolationScope = currentScopes?.isolationScope || core.getIsolationScope();
const shouldForkIsolationScope = effectiveContext.getValue(SENTRY_FORK_ISOLATION_SCOPE_CONTEXT_KEY) === true;
const scope = effectiveContext.getValue(SENTRY_FORK_SET_SCOPE_CONTEXT_KEY);
const isolationScope = effectiveContext.getValue(SENTRY_FORK_SET_ISOLATION_SCOPE_CONTEXT_KEY);
const newCurrentScope = scope || currentScope.clone();
const newIsolationScope = isolationScope || (shouldForkIsolationScope ? currentIsolationScope.clone() : currentIsolationScope);
const scopes = { scope: newCurrentScope, isolationScope: newIsolationScope };
const ctx1 = setScopesOnContext(effectiveContext, scopes);
const ctx2 = ctx1.deleteValue(SENTRY_FORK_ISOLATION_SCOPE_CONTEXT_KEY).deleteValue(SENTRY_FORK_SET_SCOPE_CONTEXT_KEY).deleteValue(SENTRY_FORK_SET_ISOLATION_SCOPE_CONTEXT_KEY);
setContextOnScope(newCurrentScope, ctx2);
return ctx2;
}
function wrapContextManagerClass(ContextManagerClass) {
class SentryContextManager extends ContextManagerClass {
constructor(...args) {
super(...args);
setIsSetup("SentryContextManager");
}
/**
* Overwrite with() of the original AsyncLocalStorageContextManager
* to ensure we also create new scopes per context.
*/
with(context, fn, thisArg, ...args) {
const ctx2 = buildContextWithSentryScopes(context, this.active());
return super.with(ctx2, fn, thisArg, ...args);
}
/**
* Gets underlying AsyncLocalStorage and symbol to allow lookup of scope.
*/
getAsyncLocalStorageLookup() {
return {
// @ts-expect-error This is on the base class, but not part of the interface
asyncLocalStorage: this._asyncLocalStorage,
contextSymbol: SENTRY_SCOPES_CONTEXT_KEY
};
}
}
return SentryContextManager;
}
function groupSpansWithParents(spans) {
const nodeMap = /* @__PURE__ */ new Map();
for (const span of spans) {
createOrUpdateSpanNodeAndRefs(nodeMap, span);
}
return Array.from(nodeMap, function([_id, spanNode]) {
return spanNode;
});
}
function getLocalParentId(span) {
const parentIsRemote = span.attributes[SEMANTIC_ATTRIBUTE_SENTRY_PARENT_IS_REMOTE] === true;
return !parentIsRemote ? getParentSpanId(span) : void 0;
}
function createOrUpdateSpanNodeAndRefs(nodeMap, span) {
const id = span.spanContext().spanId;
const parentId = getLocalParentId(span);
if (!parentId) {
createOrUpdateNode(nodeMap, { id, span, children: [] });
return;
}
const parentNode = createOrGetParentNode(nodeMap, parentId);
const node = createOrUpdateNode(nodeMap, { id, span, parentNode, children: [] });
parentNode.children.push(node);
}
function createOrGetParentNode(nodeMap, id) {
const existing = nodeMap.get(id);
if (existing) {
return existing;
}
return createOrUpdateNode(nodeMap, { id, children: [] });
}
function createOrUpdateNode(nodeMap, spanNode) {
const existing = nodeMap.get(spanNode.id);
if (existing?.span) {
return existing;
}
if (existing && !existing.span) {
existing.span = spanNode.span;
existing.parentNode = spanNode.parentNode;
return existing;
}
nodeMap.set(spanNode.id, spanNode);
return spanNode;
}
const canonicalGrpcErrorCodesMap = {
"1": "cancelled",
"2": "unknown_error",
"3": "invalid_argument",
"4": "deadline_exceeded",
"5": "not_found",
"6": "already_exists",
"7": "permission_denied",
"8": "resource_exhausted",
"9": "failed_precondition",
"10": "aborted",
"11": "out_of_range",
"12": "unimplemented",
"13": "internal_error",
"14": "unavailable",
"15": "data_loss",
"16": "unauthenticated"
};
const isStatusErrorMessageValid = (message) => {
return Object.values(canonicalGrpcErrorCodesMap).includes(message);
};
function mapStatus(span) {
const attributes = spanHasAttributes(span) ? span.attributes : {};
const status = spanHasStatus(span) ? span.status : void 0;
if (status) {
if (status.code === api.SpanStatusCode.OK) {
return { code: core.SPAN_STATUS_OK };
} else if (status.code === api.SpanStatusCode.ERROR) {
if (typeof status.message === "undefined") {
const inferredStatus2 = inferStatusFromAttributes(attributes);
if (inferredStatus2) {
return inferredStatus2;
}
}
if (status.message && isStatusErrorMessageValid(status.message)) {
return { code: core.SPAN_STATUS_ERROR, message: status.message };
} else {
return { code: core.SPAN_STATUS_ERROR, message: "internal_error" };
}
}
}
const inferredStatus = inferStatusFromAttributes(attributes);
if (inferredStatus) {
return inferredStatus;
}
if (status?.code === api.SpanStatusCode.UNSET) {
return { code: core.SPAN_STATUS_OK };
} else {
return { code: core.SPAN_STATUS_ERROR, message: "unknown_error" };
}
}
function inferStatusFromAttributes(attributes$1) {
const httpCodeAttribute = attributes$1[attributes.HTTP_RESPONSE_STATUS_CODE] || attributes$1[attributes.HTTP_STATUS_CODE];
const grpcCodeAttribute = attributes$1[attributes.RPC_GRPC_STATUS_CODE];
const numberHttpCode = typeof httpCodeAttribute === "number" ? httpCodeAttribute : typeof httpCodeAttribute === "string" ? parseInt(httpCodeAttribute) : void 0;
if (typeof numberHttpCode === "number") {
return core.getSpanStatusFromHttpCode(numberHttpCode);
}
if (typeof grpcCodeAttribute === "string") {
return { code: core.SPAN_STATUS_ERROR, message: canonicalGrpcErrorCodesMap[grpcCodeAttribute] || "unknown_error" };
}
return void 0;
}
const MAX_SPAN_COUNT = 1e3;
const DEFAULT_TIMEOUT = 300;
const SENT_SPANS_MAX_SIZE = 1e4;
class SentrySpanExporter {
constructor(options) {
this._finishedSpanBucketSize = options?.timeout || DEFAULT_TIMEOUT;
this._finishedSpanBuckets = new Array(this._finishedSpanBucketSize).fill(void 0);
this._lastCleanupTimestampInS = Math.floor(core._INTERNAL_safeDateNow() / 1e3);
this._spansToBucketEntry = /* @__PURE__ */ new WeakMap();
this._sentSpans = new core.LRUMap(SENT_SPANS_MAX_SIZE);
this._debouncedFlush = core.debounce(this.flush.bind(this), 1, { maxWait: 100 });
}
/**
* Export a single span.
* This is called by the span processor whenever a span is ended.
*/
export(span) {
const currentTimestampInS = Math.floor(core._INTERNAL_safeDateNow() / 1e3);
if (this._lastCleanupTimestampInS !== currentTimestampInS) {
let droppedSpanCount = 0;
this._finishedSpanBuckets.forEach((bucket, i) => {
if (bucket && bucket.timestampInS <= currentTimestampInS - this._finishedSpanBucketSize) {
droppedSpanCount += bucket.spans.size;
this._finishedSpanBuckets[i] = void 0;
}
});
if (droppedSpanCount > 0) {
debugBuild.DEBUG_BUILD && core.debug.log(
`SpanExporter dropped ${droppedSpanCount} spans because they were pending for more than ${this._finishedSpanBucketSize} seconds.`
);
}
this._lastCleanupTimestampInS = currentTimestampInS;
}
const currentBucketIndex = currentTimestampInS % this._finishedSpanBucketSize;
const currentBucket = this._finishedSpanBuckets[currentBucketIndex] || {
timestampInS: currentTimestampInS,
spans: /* @__PURE__ */ new Set()
};
this._finishedSpanBuckets[currentBucketIndex] = currentBucket;
currentBucket.spans.add(span);
this._spansToBucketEntry.set(span, currentBucket);
const localParentId = getLocalParentId(span);
if (!localParentId || this._sentSpans.get(localParentId)) {
this._debouncedFlush();
}
}
/**
* Try to flush any pending spans immediately.
* This is called internally by the exporter (via _debouncedFlush),
* but can also be triggered externally if we force-flush.
*/
flush() {
const finishedSpans = this._finishedSpanBuckets.flatMap((bucket) => bucket ? Array.from(bucket.spans) : []);
const sentSpans = this._maybeSend(finishedSpans);
const sentSpanCount = sentSpans.size;
const remainingOpenSpanCount = finishedSpans.length - sentSpanCount;
debugBuild.DEBUG_BUILD && core.debug.log(
`SpanExporter exported ${sentSpanCount} spans, ${remainingOpenSpanCount} spans are waiting for their parent spans to finish`
);
for (const span of sentSpans) {
this._sentSpans.set(span.spanContext().spanId, 1);
const bucketEntry = this._spansToBucketEntry.get(span);
if (bucketEntry) {
bucketEntry.spans.delete(span);
}
}
this._debouncedFlush.cancel();
}
/**
* Clear the exporter.
* This is called when the span processor is shut down.
*/
clear() {
this._finishedSpanBuckets = this._finishedSpanBuckets.fill(void 0);
this._sentSpans.clear();
this._debouncedFlush.cancel();
}
/**
* Send the given spans, but only if they are part of a finished transaction.
*
* Returns the sent spans.
* Spans remain unsent when their parent span is not yet finished.
* This will happen regularly, as child spans are generally finished before their parents.
* But it _could_ also happen because, for whatever reason, a parent span was lost.
* In this case, we'll eventually need to clean this up.
*/
_maybeSend(spans) {
const grouped = groupSpansWithParents(spans);
const sentSpans = /* @__PURE__ */ new Set();
const rootNodes = this._getCompletedRootNodes(grouped);
for (const root of rootNodes) {
const span = root.span;
sentSpans.add(span);
const transactionEvent = createTransactionForOtelSpan(span);
if (root.parentNode && this._sentSpans.get(root.parentNode.id)) {
const traceData = transactionEvent.contexts?.trace?.data;
if (traceData) {
traceData["sentry.parent_span_already_sent"] = true;
}
}
const spans2 = transactionEvent.spans || [];
let hasGenAiSpans = false;
for (const child of root.children) {
if (createAndFinishSpanForOtelSpan(child, spans2, sentSpans)) {
hasGenAiSpans = true;
}
}
transactionEvent.spans = spans2.length > MAX_SPAN_COUNT ? spans2.sort((a, b) => a.start_timestamp - b.start_timestamp).slice(0, MAX_SPAN_COUNT) : spans2;
if (hasGenAiSpans) {
transactionEvent.sdkProcessingMetadata = {
...transactionEvent.sdkProcessingMetadata,
hasGenAiSpans: true
};
}
const measurements = core.timedEventsToMeasurements(span.events);
if (measurements) {
transactionEvent.measurements = measurements;
}
core.captureEvent(transactionEvent);
}
return sentSpans;
}
/** Check if a node is a completed root node or a node whose parent has already been sent */
_nodeIsCompletedRootNodeOrHasSentParent(node) {
return !!node.span && (!node.parentNode || !!this._sentSpans.get(node.parentNode.id));
}
/** Get all completed root nodes from a list of nodes */
_getCompletedRootNodes(nodes) {
return nodes.filter((node) => this._nodeIsCompletedRootNodeOrHasSentParent(node));
}
}
function parseSpan(span) {
const attributes = span.attributes;
const origin = attributes[core.SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN];
const op = attributes[core.SEMANTIC_ATTRIBUTE_SENTRY_OP];
const source = attributes[core.SEMANTIC_ATTRIBUTE_SENTRY_SOURCE];
return { origin, op, source };
}
function createTransactionForOtelSpan(span) {
const { op, description, data, origin = "manual", source } = getSpanData(span);
const capturedSpanScopes = core.getCapturedScopesOnSpan(span);
const sampleRate = span.attributes[core.SEMANTIC_ATTRIBUTE_SENTRY_SAMPLE_RATE];
const attributes$1 = {
[core.SEMANTIC_ATTRIBUTE_SENTRY_SOURCE]: source,
[core.SEMANTIC_ATTRIBUTE_SENTRY_SAMPLE_RATE]: sampleRate,
[core.SEMANTIC_ATTRIBUTE_SENTRY_OP]: op,
[core.SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: origin,
...data,
...removeSentryAttributes(span.attributes)
};
const { links } = span;
const { traceId: trace_id, spanId: span_id } = span.spanContext();
const parent_span_id = getParentSpanId(span);
const status = mapStatus(span);
const traceContext = {
parent_span_id,
span_id,
trace_id,
data: attributes$1,
origin,
op,
status: core.getStatusMessage(status),
// As per protocol, span status is allowed to be undefined
links: core.convertSpanLinksForEnvelope(links)
};
const statusCode = attributes$1[attributes.HTTP_RESPONSE_STATUS_CODE];
const responseContext = typeof statusCode === "number" ? { response: { status_code: statusCode } } : void 0;
const transactionEvent = {
contexts: {
trace: traceContext,
otel: {
resource: span.resource.attributes
},
...responseContext
},
spans: [],
start_timestamp: core.spanTimeInputToSeconds(span.startTime),
timestamp: core.spanTimeInputToSeconds(span.endTime),
transaction: description,
type: "transaction",
sdkProcessingMetadata: {
capturedSpanScope: capturedSpanScopes.scope,
capturedSpanIsolationScope: capturedSpanScopes.isolationScope,
sampleRate,
dynamicSamplingContext: core.getDynamicSamplingContextFromSpan(span)
},
...source && {
transaction_info: {
source
}
}
};
return transactionEvent;
}
function createAndFinishSpanForOtelSpan(node, spans, sentSpans) {
const span = node.span;
if (span) {
sentSpans.add(span);
}
const shouldDrop = !span;
if (shouldDrop) {
let hasGenAiSpans2 = false;
node.children.forEach((child) => {
if (createAndFinishSpanForOtelSpan(child, spans, sentSpans)) {
hasGenAiSpans2 = true;
}
});
return hasGenAiSpans2;
}
const span_id = span.spanContext().spanId;
const trace_id = span.spanContext().traceId;
const parentSpanId = getParentSpanId(span);
const { attributes, startTime, endTime, links } = span;
const { op, description, data, origin = "manual" } = getSpanData(span);
const allData = {
[core.SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: origin,
[core.SEMANTIC_ATTRIBUTE_SENTRY_OP]: op,
...removeSentryAttributes(attributes),
...data
};
const status = mapStatus(span);
const spanJSON = {
span_id,
trace_id,
data: allData,
description,
parent_span_id: parentSpanId,
start_timestamp: core.spanTimeInputToSeconds(startTime),
// This is [0,0] by default in OTEL, in which case we want to interpret this as no end time
timestamp: core.spanTimeInputToSeconds(endTime) || void 0,
status: core.getStatusMessage(status),
// As per protocol, span status is allowed to be undefined
op,
origin,
measurements: core.timedEventsToMeasurements(span.events),
links: core.convertSpanLinksForEnvelope(links)
};
spans.push(spanJSON);
let hasGenAiSpans = !!op?.startsWith("gen_ai.");
node.children.forEach((child) => {
if (createAndFinishSpanForOtelSpan(child, spans, sentSpans)) {
hasGenAiSpans = true;
}
});
return hasGenAiSpans;
}
function getSpanData(span) {
const { op: definedOp, source: definedSource, origin } = parseSpan(span);
const { op: inferredOp, description, source: inferredSource, data: inferredData } = parseSpanDescription(span);
const op = definedOp || inferredOp;
const source = definedSource || inferredSource;
const data = { ...inferredData, ...getData(span) };
return {
op,
description,
source,
origin,
data
};
}
function removeSentryAttributes(data) {
const cleanedData = { ...data };
delete cleanedData[core.SEMANTIC_ATTRIBUTE_SENTRY_SAMPLE_RATE];
delete cleanedData[SEMANTIC_ATTRIBUTE_SENTRY_PARENT_IS_REMOTE];
delete cleanedData[core.SEMANTIC_ATTRIBUTE_SENTRY_CUSTOM_SPAN_NAME];
return cleanedData;
}
function getData(span) {
const attributes$1 = span.attributes;
const data = {};
if (span.kind !== api.SpanKind.INTERNAL) {
data["otel.kind"] = api.SpanKind[span.kind];
}
const maybeHttpStatusCodeAttribute = attributes$1[attributes.HTTP_STATUS_CODE];
if (maybeHttpStatusCodeAttribute) {
data[attributes.HTTP_RESPONSE_STATUS_CODE] = maybeHttpStatusCodeAttribute;
}
const requestData = getRequestSpanData(span);
if (requestData.url) {
data.url = requestData.url;
}
if (requestData["http.query"]) {
data["http.query"] = requestData["http.query"].slice(1);
}
if (requestData["http.fragment"]) {
data["http.fragment"] = requestData["http.fragment"].slice(1);
}
return data;
}
class SentrySpanProcessor {
constructor(options) {
this._unsubscribePreprocessSpan = void 0;
setIsSetup("SentrySpanProcessor");
this._exporter = new SentrySpanExporter(options);
this._client = options?.client ?? core.getClient();
if (this._client && core.hasSpanStreamingEnabled(this._client)) {
this._unsubscribePreprocessSpan = this._client.on("preprocessSpan", backfillStreamedSpanDataFromOtel);
}
}
/**
* @inheritDoc
*/
async forceFlush() {
this._exporter.flush();
}
/**
* @inheritDoc
*/
async shutdown() {
this._unsubscribePreprocessSpan?.();
this._exporter.clear();
}
/**
* @inheritDoc
*/
onStart(span, parentContext) {
const parentSpan = api.trace.getSpan(parentContext);
let scopes = getScopesFromContext(parentContext);
if (parentSpan && !parentSpan.spanContext().isRemote) {
core.addChildSpanToSpan(parentSpan, span);
}
if (parentSpan?.spanContext().isRemote) {
span.setAttribute(SEMANTIC_ATTRIBUTE_SENTRY_PARENT_IS_REMOTE, true);
}
if (parentContext === api.ROOT_CONTEXT) {
scopes = {
scope: core.getDefaultCurrentScope(),
isolationScope: core.getDefaultIsolationScope()
};
}
if (scopes) {
core.setCapturedScopesOnSpan(span, scopes.scope, scopes.isolationScope);
}
core.logSpanStart(span);
this._client?.emit("spanStart", span);
}
/** @inheritDoc */
onEnd(span) {
core.logSpanEnd(span);
this._client?.emit("spanEnd", span);
if (this._client && core.hasSpanStreamingEnabled(this._client)) {
this._client.emit("afterSpanEnd", span);
} else {
this._exporter.export(span);
}
}
}
function backfillStreamedSpanDataFromOtel(spanJSON, hint) {
const attributes = spanJSON.attributes;
if (!attributes) {
return;
}
const kind = hint?.spanKind ?? api.SpanKind.INTERNAL;
const { op, description, source, data } = inferSpanData(spanJSON.name, attributes, kind);
spanJSON.name = description;
core.safeSetSpanJSONAttributes(spanJSON, {
[core.SEMANTIC_ATTRIBUTE_SENTRY_OP]: op,
[core.SEMANTIC_ATTRIBUTE_SENTRY_SOURCE]: source,
...data
});
if (kind !== api.SpanKind.INTERNAL) {
core.safeSetSpanJSONAttributes(spanJSON, {
"otel.kind": api.SpanKind[kind]
});
}
}
class SentrySampler {
constructor(client) {
this._client = client;
this._isSpanStreaming = core.hasSpanStreamingEnabled(client);
setIsSetup("SentrySampler");
}
/** @inheritDoc */
shouldSample(context, traceId, spanName, spanKind, spanAttributes, _links) {
const options = this._client.getOptions();
const { ignoreSpans } = options;
const parentSpan = getValidSpan(context);
const parentContext = parentSpan?.spanContext();
if (!core.hasSpansEnabled(options)) {
return wrapSamplingDecision({ decision: void 0, context, spanAttributes });
}
const maybeSpanHttpMethod = spanAttributes[attributes.HTTP_METHOD] || spanAttributes[attributes.HTTP_REQUEST_METHOD];
if (spanKind === api.SpanKind.CLIENT && maybeSpanHttpMethod && (!parentSpan || parentContext?.isRemote)) {
if (!this._isSpanStreaming) {
this._client.recordDroppedEvent("no_parent_span", "span");
return wrapSamplingDecision({ decision: void 0, context, spanAttributes });
}
}
const parentSampled = parentSpan ? getParentSampled(parentSpan, traceId, spanName) : void 0;
const isRootSpan = !parentSpan || parentContext?.isRemote;
if (!isRootSpan) {
if (this._isSpanStreaming) {
if (parentSampled) {
if (ignoreSpans?.length) {
const { description: inferredChildName, op: childOp } = inferSpanData(spanName, spanAttributes, spanKind);
if (core.shouldIgnoreSpan(
{
description: inferredChildName,
op: spanAttributes[core.SEMANTIC_ATTRIBUTE_SENTRY_OP] ?? childOp,
attributes: spanAttributes
},
ignoreSpans
)) {
this._client.recordDroppedEvent("ignored", "span");
return wrapSamplingDecision({
decision: sdkTraceBase.SamplingDecision.NOT_RECORD,
context,
spanAttributes,
ignoredChildSpan: true
});
}
}
}
if (!parentSampled) {
const parentSegmentIgnored = parentContext?.traceState?.get(SENTRY_TRACE_STATE_SEGMENT_IGNORED) === "1";
this._client.recordDroppedEvent(parentSegmentIgnored ? "ignored" : "sample_rate", "span");
}
}
return wrapSamplingDecision({
decision: parentSampled ? sdkTraceBase.SamplingDecision.RECORD_AND_SAMPLED : sdkTraceBase.SamplingDecision.NOT_RECORD,
context,
spanAttributes
});
}
const {
description: inferredSpanName,
data: inferredAttributes,
op
} = inferSpanData(spanName, spanAttributes, spanKind);
const mergedAttributes = {
...inferredAttributes,
...spanAttributes
};
if (op) {
mergedAttributes[core.SEMANTIC_ATTRIBUTE_SENTRY_OP] = op;
}
if (this._isSpanStreaming && ignoreSpans?.length && core.shouldIgnoreSpan(
{
description: inferredSpanName,
op: mergedAttributes[core.SEMANTIC_ATTRIBUTE_SENTRY_OP] ?? op,
attributes: mergedAttributes
},
ignoreSpans
)) {
this._client.recordDroppedEvent("ignored", "span");
return wrapSamplingDecision({
decision: sdkTraceBase.SamplingDecision.NOT_RECORD,
context,
spanAttributes,
ignoredSegmentSpan: true
});
}
const mutableSamplingDecision = { decision: true };
this._client.emit(
"beforeSampling",
{
spanAttributes: mergedAttributes,
spanName: inferredSpanName,
parentSampled,
parentContext
},
mutableSamplingDecision
);
if (!mutableSamplingDecision.decision) {
return wrapSamplingDecision({ decision: void 0, context, spanAttributes });
}
const { isolationScope } = getScopesFromContext(context) ?? {};
const dscString = parentContext?.traceState ? parentContext.traceState.get(SENTRY_TRACE_STATE_DSC) : void 0;
const dsc = dscString ? core.baggageHeaderToDynamicSamplingContext(dscString) : void 0;
const sampleRand = core.parseSampleRate(dsc?.sample_rand) ?? core._INTERNAL_safeMathRandom();
const [sampled, sampleRate, localSampleRateWasApplied] = core.sampleSpan(
options,
{
name: inferredSpanName,
attributes: mergedAttributes,
normalizedRequest: isolationScope?.getScopeData().sdkProcessingMetadata.normalizedRequest,
parentSampled,
parentSampleRate: core.parseSampleRate(dsc?.sample_rate)
},
sampleRand
);
const method = `${maybeSpanHttpMethod}`.toUpperCase();
if (method === "OPTIONS" || method === "HEAD") {
debugBuild.DEBUG_BUILD && core.debug.log(`[Tracing] Not sampling span because HTTP method is '${method}' for ${spanName}`);
return wrapSamplingDecision({
decision: sdkTraceBase.SamplingDecision.NOT_RECORD,
context,
spanAttributes,
sampleRand,
downstreamTraceSampleRate: 0
// we don't want to sample anything in the downstream trace either
});
}
if (!sampled && // We check for `parentSampled === undefined` because we only want to record client reports for spans that are trace roots (ie. when there was incoming trace)
parentSampled === void 0) {
debugBuild.DEBUG_BUILD && core.debug.log("[Tracing] Discarding root span because its trace was not chosen to be sampled.");
this._client.recordDroppedEvent("sample_rate", this._isSpanStreaming ? "span" : "transaction");
}
return {
...wrapSamplingDecision({
decision: sampled ? sdkTraceBase.SamplingDecision.RECORD_AND_SAMPLED : sdkTraceBase.SamplingDecision.NOT_RECORD,
context,
spanAttributes,
sampleRand,
downstreamTraceSampleRate: localSampleRateWasApplied ? sampleRate : void 0
}),
attributes: {
// We set the sample rate on the span when a local sample rate was applied to better understand how traces were sampled in Sentry
[core.SEMANTIC_ATTRIBUTE_SENTRY_SAMPLE_RATE]: localSampleRateWasApplied ? sampleRate : void 0
}
};
}
/** Returns the sampler name or short description with the configuration. */
toString() {
return "SentrySampler";
}
}
function getParentSampled(parentSpan, traceId, spanName) {
const parentContext = parentSpan.spanContext();
if (api.isSpanContextValid(parentContext) && parentContext.traceId === traceId) {
if (parentContext.isRemote) {
const parentSampled2 = getSamplingDecision(parentSpan.spanContext());
debugBuild.DEBUG_BUILD && core.debug.log(`[Tracing] Inheriting remote parent's sampled decision for ${spanName}: ${parentSampled2}`);
return parentSampled2;
}
const parentSampled = getSamplingDecision(parentContext);
debugBuild.DEBUG_BUILD && core.debug.log(`[Tracing] Inheriting parent's sampled decision for ${spanName}: ${parentSampled}`);
return parentSampled;
}
return void 0;
}
function wrapSamplingDecision({
decision,
context,
spanAttributes,
sampleRand,
downstreamTraceSampleRate,
ignoredChildSpan,
ignoredSegmentSpan
}) {
let traceState = getBaseTraceState(context, spanAttributes);
if (downstreamTraceSampleRate !== void 0) {
traceState = traceState.set(SENTRY_TRACE_STATE_SAMPLE_RATE, `${downstreamTraceSampleRate}`);
}
if (sampleRand !== void 0) {
traceState = traceState.set(SENTRY_TRACE_STATE_SAMPLE_RAND, `${sampleRand}`);
}
if (ignoredChildSpan) {
traceState = traceState.set(SENTRY_TRACE_STATE_CHILD_IGNORED, "1");
}
if (ignoredSegmentSpan) {
traceState = traceState.set(SENTRY_TRACE_STATE_SEGMENT_IGNORED, "1");
}
if (decision == void 0) {
return { decision: sdkTraceBase.SamplingDecision.NOT_RECORD, traceState };
}
if (decision === sdkTraceBase.SamplingDecision.NOT_RECORD) {
return { decision, traceState: traceState.set(SENTRY_TRACE_STATE_SAMPLED_NOT_RECORDING, "1") };
}
return { decision, traceState };
}
function getBaseTraceState(context, spanAttributes) {
const parentSpan = api.trace.getSpan(context);
const parentContext = parentSpan?.spanContext();
let traceState = parentContext?.traceState || new TraceState();
const url = spanAttributes[attributes.HTTP_URL] || spanAttributes[attributes.URL_FULL];
if (url && typeof url === "string") {
traceState = traceState.set(SENTRY_TRACE_STATE_URL, url);
}
return traceState;
}
function getValidSpan(context) {
const span = api.trace.getSpan(context);
return span && api.isSpanContextValid(span.spanContext()) ? span : void 0;
}
const ATTR_TELEMETRY_SDK_LANGUAGE = "telemetry.sdk.language";
const ATTR_TELEMETRY_SDK_NAME = "telemetry.sdk.name";
const ATTR_TELEMETRY_SDK_VERSION = "telemetry.sdk.version";
const SEMRESATTRS_SERVICE_NAMESPACE = "service.namespace";
class SentryResource {
constructor(attributes) {
this._attributes = attributes;
}
get attributes() {
return this._attributes;
}
merge(other) {
if (!other) {
return this;
}
return new SentryResource({ ...this._attributes, ...other.attributes });
}
getRawAttributes() {
return Object.entries(this._attributes);
}
}
function parseOtelResourceAttributes(raw) {
if (!raw) {
return {};
}
const result = {};
for (const pair of raw.split(",")) {
const eq = pair.indexOf("=");
if (eq === -1) {
continue;
}
const key = pair.substring(0, eq).trim();
const value = pair.substring(eq + 1).trim();
if (key) {
try {
result[key] = decodeURIComponent(value);
} catch {
result[key] = value;
}
}
}
return result;
}
function getSentryResource(serviceNameFallback) {
const env = typeof process !== "undefined" ? process.env : {};
const otelServiceName = env.OTEL_SERVICE_NAME;
const otelResourceAttrs = parseOtelResourceAttributes(env.OTEL_RESOURCE_ATTRIBUTES);
return new SentryResource({
// Lowest priority: Sentry defaults
// eslint-disable-next-line typescript/no-deprecated
[SEMRESATTRS_SERVICE_NAMESPACE]: "sentry",
[attributes.SERVICE_NAME]: serviceNameFallback,
// OTEL_RESOURCE_ATTRIBUTES overrides defaults (including service.name and service.namespace)
...otelResourceAttrs,
// OTEL_SERVICE_NAME explicitly overrides service.name
...otelServiceName ? { [attributes.SERVICE_NAME]: otelServiceName } : {},
// Highest priority: Sentry SDK telemetry attrs (cannot be overridden by env vars)
[attributes.SERVICE_VERSION]: core.SDK_VERSION,
[ATTR_TELEMETRY_SDK_LANGUAGE]: core$1.SDK_INFO[ATTR_TELEMETRY_SDK_LANGUAGE],
[ATTR_TELEMETRY_SDK_NAME]: core$1.SDK_INFO[ATTR_TELEMETRY_SDK_NAME],
[ATTR_TELEMETRY_SDK_VERSION]: core$1.SDK_INFO[ATTR_TELEMETRY_SDK_VERSION]
});
}
exports.SEMANTIC_ATTRIBUTE_SENTRY_GRAPHQL_OPERATION = SEMANTIC_ATTRIBUTE_SENTRY_GRAPHQL_OPERATION;
exports.SENTRY_SCOPES_CONTEXT_KEY = SENTRY_SCOPES_CONTEXT_KEY;
exports.SentryPropagator = SentryPropagator;
exports.SentrySampler = SentrySampler;
exports.SentrySpanProcessor = SentrySpanProcessor;
exports.buildContextWithSentryScopes = buildContextWithSentryScopes;
exports.continueTrace = continueTrace;
exports.enhanceDscWithOpenTelemetryRootSpanName = enhanceDscWithOpenTelemetryRootSpanName;
exports.getActiveSpan = getActiveSpan;
exports.getRequestSpanData = getRequestSpanData;
exports.getScopesFromContext = getScopesFromContext;
exports.getSentryResource = getSentryResource;
exports.getSpanKind = getSpanKind;
exports.getTraceContextForScope = getTraceContextForScope;
exports.isSentryRequestSpan = isSentryRequestSpan;
exports.openTelemetrySetupCheck = openTelemetrySetupCheck;
exports.setIsSetup = setIsSetup;
exports.setOpenTelemetryContextAsyncContextStrategy = setOpenTelemetryContextAsyncContextStrategy;
exports.setupEventContextTrace = setupEventContextTrace;
exports.spanHasAttributes = spanHasAttributes;
exports.spanHasEvents = spanHasEvents;
exports.spanHasKind = spanHasKind;
exports.spanHasName = spanHasName;
exports.spanHasParentId = spanHasParentId;
exports.spanHasStatus = spanHasStatus;
exports.startInactiveSpan = startInactiveSpan;
exports.startSpan = startSpan;
exports.startSpanManual = startSpanManual;
exports.suppressTracing = suppressTracing;
exports.withActiveSpan = withActiveSpan;
exports.wrapClientClass = wrapClientClass;
exports.wrapContextManagerClass = wrapContextManagerClass;
exports.wrapSamplingDecision = wrapSamplingDecision;
//# sourceMappingURL=resource-DEULI4zI.js.map

Sorry, the diff of this file is too big to display

Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
const diagnosticsChannel = require('node:diagnostics_channel');
const api = require('@opentelemetry/api');
const core = require('@sentry/core');
const debugBuild = require('./debug-build-CQngOfDt.js');
function tracingChannel(channelNameOrInstance, transformStart) {
const channel = diagnosticsChannel.tracingChannel(channelNameOrInstance);
let lookup;
try {
const contextManager = api.context._getContextManager();
lookup = contextManager.getAsyncLocalStorageLookup();
} catch {
}
if (!lookup) {
debugBuild.DEBUG_BUILD && core.logger.warn(
"[TracingChannel] Could not access OpenTelemetry AsyncLocalStorage, context propagation will not work."
);
return channel;
}
const otelStorage = lookup.asyncLocalStorage;
channel.start.bindStore(otelStorage, (data) => {
const span = transformStart(data);
data._sentrySpan = span;
return api.trace.setSpan(api.context.active(), span);
});
return channel;
}
exports.tracingChannel = tracingChannel;
//# sourceMappingURL=tracingChannel.js.map
{"version":3,"file":"tracingChannel.js","sources":["../../src/tracingChannel.ts"],"sourcesContent":["/**\n * Vendored and adapted from https://github.com/logaretm/otel-tracing-channel\n *\n * Creates a TracingChannel with proper OpenTelemetry context propagation\n * using Node.js diagnostic_channel's `bindStore` mechanism.\n */\nimport type { TracingChannel, TracingChannelSubscribers } from 'node:diagnostics_channel';\nimport * as diagnosticsChannel from 'node:diagnostics_channel';\nimport type { Span } from '@opentelemetry/api';\nimport { context, trace } from '@opentelemetry/api';\nimport { logger } from '@sentry/core';\nimport type { SentryAsyncLocalStorageContextManager } from './asyncLocalStorageContextManager';\nimport type { AsyncLocalStorageLookup } from './contextManager';\nimport { DEBUG_BUILD } from './debug-build';\n\n/**\n * Transform function that creates a span from the channel data.\n */\nexport type OtelTracingChannelTransform<TData = object> = (data: TData) => Span;\n\nexport type TracingChannelContextWithSpan<TContext extends object = object> = TContext & { _sentrySpan?: Span };\n\n/**\n * A TracingChannel whose `subscribe` / `unsubscribe` accept partial subscriber\n * objects — you only need to provide handlers for the events you care about.\n */\nexport interface OtelTracingChannel<\n TData extends object = object,\n TDataWithSpan extends object = TracingChannelContextWithSpan<TData>,\n> extends Omit<TracingChannel<TData, TDataWithSpan>, 'subscribe' | 'unsubscribe'> {\n subscribe(subscribers: Partial<TracingChannelSubscribers<TDataWithSpan>>): void;\n unsubscribe(subscribers: Partial<TracingChannelSubscribers<TDataWithSpan>>): void;\n}\n\ninterface ContextApi {\n _getContextManager(): SentryAsyncLocalStorageContextManager;\n}\n\n/**\n * Creates a new tracing channel with proper OTel context propagation.\n *\n * When the channel's `tracePromise` / `traceSync` / `traceCallback` is called,\n * the `transformStart` function runs inside `bindStore` so that:\n * 1. A new span is created from the channel data.\n * 2. The span is set on the OTel context stored in AsyncLocalStorage.\n * 3. Downstream code (including Sentry's span processor) sees the correct parent.\n *\n * @param channelNameOrInstance - Either a channel name string or an existing TracingChannel instance.\n * @param transformStart - Function that creates an OpenTelemetry span from the channel data.\n * @returns The tracing channel with OTel context bound.\n */\nexport function tracingChannel<TData extends object = object>(\n channelNameOrInstance: string,\n transformStart: OtelTracingChannelTransform<TData>,\n): OtelTracingChannel<TData, TracingChannelContextWithSpan<TData>> {\n const channel = diagnosticsChannel.tracingChannel<\n TracingChannelContextWithSpan<TData>,\n TracingChannelContextWithSpan<TData>\n >(channelNameOrInstance) as unknown as OtelTracingChannel<TData, TracingChannelContextWithSpan<TData>>;\n\n let lookup: AsyncLocalStorageLookup | undefined;\n try {\n const contextManager = (context as unknown as ContextApi)._getContextManager();\n lookup = contextManager.getAsyncLocalStorageLookup();\n } catch {\n // getAsyncLocalStorageLookup may not exist if using a non-Sentry context manager\n }\n\n if (!lookup) {\n DEBUG_BUILD &&\n logger.warn(\n '[TracingChannel] Could not access OpenTelemetry AsyncLocalStorage, context propagation will not work.',\n );\n return channel;\n }\n\n const otelStorage = lookup.asyncLocalStorage;\n\n // Bind the start channel so that each trace invocation runs the transform\n // and stores the resulting context (with span) in AsyncLocalStorage.\n // @ts-expect-error bindStore types don't account for AsyncLocalStorage of a different generic type\n channel.start.bindStore(otelStorage, (data: TracingChannelContextWithSpan<TData>) => {\n const span = transformStart(data);\n\n // Store the span on data so downstream event handlers (asyncEnd, error, etc.) can access it.\n data._sentrySpan = span;\n\n // Return the context with the span set — this is what gets stored in AsyncLocalStorage.\n return trace.setSpan(context.active(), span);\n });\n\n return channel;\n}\n"],"names":["context","DEBUG_BUILD","logger","trace"],"mappings":";;;;;;;AAmDO,SAAS,cAAA,CACd,uBACA,cAAA,EACiE;AACjE,EAAA,MAAM,OAAA,GAAU,kBAAA,CAAmB,cAAA,CAGjC,qBAAqB,CAAA;AAEvB,EAAA,IAAI,MAAA;AACJ,EAAA,IAAI;AACF,IAAA,MAAM,cAAA,GAAkBA,YAAkC,kBAAA,EAAmB;AAC7E,IAAA,MAAA,GAAS,eAAe,0BAAA,EAA2B;AAAA,EACrD,CAAA,CAAA,MAAQ;AAAA,EAER;AAEA,EAAA,IAAI,CAAC,MAAA,EAAQ;AACX,IAAAC,sBAAA,IACEC,WAAA,CAAO,IAAA;AAAA,MACL;AAAA,KACF;AACF,IAAA,OAAO,OAAA;AAAA,EACT;AAEA,EAAA,MAAM,cAAc,MAAA,CAAO,iBAAA;AAK3B,EAAA,OAAA,CAAQ,KAAA,CAAM,SAAA,CAAU,WAAA,EAAa,CAAC,IAAA,KAA+C;AACnF,IAAA,MAAM,IAAA,GAAO,eAAe,IAAI,CAAA;AAGhC,IAAA,IAAA,CAAK,WAAA,GAAc,IAAA;AAGnB,IAAA,OAAOC,SAAA,CAAM,OAAA,CAAQH,WAAA,CAAQ,MAAA,IAAU,IAAI,CAAA;AAAA,EAC7C,CAAC,CAAA;AAED,EAAA,OAAO,OAAA;AACT;;;;"}
const DEBUG_BUILD = (typeof __SENTRY_DEBUG__ === 'undefined' || __SENTRY_DEBUG__);
export { DEBUG_BUILD as D };
//# sourceMappingURL=debug-build-B98wrZ1j.js.map
{"version":3,"file":"debug-build-B98wrZ1j.js","sources":["../../src/debug-build.ts"],"sourcesContent":["declare const __DEBUG_BUILD__: boolean;\n\n/**\n * This serves as a build time flag that will be true by default, but false in non-debug builds or if users replace `__SENTRY_DEBUG__` in their generated code.\n *\n * ATTENTION: This constant must never cross package boundaries (i.e. be exported) to guarantee that it can be used for tree shaking.\n */\nexport const DEBUG_BUILD = __DEBUG_BUILD__;\n"],"names":[],"mappings":"AAOO,MAAM,WAAA,IAAc,OAAA,gBAAA,KAAA,WAAA,IAAA,gBAAA;;;;"}
import * as api from '@opentelemetry/api';
import { trace, SpanKind, createContextKey, TraceFlags, propagation, INVALID_TRACEID, context, SpanStatusCode, ROOT_CONTEXT, isSpanContextValid } from '@opentelemetry/api';
import { parseUrl, getSanitizedUrlString, SDK_VERSION, derefWeakRef, addNonEnumerableProperty, makeWeakRef, isSentryRequestUrl, getClient, baggageHeaderToDynamicSamplingContext, SEMANTIC_ATTRIBUTE_SENTRY_OP, SEMANTIC_ATTRIBUTE_SENTRY_SOURCE, SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN, SEMANTIC_ATTRIBUTE_SENTRY_CUSTOM_SPAN_NAME, stripUrlQueryAndFragment, spanToJSON, hasSpansEnabled, dynamicSamplingContextToSentryBaggageHeader, LRUMap, debug, shouldPropagateTraceForUrl, parseBaggageHeader, SENTRY_BAGGAGE_KEY_PREFIX, generateSentryTraceHeader, generateTraceparentHeader, getDynamicSamplingContextFromSpan, getCurrentScope, getDynamicSamplingContextFromScope, getIsolationScope, propagationContextFromHeaders, shouldContinueTrace, spanToTraceContext, getTraceContextFromScope, generateTraceId, generateSpanId, _INTERNAL_safeMathRandom, getRootSpan, handleCallbackErrors, getCapturedScopesOnSpan, setAsyncContextStrategy, getDefaultIsolationScope, getDefaultCurrentScope, SPAN_STATUS_OK, SPAN_STATUS_ERROR, getSpanStatusFromHttpCode, _INTERNAL_safeDateNow, debounce, timedEventsToMeasurements, captureEvent, SEMANTIC_ATTRIBUTE_SENTRY_SAMPLE_RATE, convertSpanLinksForEnvelope, getStatusMessage, spanTimeInputToSeconds, hasSpanStreamingEnabled, addChildSpanToSpan, setCapturedScopesOnSpan, logSpanStart, logSpanEnd, safeSetSpanJSONAttributes, shouldIgnoreSpan, parseSampleRate, sampleSpan } from '@sentry/core';
import { URL_FULL, HTTP_URL, HTTP_REQUEST_METHOD, HTTP_METHOD, DB_SYSTEM_NAME, DB_SYSTEM, RPC_SERVICE, MESSAGING_SYSTEM, FAAS_TRIGGER, DB_STATEMENT, HTTP_TARGET, HTTP_ROUTE, HTTP_RESPONSE_STATUS_CODE, HTTP_STATUS_CODE, RPC_GRPC_STATUS_CODE, SERVICE_VERSION, SERVICE_NAME } from '@sentry/conventions/attributes';
import { W3CBaggagePropagator, isTracingSuppressed, suppressTracing as suppressTracing$1, SDK_INFO } from '@opentelemetry/core';
import { D as DEBUG_BUILD } from './debug-build-B98wrZ1j.js';
import { SamplingDecision } from '@opentelemetry/sdk-trace-base';
const SEMANTIC_ATTRIBUTE_SENTRY_PARENT_IS_REMOTE = "sentry.parentIsRemote";
const SEMANTIC_ATTRIBUTE_SENTRY_GRAPHQL_OPERATION = "sentry.graphql.operation";
function getParentSpanId(span) {
if ("parentSpanId" in span) {
return span.parentSpanId;
} else if ("parentSpanContext" in span) {
return span.parentSpanContext?.spanId;
}
return void 0;
}
function spanHasAttributes(span) {
const castSpan = span;
return !!castSpan.attributes && typeof castSpan.attributes === "object";
}
function spanHasKind(span) {
const castSpan = span;
return typeof castSpan.kind === "number";
}
function spanHasStatus(span) {
const castSpan = span;
return !!castSpan.status;
}
function spanHasName(span) {
const castSpan = span;
return !!castSpan.name;
}
function spanHasParentId(span) {
const castSpan = span;
return !!getParentSpanId(castSpan);
}
function spanHasEvents(span) {
const castSpan = span;
return Array.isArray(castSpan.events);
}
function getRequestSpanData(span) {
if (!spanHasAttributes(span)) {
return {};
}
const maybeUrlAttribute = span.attributes[URL_FULL] || span.attributes[HTTP_URL];
const data = {
url: maybeUrlAttribute,
// eslint-disable-next-line typescript/no-deprecated
"http.method": span.attributes[HTTP_REQUEST_METHOD] || span.attributes[HTTP_METHOD]
};
if (!data["http.method"] && data.url) {
data["http.method"] = "GET";
}
try {
if (typeof maybeUrlAttribute === "string") {
const url = parseUrl(maybeUrlAttribute);
data.url = getSanitizedUrlString(url);
if (url.search) {
data["http.query"] = url.search;
}
if (url.hash) {
data["http.fragment"] = url.hash;
}
}
} catch {
}
return data;
}
function wrapClientClass(ClientClass) {
class OpenTelemetryClient extends ClientClass {
constructor(...args) {
super(...args);
}
/** Get the OTEL tracer. */
get tracer() {
if (this._tracer) {
return this._tracer;
}
const name = "@sentry/opentelemetry";
const version = SDK_VERSION;
const tracer = trace.getTracer(name, version);
this._tracer = tracer;
return tracer;
}
/**
* @inheritDoc
*/
async flush(timeout) {
const provider = this.traceProvider;
await provider?.forceFlush();
return super.flush(timeout);
}
}
return OpenTelemetryClient;
}
function getSpanKind(span) {
if (spanHasKind(span)) {
return span.kind;
}
return SpanKind.INTERNAL;
}
const SENTRY_TRACE_HEADER = "sentry-trace";
const SENTRY_BAGGAGE_HEADER = "baggage";
const SENTRY_TRACE_STATE_DSC = "sentry.dsc";
const SENTRY_TRACE_STATE_SAMPLED_NOT_RECORDING = "sentry.sampled_not_recording";
const SENTRY_TRACE_STATE_URL = "sentry.url";
const SENTRY_TRACE_STATE_SAMPLE_RAND = "sentry.sample_rand";
const SENTRY_TRACE_STATE_SAMPLE_RATE = "sentry.sample_rate";
const SENTRY_TRACE_STATE_CHILD_IGNORED = "sentry.ignored";
const SENTRY_TRACE_STATE_SEGMENT_IGNORED = "sentry.segment_ignored";
const SENTRY_SCOPES_CONTEXT_KEY = createContextKey("sentry_scopes");
const SENTRY_FORK_ISOLATION_SCOPE_CONTEXT_KEY = createContextKey("sentry_fork_isolation_scope");
const SENTRY_FORK_SET_SCOPE_CONTEXT_KEY = createContextKey("sentry_fork_set_scope");
const SENTRY_FORK_SET_ISOLATION_SCOPE_CONTEXT_KEY = createContextKey("sentry_fork_set_isolation_scope");
const SCOPE_CONTEXT_FIELD = "_scopeContext";
function getScopesFromContext(context) {
return context.getValue(SENTRY_SCOPES_CONTEXT_KEY);
}
function setScopesOnContext(context, scopes) {
return context.setValue(SENTRY_SCOPES_CONTEXT_KEY, scopes);
}
function setContextOnScope(scope, context) {
addNonEnumerableProperty(scope, SCOPE_CONTEXT_FIELD, makeWeakRef(context));
}
function getContextFromScope(scope) {
return derefWeakRef(scope[SCOPE_CONTEXT_FIELD]);
}
function isSentryRequestSpan(span) {
if (!spanHasAttributes(span)) {
return false;
}
const { attributes } = span;
const httpUrl = attributes[HTTP_URL] || attributes[URL_FULL];
if (!httpUrl) {
return false;
}
return isSentryRequestUrl(httpUrl.toString(), getClient());
}
function getSamplingDecision(spanContext) {
const { traceFlags, traceState } = spanContext;
const sampledNotRecording = traceState ? traceState.get(SENTRY_TRACE_STATE_SAMPLED_NOT_RECORDING) === "1" : false;
if (traceFlags === TraceFlags.SAMPLED) {
return true;
}
if (sampledNotRecording) {
return false;
}
const dscString = traceState ? traceState.get(SENTRY_TRACE_STATE_DSC) : void 0;
const dsc = dscString ? baggageHeaderToDynamicSamplingContext(dscString) : void 0;
if (dsc?.sampled === "true") {
return true;
}
if (dsc?.sampled === "false") {
return false;
}
return void 0;
}
function inferSpanData(spanName, attributes, kind) {
const httpMethod = attributes[HTTP_REQUEST_METHOD] || attributes[HTTP_METHOD];
if (httpMethod) {
return descriptionForHttpMethod({ attributes, name: spanName, kind }, httpMethod);
}
const dbSystem = attributes[DB_SYSTEM_NAME] || attributes[DB_SYSTEM];
const opIsCache = typeof attributes[SEMANTIC_ATTRIBUTE_SENTRY_OP] === "string" && attributes[SEMANTIC_ATTRIBUTE_SENTRY_OP].startsWith("cache.");
if (dbSystem && !opIsCache) {
return descriptionForDbSystem({ attributes, name: spanName });
}
const customSourceOrRoute = attributes[SEMANTIC_ATTRIBUTE_SENTRY_SOURCE] === "custom" ? "custom" : "route";
const rpcService = attributes[RPC_SERVICE];
if (rpcService) {
return {
...getUserUpdatedNameAndSource(spanName, attributes, "route"),
op: "rpc"
};
}
const messagingSystem = attributes[MESSAGING_SYSTEM];
if (messagingSystem) {
return {
...getUserUpdatedNameAndSource(spanName, attributes, customSourceOrRoute),
op: "message"
};
}
const faasTrigger = attributes[FAAS_TRIGGER];
if (faasTrigger) {
return {
...getUserUpdatedNameAndSource(spanName, attributes, customSourceOrRoute),
op: faasTrigger.toString()
};
}
return { op: void 0, description: spanName, source: "custom" };
}
function parseSpanDescription(span) {
const attributes = spanHasAttributes(span) ? span.attributes : {};
const name = spanHasName(span) ? span.name : "<unknown>";
const kind = getSpanKind(span);
return inferSpanData(name, attributes, kind);
}
function descriptionForDbSystem({ attributes, name }) {
const userDefinedName = attributes[SEMANTIC_ATTRIBUTE_SENTRY_CUSTOM_SPAN_NAME];
if (typeof userDefinedName === "string") {
return {
op: "db",
description: userDefinedName,
source: attributes[SEMANTIC_ATTRIBUTE_SENTRY_SOURCE] || "custom"
};
}
if (attributes[SEMANTIC_ATTRIBUTE_SENTRY_SOURCE] === "custom") {
return { op: "db", description: name, source: "custom" };
}
const statement = attributes[DB_STATEMENT];
const description = statement ? statement.toString() : name;
return { op: "db", description, source: "task" };
}
function descriptionForHttpMethod({ name, kind, attributes }, httpMethod) {
const opParts = ["http"];
switch (kind) {
case SpanKind.CLIENT:
opParts.push("client");
break;
case SpanKind.SERVER:
opParts.push("server");
break;
}
if (attributes["sentry.http.prefetch"]) {
opParts.push("prefetch");
}
const { urlPath, url, query, fragment, hasRoute } = getSanitizedUrl(attributes, kind);
if (!urlPath) {
return { ...getUserUpdatedNameAndSource(name, attributes), op: opParts.join(".") };
}
const graphqlOperationsAttribute = attributes[SEMANTIC_ATTRIBUTE_SENTRY_GRAPHQL_OPERATION];
const baseDescription = `${httpMethod} ${urlPath}`;
const inferredDescription = graphqlOperationsAttribute ? `${baseDescription} (${getGraphqlOperationNamesFromAttribute(graphqlOperationsAttribute)})` : baseDescription;
const inferredSource = hasRoute || urlPath === "/" ? "route" : "url";
const data = {};
if (url) {
data.url = url;
}
if (query) {
data["http.query"] = query;
}
if (fragment) {
data["http.fragment"] = fragment;
}
const isClientOrServerKind = kind === SpanKind.CLIENT || kind === SpanKind.SERVER;
const origin = attributes[SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN] || "manual";
const isManualSpan = !`${origin}`.startsWith("auto");
const alreadyHasCustomSource = attributes[SEMANTIC_ATTRIBUTE_SENTRY_SOURCE] === "custom";
const customSpanName = attributes[SEMANTIC_ATTRIBUTE_SENTRY_CUSTOM_SPAN_NAME];
const useInferredDescription = !alreadyHasCustomSource && customSpanName == null && (isClientOrServerKind || !isManualSpan);
const { description, source } = useInferredDescription ? { description: inferredDescription, source: inferredSource } : getUserUpdatedNameAndSource(name, attributes);
return {
op: opParts.join("."),
description,
source,
data
};
}
function getGraphqlOperationNamesFromAttribute(attr) {
if (Array.isArray(attr)) {
const sorted = attr.slice().sort();
if (sorted.length <= 5) {
return sorted.join(", ");
} else {
return `${sorted.slice(0, 5).join(", ")}, +${sorted.length - 5}`;
}
}
return `${attr}`;
}
function getSanitizedUrl(attributes, kind) {
const httpTarget = attributes[HTTP_TARGET];
const httpUrl = attributes[HTTP_URL] || attributes[URL_FULL];
const httpRoute = attributes[HTTP_ROUTE];
const parsedUrl = typeof httpUrl === "string" ? parseUrl(httpUrl) : void 0;
const url = parsedUrl ? getSanitizedUrlString(parsedUrl) : void 0;
const query = parsedUrl?.search || void 0;
const fragment = parsedUrl?.hash || void 0;
if (typeof httpRoute === "string") {
return { urlPath: httpRoute, url, query, fragment, hasRoute: true };
}
if (kind === SpanKind.SERVER && typeof httpTarget === "string") {
return { urlPath: stripUrlQueryAndFragment(httpTarget), url, query, fragment, hasRoute: false };
}
if (parsedUrl) {
return { urlPath: url, url, query, fragment, hasRoute: false };
}
if (typeof httpTarget === "string") {
return { urlPath: stripUrlQueryAndFragment(httpTarget), url, query, fragment, hasRoute: false };
}
return { urlPath: void 0, url, query, fragment, hasRoute: false };
}
function getUserUpdatedNameAndSource(originalName, attributes, fallbackSource = "custom") {
const source = attributes[SEMANTIC_ATTRIBUTE_SENTRY_SOURCE] || fallbackSource;
const description = attributes[SEMANTIC_ATTRIBUTE_SENTRY_CUSTOM_SPAN_NAME];
if (description && typeof description === "string") {
return {
description,
source
};
}
return { description: originalName, source };
}
function enhanceDscWithOpenTelemetryRootSpanName(client) {
client.on("createDsc", (dsc, rootSpan) => {
if (!rootSpan) {
return;
}
const jsonSpan = spanToJSON(rootSpan);
const attributes = jsonSpan.data;
const source = attributes[SEMANTIC_ATTRIBUTE_SENTRY_SOURCE];
const { description } = spanHasName(rootSpan) ? parseSpanDescription(rootSpan) : { description: void 0 };
if (source !== "url" && description) {
dsc.transaction = description;
}
if (hasSpansEnabled()) {
const sampled = getSamplingDecision(rootSpan.spanContext());
dsc.sampled = sampled == void 0 ? void 0 : String(sampled);
}
});
}
function getActiveSpan() {
return trace.getActiveSpan();
}
class TraceState {
constructor() {
this._internalState = /* @__PURE__ */ new Map();
}
/** @inheritDoc */
set(key, value) {
const next = this._clone();
if (next._internalState.has(key)) {
next._internalState.delete(key);
}
next._internalState.set(key, value);
return next;
}
/** @inheritDoc */
unset(key) {
const next = this._clone();
next._internalState.delete(key);
return next;
}
/** @inheritDoc */
get(key) {
return this._internalState.get(key);
}
/** @inheritDoc */
serialize() {
return Array.from(this._internalState.keys()).reverse().map((key) => `${key}=${this._internalState.get(key)}`).join(",");
}
_clone() {
const next = new TraceState();
next._internalState = new Map(this._internalState);
return next;
}
}
function makeTraceState({
dsc,
sampled
}) {
const dscString = dsc ? dynamicSamplingContextToSentryBaggageHeader(dsc) : void 0;
const traceStateBase = new TraceState();
const traceStateWithDsc = dscString ? traceStateBase.set(SENTRY_TRACE_STATE_DSC, dscString) : traceStateBase;
return sampled === false ? traceStateWithDsc.set(SENTRY_TRACE_STATE_SAMPLED_NOT_RECORDING, "1") : traceStateWithDsc;
}
const setupElements = /* @__PURE__ */ new Set();
function openTelemetrySetupCheck() {
return Array.from(setupElements);
}
function setIsSetup(element) {
setupElements.add(element);
}
class SentryPropagator extends W3CBaggagePropagator {
constructor() {
super();
setIsSetup("SentryPropagator");
this._urlMatchesTargetsMap = new LRUMap(100);
}
/**
* @inheritDoc
*/
inject(context2, carrier, setter) {
if (isTracingSuppressed(context2)) {
DEBUG_BUILD && debug.log("[Tracing] Not injecting trace data for url because tracing is suppressed.");
return;
}
const activeSpan = trace.getSpan(context2);
const url = activeSpan && getCurrentURL(activeSpan);
const { tracePropagationTargets, propagateTraceparent } = getClient()?.getOptions() || {};
if (!shouldPropagateTraceForUrl(url, tracePropagationTargets, this._urlMatchesTargetsMap)) {
DEBUG_BUILD && debug.log("[Tracing] Not injecting trace data for url because it does not match tracePropagationTargets:", url);
return;
}
const existingBaggageHeader = getExistingBaggage(carrier);
const existingSentryTraceHeader = getExistingSentryTrace(carrier);
let baggage = propagation.getBaggage(context2) || propagation.createBaggage({});
const { dynamicSamplingContext, traceId, spanId, sampled } = getInjectionData(context2);
if (existingBaggageHeader) {
const baggageEntries = parseBaggageHeader(existingBaggageHeader);
if (baggageEntries) {
Object.entries(baggageEntries).forEach(([key, value]) => {
if (!existingSentryTraceHeader && key.startsWith(SENTRY_BAGGAGE_KEY_PREFIX)) {
return;
}
baggage = baggage.setEntry(key, { value });
});
}
}
if (!existingSentryTraceHeader && dynamicSamplingContext) {
baggage = Object.entries(dynamicSamplingContext).reduce((b, [dscKey, dscValue]) => {
if (dscValue) {
return b.setEntry(`${SENTRY_BAGGAGE_KEY_PREFIX}${dscKey}`, { value: dscValue });
}
return b;
}, baggage);
}
if (!existingSentryTraceHeader && traceId && traceId !== INVALID_TRACEID) {
setter.set(carrier, SENTRY_TRACE_HEADER, generateSentryTraceHeader(traceId, spanId, sampled));
if (propagateTraceparent) {
setter.set(carrier, "traceparent", generateTraceparentHeader(traceId, spanId, sampled));
}
}
super.inject(propagation.setBaggage(context2, baggage), carrier, setter);
}
/**
* @inheritDoc
*/
extract(context2, carrier, getter) {
const maybeSentryTraceHeader = getter.get(carrier, SENTRY_TRACE_HEADER);
const baggage = getter.get(carrier, SENTRY_BAGGAGE_HEADER);
const sentryTrace = maybeSentryTraceHeader ? Array.isArray(maybeSentryTraceHeader) ? maybeSentryTraceHeader[0] : maybeSentryTraceHeader : void 0;
return ensureScopesOnContext(getContextWithRemoteActiveSpan(context2, { sentryTrace, baggage }));
}
/**
* @inheritDoc
*/
fields() {
return [SENTRY_TRACE_HEADER, SENTRY_BAGGAGE_HEADER, "traceparent"];
}
}
function getInjectionData(context2, options = {}) {
const span = trace.getSpan(context2);
if (span?.spanContext().isRemote) {
const spanContext = span.spanContext();
const dynamicSamplingContext2 = getDynamicSamplingContextFromSpan(span);
return {
dynamicSamplingContext: dynamicSamplingContext2,
traceId: spanContext.traceId,
spanId: void 0,
sampled: getSamplingDecision(spanContext)
// TODO: Do we need to change something here?
};
}
if (span) {
const spanContext = span.spanContext();
const dynamicSamplingContext2 = getDynamicSamplingContextFromSpan(span);
return {
dynamicSamplingContext: dynamicSamplingContext2,
traceId: spanContext.traceId,
spanId: spanContext.spanId,
sampled: getSamplingDecision(spanContext)
// TODO: Do we need to change something here?
};
}
const scope = options.scope || getScopesFromContext(context2)?.scope || getCurrentScope();
const client = options.client || getClient();
const propagationContext = scope.getPropagationContext();
const dynamicSamplingContext = client ? getDynamicSamplingContextFromScope(client, scope) : void 0;
return {
dynamicSamplingContext,
traceId: propagationContext.traceId,
spanId: propagationContext.propagationSpanId,
sampled: propagationContext.sampled
};
}
function getContextWithRemoteActiveSpan(ctx, { sentryTrace, baggage }) {
const propagationContext = propagationContextFromHeaders(sentryTrace, baggage);
const { traceId, parentSpanId, sampled, dsc } = propagationContext;
const client = getClient();
const incomingDsc = baggageHeaderToDynamicSamplingContext(baggage);
if (!parentSpanId || client && !shouldContinueTrace(client, incomingDsc?.org_id)) {
return ctx;
}
const spanContext = generateRemoteSpanContext({
traceId,
spanId: parentSpanId,
sampled,
dsc
});
return trace.setSpanContext(ctx, spanContext);
}
function continueTraceAsRemoteSpan(ctx, options, callback) {
const ctxWithSpanContext = ensureScopesOnContext(getContextWithRemoteActiveSpan(ctx, options));
return context.with(ctxWithSpanContext, callback);
}
function ensureScopesOnContext(ctx) {
const scopes = getScopesFromContext(ctx);
const newScopes = {
// If we have no scope here, this is most likely either the root context or a context manually derived from it
// In this case, we want to fork the current scope, to ensure we do not pollute the root scope
scope: scopes ? scopes.scope : getCurrentScope().clone(),
isolationScope: scopes ? scopes.isolationScope : getIsolationScope()
};
return setScopesOnContext(ctx, newScopes);
}
function getExistingBaggage(carrier) {
try {
const baggage = carrier[SENTRY_BAGGAGE_HEADER];
return Array.isArray(baggage) ? baggage.join(",") : baggage;
} catch {
return void 0;
}
}
function getExistingSentryTrace(carrier) {
try {
return carrier[SENTRY_TRACE_HEADER];
} catch {
return void 0;
}
}
function getCurrentURL(span) {
const spanData = spanToJSON(span).data;
const urlAttribute = spanData[HTTP_URL] || spanData[URL_FULL];
if (typeof urlAttribute === "string") {
return urlAttribute;
}
const urlTraceState = span.spanContext().traceState?.get(SENTRY_TRACE_STATE_URL);
if (urlTraceState) {
return urlTraceState;
}
return void 0;
}
function generateRemoteSpanContext({
spanId,
traceId,
sampled,
dsc
}) {
const traceState = makeTraceState({
dsc,
sampled
});
const spanContext = {
traceId,
spanId,
isRemote: true,
traceFlags: sampled ? TraceFlags.SAMPLED : TraceFlags.NONE,
traceState
};
return spanContext;
}
function _startSpan(options, callback, autoEnd) {
const tracer = getTracer();
const { name, parentSpan: customParentSpan } = options;
const wrapper = getActiveSpanWrapper(customParentSpan);
return wrapper(() => {
const activeCtx = getContext(options.scope, options.forceTransaction);
const missingRequiredParent = options.onlyIfParent && !trace.getSpan(activeCtx);
const ctx = missingRequiredParent ? suppressTracing$1(activeCtx) : activeCtx;
if (missingRequiredParent) {
getClient()?.recordDroppedEvent("no_parent_span", "span");
}
const spanOptions = getSpanOptions(options);
if (!hasSpansEnabled()) {
const suppressedCtx = isTracingSuppressed(ctx) ? ctx : suppressTracing$1(ctx);
return context.with(suppressedCtx, () => {
return tracer.startActiveSpan(name, spanOptions, suppressedCtx, (span) => {
patchSpanEnd(span);
return context.with(activeCtx, () => {
return handleCallbackErrors(
() => callback(span),
() => {
if (spanToJSON(span).status === void 0) {
span.setStatus({ code: SpanStatusCode.ERROR });
}
},
autoEnd ? () => span.end() : void 0
);
});
});
});
}
return tracer.startActiveSpan(name, spanOptions, ctx, (span) => {
patchSpanEnd(span);
return handleCallbackErrors(
() => callback(span),
() => {
if (spanToJSON(span).status === void 0) {
span.setStatus({ code: SpanStatusCode.ERROR });
}
},
autoEnd ? () => span.end() : void 0
);
});
});
}
function startSpan(options, callback) {
return _startSpan(options, callback, true);
}
function startSpanManual(options, callback) {
return _startSpan(options, (span) => callback(span, () => span.end()), false);
}
function startInactiveSpan(options) {
const tracer = getTracer();
const { name, parentSpan: customParentSpan } = options;
const wrapper = getActiveSpanWrapper(customParentSpan);
return wrapper(() => {
const activeCtx = getContext(options.scope, options.forceTransaction);
const missingRequiredParent = options.onlyIfParent && !trace.getSpan(activeCtx);
let ctx = missingRequiredParent ? suppressTracing$1(activeCtx) : activeCtx;
if (missingRequiredParent) {
getClient()?.recordDroppedEvent("no_parent_span", "span");
}
const spanOptions = getSpanOptions(options);
if (!hasSpansEnabled()) {
ctx = isTracingSuppressed(ctx) ? ctx : suppressTracing$1(ctx);
}
const span = tracer.startSpan(name, spanOptions, ctx);
patchSpanEnd(span);
return span;
});
}
function withActiveSpan(span, callback) {
const newContextWithActiveSpan = span ? trace.setSpan(context.active(), span) : trace.deleteSpan(context.active());
return context.with(newContextWithActiveSpan, () => callback(getCurrentScope()));
}
function getTracer() {
const client = getClient();
return client?.tracer || trace.getTracer("@sentry/opentelemetry", SDK_VERSION);
}
function getSpanOptions(options) {
const { startTime, attributes, kind, op, links } = options;
const fixedStartTime = typeof startTime === "number" ? ensureTimestampInMilliseconds(startTime) : startTime;
return {
attributes: op ? {
[SEMANTIC_ATTRIBUTE_SENTRY_OP]: op,
...attributes
} : attributes,
kind,
links,
startTime: fixedStartTime
};
}
function ensureTimestampInMilliseconds(timestamp) {
const isMs = timestamp < 9999999999;
return isMs ? timestamp * 1e3 : timestamp;
}
function patchSpanEnd(span) {
const originalEnd = span.end.bind(span);
span.end = (endTime) => {
return originalEnd(typeof endTime === "number" ? ensureTimestampInMilliseconds(endTime) : endTime);
};
}
function getContext(scope, forceTransaction) {
const ctx = getContextForScope(scope);
const parentSpan = trace.getSpan(ctx);
if (!parentSpan) {
return ctx;
}
if (!forceTransaction) {
return ctx;
}
const ctxWithoutSpan = trace.deleteSpan(ctx);
const { spanId, traceId } = parentSpan.spanContext();
const sampled = getSamplingDecision(parentSpan.spanContext());
const rootSpan = getRootSpan(parentSpan);
const dsc = getDynamicSamplingContextFromSpan(rootSpan);
const traceState = makeTraceState({
dsc,
sampled
});
const spanOptions = {
traceId,
spanId,
isRemote: true,
traceFlags: sampled ? TraceFlags.SAMPLED : TraceFlags.NONE,
traceState
};
const ctxWithSpanContext = trace.setSpanContext(ctxWithoutSpan, spanOptions);
return ctxWithSpanContext;
}
function getContextForScope(scope) {
if (scope) {
const ctx = getContextFromScope(scope);
if (ctx) {
return ctx;
}
}
return context.active();
}
function continueTrace(options, callback) {
return continueTraceAsRemoteSpan(context.active(), options, callback);
}
function startNewTrace(callback) {
const traceId = generateTraceId();
const spanId = generateSpanId();
const spanContext = {
traceId,
spanId,
isRemote: true,
traceFlags: TraceFlags.NONE
};
const ctxWithTrace = trace.setSpanContext(context.active(), spanContext);
return context.with(ctxWithTrace, () => {
getCurrentScope().setPropagationContext({
traceId,
sampleRand: _INTERNAL_safeMathRandom()
});
return callback();
});
}
function getTraceContextForScope(client, scope) {
const ctx = getContextFromScope(scope);
const span = ctx && trace.getSpan(ctx);
const traceContext = span ? spanToTraceContext(span) : getTraceContextFromScope(scope);
const dynamicSamplingContext = span ? getDynamicSamplingContextFromSpan(span) : getDynamicSamplingContextFromScope(client, scope);
return [dynamicSamplingContext, traceContext];
}
function getActiveSpanWrapper(parentSpan) {
return parentSpan !== void 0 ? (callback) => {
return withActiveSpan(parentSpan, callback);
} : (callback) => callback();
}
function suppressTracing(callback) {
const ctx = suppressTracing$1(context.active());
return context.with(ctx, callback);
}
function setupEventContextTrace(client) {
client.on("preprocessEvent", (event) => {
const span = getActiveSpan();
if (!span || event.type === "transaction") {
return;
}
event.contexts = {
trace: spanToTraceContext(span),
...event.contexts
};
const rootSpan = getRootSpan(span);
event.sdkProcessingMetadata = {
dynamicSamplingContext: getDynamicSamplingContextFromSpan(rootSpan),
...event.sdkProcessingMetadata
};
return event;
});
}
function getTraceData({
span,
scope,
client,
propagateTraceparent
} = {}) {
let ctx = (scope && getContextFromScope(scope)) ?? api.context.active();
if (span) {
const { scope: scope2 } = getCapturedScopesOnSpan(span);
ctx = scope2 && getContextFromScope(scope2) || api.trace.setSpan(api.context.active(), span);
}
const { traceId, spanId, sampled, dynamicSamplingContext } = getInjectionData(ctx, { scope, client });
const traceData = {
"sentry-trace": generateSentryTraceHeader(traceId, spanId, sampled),
baggage: dynamicSamplingContextToSentryBaggageHeader(dynamicSamplingContext)
};
if (propagateTraceparent) {
traceData.traceparent = generateTraceparentHeader(traceId, spanId, sampled);
}
return traceData;
}
function setOpenTelemetryContextAsyncContextStrategy() {
function getScopes() {
const ctx = api.context.active();
const scopes = getScopesFromContext(ctx);
if (scopes) {
return scopes;
}
return {
scope: getDefaultCurrentScope(),
isolationScope: getDefaultIsolationScope()
};
}
function withScope(callback) {
const ctx = api.context.active();
return api.context.with(ctx, () => {
return callback(getCurrentScope());
});
}
function withSetScope(scope, callback) {
const ctx = getContextFromScope(scope) || api.context.active();
return api.context.with(ctx.setValue(SENTRY_FORK_SET_SCOPE_CONTEXT_KEY, scope), () => {
return callback(scope);
});
}
function withIsolationScope(callback) {
const ctx = api.context.active();
return api.context.with(ctx.setValue(SENTRY_FORK_ISOLATION_SCOPE_CONTEXT_KEY, true), () => {
return callback(getIsolationScope());
});
}
function withSetIsolationScope(isolationScope, callback) {
const ctx = api.context.active();
return api.context.with(ctx.setValue(SENTRY_FORK_SET_ISOLATION_SCOPE_CONTEXT_KEY, isolationScope), () => {
return callback(getIsolationScope());
});
}
function getCurrentScope() {
return getScopes().scope;
}
function getIsolationScope() {
return getScopes().isolationScope;
}
setAsyncContextStrategy({
withScope,
withSetScope,
withSetIsolationScope,
withIsolationScope,
getCurrentScope,
getIsolationScope,
startSpan,
startSpanManual,
startInactiveSpan,
getActiveSpan,
suppressTracing,
getTraceData,
continueTrace,
startNewTrace,
// The types here don't fully align, because our own `Span` type is narrower
// than the OTEL one - but this is OK for here, as we now we'll only have OTEL spans passed around
withActiveSpan
});
}
function buildContextWithSentryScopes(context, activeContext) {
const span = trace.getSpan(context);
let effectiveContext;
if (span?.spanContext().traceState?.get(SENTRY_TRACE_STATE_CHILD_IGNORED) === "1") {
const contextWithoutSpan = trace.deleteSpan(context);
const parentSpan = trace.getSpan(activeContext);
effectiveContext = parentSpan ? trace.setSpan(contextWithoutSpan, parentSpan) : contextWithoutSpan;
} else {
effectiveContext = context;
}
const currentScopes = getScopesFromContext(effectiveContext);
const currentScope = currentScopes?.scope || getCurrentScope();
const currentIsolationScope = currentScopes?.isolationScope || getIsolationScope();
const shouldForkIsolationScope = effectiveContext.getValue(SENTRY_FORK_ISOLATION_SCOPE_CONTEXT_KEY) === true;
const scope = effectiveContext.getValue(SENTRY_FORK_SET_SCOPE_CONTEXT_KEY);
const isolationScope = effectiveContext.getValue(SENTRY_FORK_SET_ISOLATION_SCOPE_CONTEXT_KEY);
const newCurrentScope = scope || currentScope.clone();
const newIsolationScope = isolationScope || (shouldForkIsolationScope ? currentIsolationScope.clone() : currentIsolationScope);
const scopes = { scope: newCurrentScope, isolationScope: newIsolationScope };
const ctx1 = setScopesOnContext(effectiveContext, scopes);
const ctx2 = ctx1.deleteValue(SENTRY_FORK_ISOLATION_SCOPE_CONTEXT_KEY).deleteValue(SENTRY_FORK_SET_SCOPE_CONTEXT_KEY).deleteValue(SENTRY_FORK_SET_ISOLATION_SCOPE_CONTEXT_KEY);
setContextOnScope(newCurrentScope, ctx2);
return ctx2;
}
function wrapContextManagerClass(ContextManagerClass) {
class SentryContextManager extends ContextManagerClass {
constructor(...args) {
super(...args);
setIsSetup("SentryContextManager");
}
/**
* Overwrite with() of the original AsyncLocalStorageContextManager
* to ensure we also create new scopes per context.
*/
with(context, fn, thisArg, ...args) {
const ctx2 = buildContextWithSentryScopes(context, this.active());
return super.with(ctx2, fn, thisArg, ...args);
}
/**
* Gets underlying AsyncLocalStorage and symbol to allow lookup of scope.
*/
getAsyncLocalStorageLookup() {
return {
// @ts-expect-error This is on the base class, but not part of the interface
asyncLocalStorage: this._asyncLocalStorage,
contextSymbol: SENTRY_SCOPES_CONTEXT_KEY
};
}
}
return SentryContextManager;
}
function groupSpansWithParents(spans) {
const nodeMap = /* @__PURE__ */ new Map();
for (const span of spans) {
createOrUpdateSpanNodeAndRefs(nodeMap, span);
}
return Array.from(nodeMap, function([_id, spanNode]) {
return spanNode;
});
}
function getLocalParentId(span) {
const parentIsRemote = span.attributes[SEMANTIC_ATTRIBUTE_SENTRY_PARENT_IS_REMOTE] === true;
return !parentIsRemote ? getParentSpanId(span) : void 0;
}
function createOrUpdateSpanNodeAndRefs(nodeMap, span) {
const id = span.spanContext().spanId;
const parentId = getLocalParentId(span);
if (!parentId) {
createOrUpdateNode(nodeMap, { id, span, children: [] });
return;
}
const parentNode = createOrGetParentNode(nodeMap, parentId);
const node = createOrUpdateNode(nodeMap, { id, span, parentNode, children: [] });
parentNode.children.push(node);
}
function createOrGetParentNode(nodeMap, id) {
const existing = nodeMap.get(id);
if (existing) {
return existing;
}
return createOrUpdateNode(nodeMap, { id, children: [] });
}
function createOrUpdateNode(nodeMap, spanNode) {
const existing = nodeMap.get(spanNode.id);
if (existing?.span) {
return existing;
}
if (existing && !existing.span) {
existing.span = spanNode.span;
existing.parentNode = spanNode.parentNode;
return existing;
}
nodeMap.set(spanNode.id, spanNode);
return spanNode;
}
const canonicalGrpcErrorCodesMap = {
"1": "cancelled",
"2": "unknown_error",
"3": "invalid_argument",
"4": "deadline_exceeded",
"5": "not_found",
"6": "already_exists",
"7": "permission_denied",
"8": "resource_exhausted",
"9": "failed_precondition",
"10": "aborted",
"11": "out_of_range",
"12": "unimplemented",
"13": "internal_error",
"14": "unavailable",
"15": "data_loss",
"16": "unauthenticated"
};
const isStatusErrorMessageValid = (message) => {
return Object.values(canonicalGrpcErrorCodesMap).includes(message);
};
function mapStatus(span) {
const attributes = spanHasAttributes(span) ? span.attributes : {};
const status = spanHasStatus(span) ? span.status : void 0;
if (status) {
if (status.code === SpanStatusCode.OK) {
return { code: SPAN_STATUS_OK };
} else if (status.code === SpanStatusCode.ERROR) {
if (typeof status.message === "undefined") {
const inferredStatus2 = inferStatusFromAttributes(attributes);
if (inferredStatus2) {
return inferredStatus2;
}
}
if (status.message && isStatusErrorMessageValid(status.message)) {
return { code: SPAN_STATUS_ERROR, message: status.message };
} else {
return { code: SPAN_STATUS_ERROR, message: "internal_error" };
}
}
}
const inferredStatus = inferStatusFromAttributes(attributes);
if (inferredStatus) {
return inferredStatus;
}
if (status?.code === SpanStatusCode.UNSET) {
return { code: SPAN_STATUS_OK };
} else {
return { code: SPAN_STATUS_ERROR, message: "unknown_error" };
}
}
function inferStatusFromAttributes(attributes) {
const httpCodeAttribute = attributes[HTTP_RESPONSE_STATUS_CODE] || attributes[HTTP_STATUS_CODE];
const grpcCodeAttribute = attributes[RPC_GRPC_STATUS_CODE];
const numberHttpCode = typeof httpCodeAttribute === "number" ? httpCodeAttribute : typeof httpCodeAttribute === "string" ? parseInt(httpCodeAttribute) : void 0;
if (typeof numberHttpCode === "number") {
return getSpanStatusFromHttpCode(numberHttpCode);
}
if (typeof grpcCodeAttribute === "string") {
return { code: SPAN_STATUS_ERROR, message: canonicalGrpcErrorCodesMap[grpcCodeAttribute] || "unknown_error" };
}
return void 0;
}
const MAX_SPAN_COUNT = 1e3;
const DEFAULT_TIMEOUT = 300;
const SENT_SPANS_MAX_SIZE = 1e4;
class SentrySpanExporter {
constructor(options) {
this._finishedSpanBucketSize = options?.timeout || DEFAULT_TIMEOUT;
this._finishedSpanBuckets = new Array(this._finishedSpanBucketSize).fill(void 0);
this._lastCleanupTimestampInS = Math.floor(_INTERNAL_safeDateNow() / 1e3);
this._spansToBucketEntry = /* @__PURE__ */ new WeakMap();
this._sentSpans = new LRUMap(SENT_SPANS_MAX_SIZE);
this._debouncedFlush = debounce(this.flush.bind(this), 1, { maxWait: 100 });
}
/**
* Export a single span.
* This is called by the span processor whenever a span is ended.
*/
export(span) {
const currentTimestampInS = Math.floor(_INTERNAL_safeDateNow() / 1e3);
if (this._lastCleanupTimestampInS !== currentTimestampInS) {
let droppedSpanCount = 0;
this._finishedSpanBuckets.forEach((bucket, i) => {
if (bucket && bucket.timestampInS <= currentTimestampInS - this._finishedSpanBucketSize) {
droppedSpanCount += bucket.spans.size;
this._finishedSpanBuckets[i] = void 0;
}
});
if (droppedSpanCount > 0) {
DEBUG_BUILD && debug.log(
`SpanExporter dropped ${droppedSpanCount} spans because they were pending for more than ${this._finishedSpanBucketSize} seconds.`
);
}
this._lastCleanupTimestampInS = currentTimestampInS;
}
const currentBucketIndex = currentTimestampInS % this._finishedSpanBucketSize;
const currentBucket = this._finishedSpanBuckets[currentBucketIndex] || {
timestampInS: currentTimestampInS,
spans: /* @__PURE__ */ new Set()
};
this._finishedSpanBuckets[currentBucketIndex] = currentBucket;
currentBucket.spans.add(span);
this._spansToBucketEntry.set(span, currentBucket);
const localParentId = getLocalParentId(span);
if (!localParentId || this._sentSpans.get(localParentId)) {
this._debouncedFlush();
}
}
/**
* Try to flush any pending spans immediately.
* This is called internally by the exporter (via _debouncedFlush),
* but can also be triggered externally if we force-flush.
*/
flush() {
const finishedSpans = this._finishedSpanBuckets.flatMap((bucket) => bucket ? Array.from(bucket.spans) : []);
const sentSpans = this._maybeSend(finishedSpans);
const sentSpanCount = sentSpans.size;
const remainingOpenSpanCount = finishedSpans.length - sentSpanCount;
DEBUG_BUILD && debug.log(
`SpanExporter exported ${sentSpanCount} spans, ${remainingOpenSpanCount} spans are waiting for their parent spans to finish`
);
for (const span of sentSpans) {
this._sentSpans.set(span.spanContext().spanId, 1);
const bucketEntry = this._spansToBucketEntry.get(span);
if (bucketEntry) {
bucketEntry.spans.delete(span);
}
}
this._debouncedFlush.cancel();
}
/**
* Clear the exporter.
* This is called when the span processor is shut down.
*/
clear() {
this._finishedSpanBuckets = this._finishedSpanBuckets.fill(void 0);
this._sentSpans.clear();
this._debouncedFlush.cancel();
}
/**
* Send the given spans, but only if they are part of a finished transaction.
*
* Returns the sent spans.
* Spans remain unsent when their parent span is not yet finished.
* This will happen regularly, as child spans are generally finished before their parents.
* But it _could_ also happen because, for whatever reason, a parent span was lost.
* In this case, we'll eventually need to clean this up.
*/
_maybeSend(spans) {
const grouped = groupSpansWithParents(spans);
const sentSpans = /* @__PURE__ */ new Set();
const rootNodes = this._getCompletedRootNodes(grouped);
for (const root of rootNodes) {
const span = root.span;
sentSpans.add(span);
const transactionEvent = createTransactionForOtelSpan(span);
if (root.parentNode && this._sentSpans.get(root.parentNode.id)) {
const traceData = transactionEvent.contexts?.trace?.data;
if (traceData) {
traceData["sentry.parent_span_already_sent"] = true;
}
}
const spans2 = transactionEvent.spans || [];
let hasGenAiSpans = false;
for (const child of root.children) {
if (createAndFinishSpanForOtelSpan(child, spans2, sentSpans)) {
hasGenAiSpans = true;
}
}
transactionEvent.spans = spans2.length > MAX_SPAN_COUNT ? spans2.sort((a, b) => a.start_timestamp - b.start_timestamp).slice(0, MAX_SPAN_COUNT) : spans2;
if (hasGenAiSpans) {
transactionEvent.sdkProcessingMetadata = {
...transactionEvent.sdkProcessingMetadata,
hasGenAiSpans: true
};
}
const measurements = timedEventsToMeasurements(span.events);
if (measurements) {
transactionEvent.measurements = measurements;
}
captureEvent(transactionEvent);
}
return sentSpans;
}
/** Check if a node is a completed root node or a node whose parent has already been sent */
_nodeIsCompletedRootNodeOrHasSentParent(node) {
return !!node.span && (!node.parentNode || !!this._sentSpans.get(node.parentNode.id));
}
/** Get all completed root nodes from a list of nodes */
_getCompletedRootNodes(nodes) {
return nodes.filter((node) => this._nodeIsCompletedRootNodeOrHasSentParent(node));
}
}
function parseSpan(span) {
const attributes = span.attributes;
const origin = attributes[SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN];
const op = attributes[SEMANTIC_ATTRIBUTE_SENTRY_OP];
const source = attributes[SEMANTIC_ATTRIBUTE_SENTRY_SOURCE];
return { origin, op, source };
}
function createTransactionForOtelSpan(span) {
const { op, description, data, origin = "manual", source } = getSpanData(span);
const capturedSpanScopes = getCapturedScopesOnSpan(span);
const sampleRate = span.attributes[SEMANTIC_ATTRIBUTE_SENTRY_SAMPLE_RATE];
const attributes = {
[SEMANTIC_ATTRIBUTE_SENTRY_SOURCE]: source,
[SEMANTIC_ATTRIBUTE_SENTRY_SAMPLE_RATE]: sampleRate,
[SEMANTIC_ATTRIBUTE_SENTRY_OP]: op,
[SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: origin,
...data,
...removeSentryAttributes(span.attributes)
};
const { links } = span;
const { traceId: trace_id, spanId: span_id } = span.spanContext();
const parent_span_id = getParentSpanId(span);
const status = mapStatus(span);
const traceContext = {
parent_span_id,
span_id,
trace_id,
data: attributes,
origin,
op,
status: getStatusMessage(status),
// As per protocol, span status is allowed to be undefined
links: convertSpanLinksForEnvelope(links)
};
const statusCode = attributes[HTTP_RESPONSE_STATUS_CODE];
const responseContext = typeof statusCode === "number" ? { response: { status_code: statusCode } } : void 0;
const transactionEvent = {
contexts: {
trace: traceContext,
otel: {
resource: span.resource.attributes
},
...responseContext
},
spans: [],
start_timestamp: spanTimeInputToSeconds(span.startTime),
timestamp: spanTimeInputToSeconds(span.endTime),
transaction: description,
type: "transaction",
sdkProcessingMetadata: {
capturedSpanScope: capturedSpanScopes.scope,
capturedSpanIsolationScope: capturedSpanScopes.isolationScope,
sampleRate,
dynamicSamplingContext: getDynamicSamplingContextFromSpan(span)
},
...source && {
transaction_info: {
source
}
}
};
return transactionEvent;
}
function createAndFinishSpanForOtelSpan(node, spans, sentSpans) {
const span = node.span;
if (span) {
sentSpans.add(span);
}
const shouldDrop = !span;
if (shouldDrop) {
let hasGenAiSpans2 = false;
node.children.forEach((child) => {
if (createAndFinishSpanForOtelSpan(child, spans, sentSpans)) {
hasGenAiSpans2 = true;
}
});
return hasGenAiSpans2;
}
const span_id = span.spanContext().spanId;
const trace_id = span.spanContext().traceId;
const parentSpanId = getParentSpanId(span);
const { attributes, startTime, endTime, links } = span;
const { op, description, data, origin = "manual" } = getSpanData(span);
const allData = {
[SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: origin,
[SEMANTIC_ATTRIBUTE_SENTRY_OP]: op,
...removeSentryAttributes(attributes),
...data
};
const status = mapStatus(span);
const spanJSON = {
span_id,
trace_id,
data: allData,
description,
parent_span_id: parentSpanId,
start_timestamp: spanTimeInputToSeconds(startTime),
// This is [0,0] by default in OTEL, in which case we want to interpret this as no end time
timestamp: spanTimeInputToSeconds(endTime) || void 0,
status: getStatusMessage(status),
// As per protocol, span status is allowed to be undefined
op,
origin,
measurements: timedEventsToMeasurements(span.events),
links: convertSpanLinksForEnvelope(links)
};
spans.push(spanJSON);
let hasGenAiSpans = !!op?.startsWith("gen_ai.");
node.children.forEach((child) => {
if (createAndFinishSpanForOtelSpan(child, spans, sentSpans)) {
hasGenAiSpans = true;
}
});
return hasGenAiSpans;
}
function getSpanData(span) {
const { op: definedOp, source: definedSource, origin } = parseSpan(span);
const { op: inferredOp, description, source: inferredSource, data: inferredData } = parseSpanDescription(span);
const op = definedOp || inferredOp;
const source = definedSource || inferredSource;
const data = { ...inferredData, ...getData(span) };
return {
op,
description,
source,
origin,
data
};
}
function removeSentryAttributes(data) {
const cleanedData = { ...data };
delete cleanedData[SEMANTIC_ATTRIBUTE_SENTRY_SAMPLE_RATE];
delete cleanedData[SEMANTIC_ATTRIBUTE_SENTRY_PARENT_IS_REMOTE];
delete cleanedData[SEMANTIC_ATTRIBUTE_SENTRY_CUSTOM_SPAN_NAME];
return cleanedData;
}
function getData(span) {
const attributes = span.attributes;
const data = {};
if (span.kind !== SpanKind.INTERNAL) {
data["otel.kind"] = SpanKind[span.kind];
}
const maybeHttpStatusCodeAttribute = attributes[HTTP_STATUS_CODE];
if (maybeHttpStatusCodeAttribute) {
data[HTTP_RESPONSE_STATUS_CODE] = maybeHttpStatusCodeAttribute;
}
const requestData = getRequestSpanData(span);
if (requestData.url) {
data.url = requestData.url;
}
if (requestData["http.query"]) {
data["http.query"] = requestData["http.query"].slice(1);
}
if (requestData["http.fragment"]) {
data["http.fragment"] = requestData["http.fragment"].slice(1);
}
return data;
}
class SentrySpanProcessor {
constructor(options) {
this._unsubscribePreprocessSpan = void 0;
setIsSetup("SentrySpanProcessor");
this._exporter = new SentrySpanExporter(options);
this._client = options?.client ?? getClient();
if (this._client && hasSpanStreamingEnabled(this._client)) {
this._unsubscribePreprocessSpan = this._client.on("preprocessSpan", backfillStreamedSpanDataFromOtel);
}
}
/**
* @inheritDoc
*/
async forceFlush() {
this._exporter.flush();
}
/**
* @inheritDoc
*/
async shutdown() {
this._unsubscribePreprocessSpan?.();
this._exporter.clear();
}
/**
* @inheritDoc
*/
onStart(span, parentContext) {
const parentSpan = trace.getSpan(parentContext);
let scopes = getScopesFromContext(parentContext);
if (parentSpan && !parentSpan.spanContext().isRemote) {
addChildSpanToSpan(parentSpan, span);
}
if (parentSpan?.spanContext().isRemote) {
span.setAttribute(SEMANTIC_ATTRIBUTE_SENTRY_PARENT_IS_REMOTE, true);
}
if (parentContext === ROOT_CONTEXT) {
scopes = {
scope: getDefaultCurrentScope(),
isolationScope: getDefaultIsolationScope()
};
}
if (scopes) {
setCapturedScopesOnSpan(span, scopes.scope, scopes.isolationScope);
}
logSpanStart(span);
this._client?.emit("spanStart", span);
}
/** @inheritDoc */
onEnd(span) {
logSpanEnd(span);
this._client?.emit("spanEnd", span);
if (this._client && hasSpanStreamingEnabled(this._client)) {
this._client.emit("afterSpanEnd", span);
} else {
this._exporter.export(span);
}
}
}
function backfillStreamedSpanDataFromOtel(spanJSON, hint) {
const attributes = spanJSON.attributes;
if (!attributes) {
return;
}
const kind = hint?.spanKind ?? SpanKind.INTERNAL;
const { op, description, source, data } = inferSpanData(spanJSON.name, attributes, kind);
spanJSON.name = description;
safeSetSpanJSONAttributes(spanJSON, {
[SEMANTIC_ATTRIBUTE_SENTRY_OP]: op,
[SEMANTIC_ATTRIBUTE_SENTRY_SOURCE]: source,
...data
});
if (kind !== SpanKind.INTERNAL) {
safeSetSpanJSONAttributes(spanJSON, {
"otel.kind": SpanKind[kind]
});
}
}
class SentrySampler {
constructor(client) {
this._client = client;
this._isSpanStreaming = hasSpanStreamingEnabled(client);
setIsSetup("SentrySampler");
}
/** @inheritDoc */
shouldSample(context, traceId, spanName, spanKind, spanAttributes, _links) {
const options = this._client.getOptions();
const { ignoreSpans } = options;
const parentSpan = getValidSpan(context);
const parentContext = parentSpan?.spanContext();
if (!hasSpansEnabled(options)) {
return wrapSamplingDecision({ decision: void 0, context, spanAttributes });
}
const maybeSpanHttpMethod = spanAttributes[HTTP_METHOD] || spanAttributes[HTTP_REQUEST_METHOD];
if (spanKind === SpanKind.CLIENT && maybeSpanHttpMethod && (!parentSpan || parentContext?.isRemote)) {
if (!this._isSpanStreaming) {
this._client.recordDroppedEvent("no_parent_span", "span");
return wrapSamplingDecision({ decision: void 0, context, spanAttributes });
}
}
const parentSampled = parentSpan ? getParentSampled(parentSpan, traceId, spanName) : void 0;
const isRootSpan = !parentSpan || parentContext?.isRemote;
if (!isRootSpan) {
if (this._isSpanStreaming) {
if (parentSampled) {
if (ignoreSpans?.length) {
const { description: inferredChildName, op: childOp } = inferSpanData(spanName, spanAttributes, spanKind);
if (shouldIgnoreSpan(
{
description: inferredChildName,
op: spanAttributes[SEMANTIC_ATTRIBUTE_SENTRY_OP] ?? childOp,
attributes: spanAttributes
},
ignoreSpans
)) {
this._client.recordDroppedEvent("ignored", "span");
return wrapSamplingDecision({
decision: SamplingDecision.NOT_RECORD,
context,
spanAttributes,
ignoredChildSpan: true
});
}
}
}
if (!parentSampled) {
const parentSegmentIgnored = parentContext?.traceState?.get(SENTRY_TRACE_STATE_SEGMENT_IGNORED) === "1";
this._client.recordDroppedEvent(parentSegmentIgnored ? "ignored" : "sample_rate", "span");
}
}
return wrapSamplingDecision({
decision: parentSampled ? SamplingDecision.RECORD_AND_SAMPLED : SamplingDecision.NOT_RECORD,
context,
spanAttributes
});
}
const {
description: inferredSpanName,
data: inferredAttributes,
op
} = inferSpanData(spanName, spanAttributes, spanKind);
const mergedAttributes = {
...inferredAttributes,
...spanAttributes
};
if (op) {
mergedAttributes[SEMANTIC_ATTRIBUTE_SENTRY_OP] = op;
}
if (this._isSpanStreaming && ignoreSpans?.length && shouldIgnoreSpan(
{
description: inferredSpanName,
op: mergedAttributes[SEMANTIC_ATTRIBUTE_SENTRY_OP] ?? op,
attributes: mergedAttributes
},
ignoreSpans
)) {
this._client.recordDroppedEvent("ignored", "span");
return wrapSamplingDecision({
decision: SamplingDecision.NOT_RECORD,
context,
spanAttributes,
ignoredSegmentSpan: true
});
}
const mutableSamplingDecision = { decision: true };
this._client.emit(
"beforeSampling",
{
spanAttributes: mergedAttributes,
spanName: inferredSpanName,
parentSampled,
parentContext
},
mutableSamplingDecision
);
if (!mutableSamplingDecision.decision) {
return wrapSamplingDecision({ decision: void 0, context, spanAttributes });
}
const { isolationScope } = getScopesFromContext(context) ?? {};
const dscString = parentContext?.traceState ? parentContext.traceState.get(SENTRY_TRACE_STATE_DSC) : void 0;
const dsc = dscString ? baggageHeaderToDynamicSamplingContext(dscString) : void 0;
const sampleRand = parseSampleRate(dsc?.sample_rand) ?? _INTERNAL_safeMathRandom();
const [sampled, sampleRate, localSampleRateWasApplied] = sampleSpan(
options,
{
name: inferredSpanName,
attributes: mergedAttributes,
normalizedRequest: isolationScope?.getScopeData().sdkProcessingMetadata.normalizedRequest,
parentSampled,
parentSampleRate: parseSampleRate(dsc?.sample_rate)
},
sampleRand
);
const method = `${maybeSpanHttpMethod}`.toUpperCase();
if (method === "OPTIONS" || method === "HEAD") {
DEBUG_BUILD && debug.log(`[Tracing] Not sampling span because HTTP method is '${method}' for ${spanName}`);
return wrapSamplingDecision({
decision: SamplingDecision.NOT_RECORD,
context,
spanAttributes,
sampleRand,
downstreamTraceSampleRate: 0
// we don't want to sample anything in the downstream trace either
});
}
if (!sampled && // We check for `parentSampled === undefined` because we only want to record client reports for spans that are trace roots (ie. when there was incoming trace)
parentSampled === void 0) {
DEBUG_BUILD && debug.log("[Tracing] Discarding root span because its trace was not chosen to be sampled.");
this._client.recordDroppedEvent("sample_rate", this._isSpanStreaming ? "span" : "transaction");
}
return {
...wrapSamplingDecision({
decision: sampled ? SamplingDecision.RECORD_AND_SAMPLED : SamplingDecision.NOT_RECORD,
context,
spanAttributes,
sampleRand,
downstreamTraceSampleRate: localSampleRateWasApplied ? sampleRate : void 0
}),
attributes: {
// We set the sample rate on the span when a local sample rate was applied to better understand how traces were sampled in Sentry
[SEMANTIC_ATTRIBUTE_SENTRY_SAMPLE_RATE]: localSampleRateWasApplied ? sampleRate : void 0
}
};
}
/** Returns the sampler name or short description with the configuration. */
toString() {
return "SentrySampler";
}
}
function getParentSampled(parentSpan, traceId, spanName) {
const parentContext = parentSpan.spanContext();
if (isSpanContextValid(parentContext) && parentContext.traceId === traceId) {
if (parentContext.isRemote) {
const parentSampled2 = getSamplingDecision(parentSpan.spanContext());
DEBUG_BUILD && debug.log(`[Tracing] Inheriting remote parent's sampled decision for ${spanName}: ${parentSampled2}`);
return parentSampled2;
}
const parentSampled = getSamplingDecision(parentContext);
DEBUG_BUILD && debug.log(`[Tracing] Inheriting parent's sampled decision for ${spanName}: ${parentSampled}`);
return parentSampled;
}
return void 0;
}
function wrapSamplingDecision({
decision,
context,
spanAttributes,
sampleRand,
downstreamTraceSampleRate,
ignoredChildSpan,
ignoredSegmentSpan
}) {
let traceState = getBaseTraceState(context, spanAttributes);
if (downstreamTraceSampleRate !== void 0) {
traceState = traceState.set(SENTRY_TRACE_STATE_SAMPLE_RATE, `${downstreamTraceSampleRate}`);
}
if (sampleRand !== void 0) {
traceState = traceState.set(SENTRY_TRACE_STATE_SAMPLE_RAND, `${sampleRand}`);
}
if (ignoredChildSpan) {
traceState = traceState.set(SENTRY_TRACE_STATE_CHILD_IGNORED, "1");
}
if (ignoredSegmentSpan) {
traceState = traceState.set(SENTRY_TRACE_STATE_SEGMENT_IGNORED, "1");
}
if (decision == void 0) {
return { decision: SamplingDecision.NOT_RECORD, traceState };
}
if (decision === SamplingDecision.NOT_RECORD) {
return { decision, traceState: traceState.set(SENTRY_TRACE_STATE_SAMPLED_NOT_RECORDING, "1") };
}
return { decision, traceState };
}
function getBaseTraceState(context, spanAttributes) {
const parentSpan = trace.getSpan(context);
const parentContext = parentSpan?.spanContext();
let traceState = parentContext?.traceState || new TraceState();
const url = spanAttributes[HTTP_URL] || spanAttributes[URL_FULL];
if (url && typeof url === "string") {
traceState = traceState.set(SENTRY_TRACE_STATE_URL, url);
}
return traceState;
}
function getValidSpan(context) {
const span = trace.getSpan(context);
return span && isSpanContextValid(span.spanContext()) ? span : void 0;
}
const ATTR_TELEMETRY_SDK_LANGUAGE = "telemetry.sdk.language";
const ATTR_TELEMETRY_SDK_NAME = "telemetry.sdk.name";
const ATTR_TELEMETRY_SDK_VERSION = "telemetry.sdk.version";
const SEMRESATTRS_SERVICE_NAMESPACE = "service.namespace";
class SentryResource {
constructor(attributes) {
this._attributes = attributes;
}
get attributes() {
return this._attributes;
}
merge(other) {
if (!other) {
return this;
}
return new SentryResource({ ...this._attributes, ...other.attributes });
}
getRawAttributes() {
return Object.entries(this._attributes);
}
}
function parseOtelResourceAttributes(raw) {
if (!raw) {
return {};
}
const result = {};
for (const pair of raw.split(",")) {
const eq = pair.indexOf("=");
if (eq === -1) {
continue;
}
const key = pair.substring(0, eq).trim();
const value = pair.substring(eq + 1).trim();
if (key) {
try {
result[key] = decodeURIComponent(value);
} catch {
result[key] = value;
}
}
}
return result;
}
function getSentryResource(serviceNameFallback) {
const env = typeof process !== "undefined" ? process.env : {};
const otelServiceName = env.OTEL_SERVICE_NAME;
const otelResourceAttrs = parseOtelResourceAttributes(env.OTEL_RESOURCE_ATTRIBUTES);
return new SentryResource({
// Lowest priority: Sentry defaults
// eslint-disable-next-line typescript/no-deprecated
[SEMRESATTRS_SERVICE_NAMESPACE]: "sentry",
[SERVICE_NAME]: serviceNameFallback,
// OTEL_RESOURCE_ATTRIBUTES overrides defaults (including service.name and service.namespace)
...otelResourceAttrs,
// OTEL_SERVICE_NAME explicitly overrides service.name
...otelServiceName ? { [SERVICE_NAME]: otelServiceName } : {},
// Highest priority: Sentry SDK telemetry attrs (cannot be overridden by env vars)
[SERVICE_VERSION]: SDK_VERSION,
[ATTR_TELEMETRY_SDK_LANGUAGE]: SDK_INFO[ATTR_TELEMETRY_SDK_LANGUAGE],
[ATTR_TELEMETRY_SDK_NAME]: SDK_INFO[ATTR_TELEMETRY_SDK_NAME],
[ATTR_TELEMETRY_SDK_VERSION]: SDK_INFO[ATTR_TELEMETRY_SDK_VERSION]
});
}
export { startSpanManual as A, suppressTracing as B, withActiveSpan as C, wrapClientClass as D, wrapContextManagerClass as E, wrapSamplingDecision as F, SEMANTIC_ATTRIBUTE_SENTRY_GRAPHQL_OPERATION as S, SENTRY_SCOPES_CONTEXT_KEY as a, SentryPropagator as b, SentrySampler as c, SentrySpanProcessor as d, buildContextWithSentryScopes as e, continueTrace as f, enhanceDscWithOpenTelemetryRootSpanName as g, getActiveSpan as h, getRequestSpanData as i, getScopesFromContext as j, getSentryResource as k, getSpanKind as l, getTraceContextForScope as m, isSentryRequestSpan as n, openTelemetrySetupCheck as o, setOpenTelemetryContextAsyncContextStrategy as p, setupEventContextTrace as q, spanHasAttributes as r, setIsSetup as s, spanHasEvents as t, spanHasKind as u, spanHasName as v, spanHasParentId as w, spanHasStatus as x, startInactiveSpan as y, startSpan as z };
//# sourceMappingURL=resource-PMlHXvcP.js.map

Sorry, the diff of this file is too big to display

import * as diagnosticsChannel from 'node:diagnostics_channel';
import { context, trace } from '@opentelemetry/api';
import { logger } from '@sentry/core';
import { D as DEBUG_BUILD } from './debug-build-B98wrZ1j.js';
function tracingChannel(channelNameOrInstance, transformStart) {
const channel = diagnosticsChannel.tracingChannel(channelNameOrInstance);
let lookup;
try {
const contextManager = context._getContextManager();
lookup = contextManager.getAsyncLocalStorageLookup();
} catch {
}
if (!lookup) {
DEBUG_BUILD && logger.warn(
"[TracingChannel] Could not access OpenTelemetry AsyncLocalStorage, context propagation will not work."
);
return channel;
}
const otelStorage = lookup.asyncLocalStorage;
channel.start.bindStore(otelStorage, (data) => {
const span = transformStart(data);
data._sentrySpan = span;
return trace.setSpan(context.active(), span);
});
return channel;
}
export { tracingChannel };
//# sourceMappingURL=tracingChannel.js.map
{"version":3,"file":"tracingChannel.js","sources":["../../src/tracingChannel.ts"],"sourcesContent":["/**\n * Vendored and adapted from https://github.com/logaretm/otel-tracing-channel\n *\n * Creates a TracingChannel with proper OpenTelemetry context propagation\n * using Node.js diagnostic_channel's `bindStore` mechanism.\n */\nimport type { TracingChannel, TracingChannelSubscribers } from 'node:diagnostics_channel';\nimport * as diagnosticsChannel from 'node:diagnostics_channel';\nimport type { Span } from '@opentelemetry/api';\nimport { context, trace } from '@opentelemetry/api';\nimport { logger } from '@sentry/core';\nimport type { SentryAsyncLocalStorageContextManager } from './asyncLocalStorageContextManager';\nimport type { AsyncLocalStorageLookup } from './contextManager';\nimport { DEBUG_BUILD } from './debug-build';\n\n/**\n * Transform function that creates a span from the channel data.\n */\nexport type OtelTracingChannelTransform<TData = object> = (data: TData) => Span;\n\nexport type TracingChannelContextWithSpan<TContext extends object = object> = TContext & { _sentrySpan?: Span };\n\n/**\n * A TracingChannel whose `subscribe` / `unsubscribe` accept partial subscriber\n * objects — you only need to provide handlers for the events you care about.\n */\nexport interface OtelTracingChannel<\n TData extends object = object,\n TDataWithSpan extends object = TracingChannelContextWithSpan<TData>,\n> extends Omit<TracingChannel<TData, TDataWithSpan>, 'subscribe' | 'unsubscribe'> {\n subscribe(subscribers: Partial<TracingChannelSubscribers<TDataWithSpan>>): void;\n unsubscribe(subscribers: Partial<TracingChannelSubscribers<TDataWithSpan>>): void;\n}\n\ninterface ContextApi {\n _getContextManager(): SentryAsyncLocalStorageContextManager;\n}\n\n/**\n * Creates a new tracing channel with proper OTel context propagation.\n *\n * When the channel's `tracePromise` / `traceSync` / `traceCallback` is called,\n * the `transformStart` function runs inside `bindStore` so that:\n * 1. A new span is created from the channel data.\n * 2. The span is set on the OTel context stored in AsyncLocalStorage.\n * 3. Downstream code (including Sentry's span processor) sees the correct parent.\n *\n * @param channelNameOrInstance - Either a channel name string or an existing TracingChannel instance.\n * @param transformStart - Function that creates an OpenTelemetry span from the channel data.\n * @returns The tracing channel with OTel context bound.\n */\nexport function tracingChannel<TData extends object = object>(\n channelNameOrInstance: string,\n transformStart: OtelTracingChannelTransform<TData>,\n): OtelTracingChannel<TData, TracingChannelContextWithSpan<TData>> {\n const channel = diagnosticsChannel.tracingChannel<\n TracingChannelContextWithSpan<TData>,\n TracingChannelContextWithSpan<TData>\n >(channelNameOrInstance) as unknown as OtelTracingChannel<TData, TracingChannelContextWithSpan<TData>>;\n\n let lookup: AsyncLocalStorageLookup | undefined;\n try {\n const contextManager = (context as unknown as ContextApi)._getContextManager();\n lookup = contextManager.getAsyncLocalStorageLookup();\n } catch {\n // getAsyncLocalStorageLookup may not exist if using a non-Sentry context manager\n }\n\n if (!lookup) {\n DEBUG_BUILD &&\n logger.warn(\n '[TracingChannel] Could not access OpenTelemetry AsyncLocalStorage, context propagation will not work.',\n );\n return channel;\n }\n\n const otelStorage = lookup.asyncLocalStorage;\n\n // Bind the start channel so that each trace invocation runs the transform\n // and stores the resulting context (with span) in AsyncLocalStorage.\n // @ts-expect-error bindStore types don't account for AsyncLocalStorage of a different generic type\n channel.start.bindStore(otelStorage, (data: TracingChannelContextWithSpan<TData>) => {\n const span = transformStart(data);\n\n // Store the span on data so downstream event handlers (asyncEnd, error, etc.) can access it.\n data._sentrySpan = span;\n\n // Return the context with the span set — this is what gets stored in AsyncLocalStorage.\n return trace.setSpan(context.active(), span);\n });\n\n return channel;\n}\n"],"names":[],"mappings":";;;;;AAmDO,SAAS,cAAA,CACd,uBACA,cAAA,EACiE;AACjE,EAAA,MAAM,OAAA,GAAU,kBAAA,CAAmB,cAAA,CAGjC,qBAAqB,CAAA;AAEvB,EAAA,IAAI,MAAA;AACJ,EAAA,IAAI;AACF,IAAA,MAAM,cAAA,GAAkB,QAAkC,kBAAA,EAAmB;AAC7E,IAAA,MAAA,GAAS,eAAe,0BAAA,EAA2B;AAAA,EACrD,CAAA,CAAA,MAAQ;AAAA,EAER;AAEA,EAAA,IAAI,CAAC,MAAA,EAAQ;AACX,IAAA,WAAA,IACE,MAAA,CAAO,IAAA;AAAA,MACL;AAAA,KACF;AACF,IAAA,OAAO,OAAA;AAAA,EACT;AAEA,EAAA,MAAM,cAAc,MAAA,CAAO,iBAAA;AAK3B,EAAA,OAAA,CAAQ,KAAA,CAAM,SAAA,CAAU,WAAA,EAAa,CAAC,IAAA,KAA+C;AACnF,IAAA,MAAM,IAAA,GAAO,eAAe,IAAI,CAAA;AAGhC,IAAA,IAAA,CAAK,WAAA,GAAc,IAAA;AAGnB,IAAA,OAAO,KAAA,CAAM,OAAA,CAAQ,OAAA,CAAQ,MAAA,IAAU,IAAI,CAAA;AAAA,EAC7C,CAAC,CAAA;AAED,EAAA,OAAO,OAAA;AACT;;;;"}
/**
* Vendored and adapted from https://github.com/logaretm/otel-tracing-channel
*
* Creates a TracingChannel with proper OpenTelemetry context propagation
* using Node.js diagnostic_channel's `bindStore` mechanism.
*/
import { TracingChannel, TracingChannelSubscribers } from 'node:diagnostics_channel';
import { Span } from '@opentelemetry/api';
/**
* Transform function that creates a span from the channel data.
*/
export type OtelTracingChannelTransform<TData = object> = (data: TData) => Span;
export type TracingChannelContextWithSpan<TContext extends object = object> = TContext & {
_sentrySpan?: Span;
};
/**
* A TracingChannel whose `subscribe` / `unsubscribe` accept partial subscriber
* objects — you only need to provide handlers for the events you care about.
*/
export interface OtelTracingChannel<TData extends object = object, TDataWithSpan extends object = TracingChannelContextWithSpan<TData>> extends Pick<TracingChannel<TData, TDataWithSpan>, Exclude<keyof TracingChannel<TData, TDataWithSpan>, 'subscribe' | 'unsubscribe'>> {
subscribe(subscribers: Partial<TracingChannelSubscribers<TDataWithSpan>>): void;
unsubscribe(subscribers: Partial<TracingChannelSubscribers<TDataWithSpan>>): void;
}
/**
* Creates a new tracing channel with proper OTel context propagation.
*
* When the channel's `tracePromise` / `traceSync` / `traceCallback` is called,
* the `transformStart` function runs inside `bindStore` so that:
* 1. A new span is created from the channel data.
* 2. The span is set on the OTel context stored in AsyncLocalStorage.
* 3. Downstream code (including Sentry's span processor) sees the correct parent.
*
* @param channelNameOrInstance - Either a channel name string or an existing TracingChannel instance.
* @param transformStart - Function that creates an OpenTelemetry span from the channel data.
* @returns The tracing channel with OTel context bound.
*/
export declare function tracingChannel<TData extends object = object>(channelNameOrInstance: string, transformStart: OtelTracingChannelTransform<TData>): OtelTracingChannel<TData, TracingChannelContextWithSpan<TData>>;
//# sourceMappingURL=tracingChannel.d.ts.map
/**
* Vendored and adapted from https://github.com/logaretm/otel-tracing-channel
*
* Creates a TracingChannel with proper OpenTelemetry context propagation
* using Node.js diagnostic_channel's `bindStore` mechanism.
*/
import type { TracingChannel, TracingChannelSubscribers } from 'node:diagnostics_channel';
import type { Span } from '@opentelemetry/api';
/**
* Transform function that creates a span from the channel data.
*/
export type OtelTracingChannelTransform<TData = object> = (data: TData) => Span;
export type TracingChannelContextWithSpan<TContext extends object = object> = TContext & {
_sentrySpan?: Span;
};
/**
* A TracingChannel whose `subscribe` / `unsubscribe` accept partial subscriber
* objects — you only need to provide handlers for the events you care about.
*/
export interface OtelTracingChannel<TData extends object = object, TDataWithSpan extends object = TracingChannelContextWithSpan<TData>> extends Omit<TracingChannel<TData, TDataWithSpan>, 'subscribe' | 'unsubscribe'> {
subscribe(subscribers: Partial<TracingChannelSubscribers<TDataWithSpan>>): void;
unsubscribe(subscribers: Partial<TracingChannelSubscribers<TDataWithSpan>>): void;
}
/**
* Creates a new tracing channel with proper OTel context propagation.
*
* When the channel's `tracePromise` / `traceSync` / `traceCallback` is called,
* the `transformStart` function runs inside `bindStore` so that:
* 1. A new span is created from the channel data.
* 2. The span is set on the OTel context stored in AsyncLocalStorage.
* 3. Downstream code (including Sentry's span processor) sees the correct parent.
*
* @param channelNameOrInstance - Either a channel name string or an existing TracingChannel instance.
* @param transformStart - Function that creates an OpenTelemetry span from the channel data.
* @returns The tracing channel with OTel context bound.
*/
export declare function tracingChannel<TData extends object = object>(channelNameOrInstance: string, transformStart: OtelTracingChannelTransform<TData>): OtelTracingChannel<TData, TracingChannelContextWithSpan<TData>>;
//# sourceMappingURL=tracingChannel.d.ts.map
{"version":3,"file":"tracingChannel.d.ts","sourceRoot":"","sources":["../../src/tracingChannel.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,OAAO,KAAK,EAAE,cAAc,EAAE,yBAAyB,EAAE,MAAM,0BAA0B,CAAC;AAE1F,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,oBAAoB,CAAC;AAO/C;;GAEG;AACH,MAAM,MAAM,2BAA2B,CAAC,KAAK,GAAG,MAAM,IAAI,CAAC,IAAI,EAAE,KAAK,KAAK,IAAI,CAAC;AAEhF,MAAM,MAAM,6BAA6B,CAAC,QAAQ,SAAS,MAAM,GAAG,MAAM,IAAI,QAAQ,GAAG;IAAE,WAAW,CAAC,EAAE,IAAI,CAAA;CAAE,CAAC;AAEhH;;;GAGG;AACH,MAAM,WAAW,kBAAkB,CACjC,KAAK,SAAS,MAAM,GAAG,MAAM,EAC7B,aAAa,SAAS,MAAM,GAAG,6BAA6B,CAAC,KAAK,CAAC,CACnE,SAAQ,IAAI,CAAC,cAAc,CAAC,KAAK,EAAE,aAAa,CAAC,EAAE,WAAW,GAAG,aAAa,CAAC;IAC/E,SAAS,CAAC,WAAW,EAAE,OAAO,CAAC,yBAAyB,CAAC,aAAa,CAAC,CAAC,GAAG,IAAI,CAAC;IAChF,WAAW,CAAC,WAAW,EAAE,OAAO,CAAC,yBAAyB,CAAC,aAAa,CAAC,CAAC,GAAG,IAAI,CAAC;CACnF;AAMD;;;;;;;;;;;;GAYG;AACH,wBAAgB,cAAc,CAAC,KAAK,SAAS,MAAM,GAAG,MAAM,EAC1D,qBAAqB,EAAE,MAAM,EAC7B,cAAc,EAAE,2BAA2B,CAAC,KAAK,CAAC,GACjD,kBAAkB,CAAC,KAAK,EAAE,6BAA6B,CAAC,KAAK,CAAC,CAAC,CAsCjE"}