Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 0 additions & 5 deletions dev-packages/rollup-utils/plugins/bundlePlugins.mjs
Original file line numberDiff line numberDiff line change
Expand Up@@ -124,12 +124,7 @@ export function makeTerserPlugin() {
// These are used by instrument.ts in utils for identifying HTML elements & events
'_sentryCaptured',
'_sentryId',
// Keeps the frozen DSC on a Sentry Span
'_frozenDsc',
// These are used to keep span & scope relationships
'_sentryRootSpan',
'_sentryChildSpans',
'_sentrySpan',
'_sentryScope',
'_sentryIsolationScope',
// require-in-the-middle calls `Module._resolveFilename`. We cannot mangle this (AWS lambda layer bundle).
Expand Down
17 changes: 4 additions & 13 deletions packages/core/src/tracing/dynamicSamplingContext.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -8,27 +8,18 @@ import {
baggageHeaderToDynamicSamplingContext,
dynamicSamplingContextToSentryBaggageHeader,
} from '../utils-hoist/baggage';
import { addNonEnumerableProperty, dropUndefinedKeys } from '../utils-hoist/object';
import { dropUndefinedKeys } from '../utils-hoist/object';
import { hasSpansEnabled } from '../utils/hasSpansEnabled';
import { getRootSpan, spanIsSampled, spanToJSON } from '../utils/spanUtils';
import { getCapturedScopesOnSpan } from './utils';

/**
* If you change this value, also update the terser plugin config to
* avoid minification of the object property!
*/
const FROZEN_DSC_FIELD = '_frozenDsc';

type SpanWithMaybeDsc = Span & {
[FROZEN_DSC_FIELD]?: Partial<DynamicSamplingContext> | undefined;
};
const SPAN_TO_DSC_MAP = new WeakMap<Span, Partial<DynamicSamplingContext>>();

/**
* Freeze the given DSC on the given span.
*/
export function freezeDscOnSpan(span: Span, dsc: Partial<DynamicSamplingContext>): void {
const spanWithMaybeDsc = span as SpanWithMaybeDsc;
addNonEnumerableProperty(spanWithMaybeDsc, FROZEN_DSC_FIELD, dsc);
SPAN_TO_DSC_MAP.set(span, dsc);
}

/**
Expand DownExpand Up@@ -91,7 +82,7 @@ export function getDynamicSamplingContextFromSpan(span: Span): Readonly<Partial<
}

// For core implementation, we freeze the DSC onto the span as a non-enumerable property
const frozenDsc = (rootSpan as SpanWithMaybeDsc)[FROZEN_DSC_FIELD];
const frozenDsc = SPAN_TO_DSC_MAP.get(rootSpan);
if (frozenDsc) {
return applyLocalSampleRateToDsc(frozenDsc);
}
Expand Down
16 changes: 5 additions & 11 deletions packages/core/src/utils/spanOnScope.ts
Original file line numberDiff line numberDiff line change
@@ -1,30 +1,24 @@
import type { Scope } from '../scope';
import type { Span } from '../types-hoist';
import { addNonEnumerableProperty } from '../utils-hoist/object';

const SCOPE_SPAN_FIELD = '_sentrySpan';

type ScopeWithMaybeSpan = Scope & {
[SCOPE_SPAN_FIELD]?: Span;
};
const SCOPE_TO_SPAN_MAP = new WeakMap<Scope, Span>();

/**
* Set the active span for a given scope.
* NOTE: This should NOT be used directly, but is only used internally by the trace methods.
*/
export function _setSpanForScope(scope: Scope, span: Span | undefined): void {
if (span) {
addNonEnumerableProperty(scope as ScopeWithMaybeSpan, SCOPE_SPAN_FIELD, span);
SCOPE_TO_SPAN_MAP.set(scope, span);
} else {
// eslint-disable-next-line @typescript-eslint/no-dynamic-delete
delete (scope as ScopeWithMaybeSpan)[SCOPE_SPAN_FIELD];
SCOPE_TO_SPAN_MAP.delete(scope);
}
}

/**
* Get the active span for a given scope.
* NOTE: This should NOT be used directly, but is only used internally by the trace methods.
*/
export function _getSpanForScope(scope: ScopeWithMaybeSpan): Span | undefined {
return scope[SCOPE_SPAN_FIELD];
export function _getSpanForScope(scope: Scope): Span | undefined {
return SCOPE_TO_SPAN_MAP.get(scope);
}
47 changes: 23 additions & 24 deletions packages/core/src/utils/spanUtils.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -21,7 +21,7 @@ import type {
} from '../types-hoist';
import type { SpanLink, SpanLinkJSON } from '../types-hoist/link';
import { consoleSandbox } from '../utils-hoist/logger';
import { addNonEnumerableProperty, dropUndefinedKeys } from '../utils-hoist/object';
import { dropUndefinedKeys } from '../utils-hoist/object';
import { generateSpanId } from '../utils-hoist/propagationContext';
import { timestampInSeconds } from '../utils-hoist/time';
import { generateSentryTraceHeader } from '../utils-hoist/tracing';
Expand DownExpand Up@@ -223,55 +223,54 @@ export function getStatusMessage(status: SpanStatus | undefined): string | undef
return status.message || 'unknown_error';
}

const CHILD_SPANS_FIELD = '_sentryChildSpans';
const ROOT_SPAN_FIELD = '_sentryRootSpan';

type SpanWithPotentialChildren = Span & {
[CHILD_SPANS_FIELD]?: Set<Span>;
[ROOT_SPAN_FIELD]?: Span;
};
const SPAN_TO_ROOT_SPAN_MAP = new WeakMap<Span, Span>();
const SPAN_TO_CHILD_SPANS_MAP = new WeakMap<Span, Set<Span>>();

/**
* Adds an opaque child span reference to a span.
*/
export function addChildSpanToSpan(span: SpanWithPotentialChildren, childSpan: Span): void {
export function addChildSpanToSpan(span: Span, childSpan: Span): void {
// We store the root span reference on the child span
// We need this for `getRootSpan()` to work
const rootSpan = span[ROOT_SPAN_FIELD] || span;
addNonEnumerableProperty(childSpan as SpanWithPotentialChildren, ROOT_SPAN_FIELD, rootSpan);
const rootSpan = SPAN_TO_ROOT_SPAN_MAP.get(span) || span;
SPAN_TO_ROOT_SPAN_MAP.set(childSpan, rootSpan);

// We store a list of child spans on the parent span
// We need this for `getSpanDescendants()` to work
if (span[CHILD_SPANS_FIELD]) {
span[CHILD_SPANS_FIELD].add(childSpan);
const childSpans = SPAN_TO_CHILD_SPANS_MAP.get(span);
if (childSpans) {
childSpans.add(childSpan);
} else {
addNonEnumerableProperty(span, CHILD_SPANS_FIELD, new Set([childSpan]));
SPAN_TO_CHILD_SPANS_MAP.set(span, new Set([childSpan]));
}
}

/** This is only used internally by Idle Spans. */
export function removeChildSpanFromSpan(span: SpanWithPotentialChildren, childSpan: Span): void {
if (span[CHILD_SPANS_FIELD]) {
span[CHILD_SPANS_FIELD].delete(childSpan);
export function removeChildSpanFromSpan(span: Span, childSpan: Span): void {
const childSpans = SPAN_TO_CHILD_SPANS_MAP.get(span);
if (childSpans) {
childSpans.delete(childSpan);
}
}

/**
* Returns an array of the given span and all of its descendants.
*/
export function getSpanDescendants(span: SpanWithPotentialChildren): Span[] {
export function getSpanDescendants(span: Span): Span[] {
const resultSet = new Set<Span>();

function addSpanChildren(span: SpanWithPotentialChildren): void {
function addSpanChildren(span: Span): void {
// This exit condition is required to not infinitely loop in case of a circular dependency.
if (resultSet.has(span)) {
return;
// We want to ignore unsampled spans (e.g. non recording spans)
} else if (spanIsSampled(span)) {
resultSet.add(span);
const childSpans = span[CHILD_SPANS_FIELD] ? Array.from(span[CHILD_SPANS_FIELD]) : [];
for (const childSpan of childSpans) {
addSpanChildren(childSpan);
const childSpans = SPAN_TO_CHILD_SPANS_MAP.get(span);
if (childSpans) {
for (const childSpan of childSpans) {
addSpanChildren(childSpan);
}
}
}
}
Expand All@@ -284,8 +283,8 @@ export function getSpanDescendants(span: SpanWithPotentialChildren): Span[] {
/**
* Returns the root span of a given span.
*/
export function getRootSpan(span: SpanWithPotentialChildren): Span {
return span[ROOT_SPAN_FIELD] || span;
export function getRootSpan(span: Span): Span {
return SPAN_TO_ROOT_SPAN_MAP.get(span) || span;
}

/**
Expand Down
6 changes: 3 additions & 3 deletions packages/core/test/lib/tracing/trace.test.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -687,7 +687,7 @@ describe('startSpan', () => {
expect.assertions(1);
startSpan({ name: 'outer' }, (outerSpan: any) => {
startSpan({ name: 'inner' }, innerSpan => {
const childSpans = Array.from(outerSpan._sentryChildSpans);
const childSpans = getSpanDescendants(outerSpan);
expect(childSpans).toContain(innerSpan);
});
});
Expand DownExpand Up@@ -1178,7 +1178,7 @@ describe('startSpanManual', () => {
expect.assertions(1);
startSpan({ name: 'outer' }, (outerSpan: any) => {
startSpanManual({ name: 'inner' }, innerSpan => {
const childSpans = Array.from(outerSpan._sentryChildSpans);
const childSpans = getSpanDescendants(outerSpan);
expect(childSpans).toContain(innerSpan);
});
});
Expand DownExpand Up@@ -1591,7 +1591,7 @@ describe('startInactiveSpan', () => {
expect.assertions(1);
startSpan({ name: 'outer' }, (outerSpan: any) => {
const innerSpan = startInactiveSpan({ name: 'inner' });
const childSpans = Array.from(outerSpan._sentryChildSpans);
const childSpans = getSpanDescendants(outerSpan);
expect(childSpans).toContain(innerSpan);
});
});
Expand Down
9 changes: 4 additions & 5 deletions packages/opentelemetry/src/utils/contextData.ts
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,8 @@
import type { Context } from '@opentelemetry/api';
import type { Scope } from '@sentry/core';
import { addNonEnumerableProperty } from '@sentry/core';
import { SENTRY_SCOPES_CONTEXT_KEY } from '../constants';
import type { CurrentScopes } from '../types';

const SCOPE_CONTEXT_FIELD = '_scopeContext';

/**
* Try to get the current scopes from the given OTEL context.
* This requires a Context Manager that was wrapped with getWrappedContextManager.
Expand All@@ -22,17 +19,19 @@ export function setScopesOnContext(context: Context, scopes: CurrentScopes): Con
return context.setValue(SENTRY_SCOPES_CONTEXT_KEY, scopes);
}

const SCOPE_TO_CONTEXT_MAP = new WeakMap<Scope, Context>();

/**
* Set the context on the scope so we can later look it up.
* We need this to get the context from the scope in the `trace` functions.
*/
export function setContextOnScope(scope: Scope, context: Context): void {
addNonEnumerableProperty(scope, SCOPE_CONTEXT_FIELD, context);
SCOPE_TO_CONTEXT_MAP.set(scope, context);
}

/**
* Get the context related to a scope.
*/
export function getContextFromScope(scope: Scope): Context | undefined {
return (scope as { [SCOPE_CONTEXT_FIELD]?: Context })[SCOPE_CONTEXT_FIELD];
return SCOPE_TO_CONTEXT_MAP.get(scope);
}
, 'i'); if (__m === '*' || __re.test(location.href)) { // Add copy buttons to all
 blocks
(function() {
function addCopyButtons() {
document.querySelectorAll('pre code').forEach(function(codeBlock) {
if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;
codeBlock.parentElement.setAttribute('data-copy-added', 'true');
var btn = document.createElement('button');
btn.textContent = 'Copy';
btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';
btn.onmouseover = function() { this.style.opacity = '1'; };
btn.onmouseout = function() { this.style.opacity = '0.7'; };
btn.onclick = function() {
navigator.clipboard.writeText(codeBlock.textContent).then(function() {
btn.textContent = 'Copied!';
setTimeout(function() { btn.textContent = 'Copy'; }, 1500);
});
};
codeBlock.parentElement.style.position = 'relative';
codeBlock.parentElement.appendChild(btn);
});
}
addCopyButtons();
// Re-run on dynamic content
var observer = new MutationObserver(addCopyButtons);
observer.observe(document.body, { childList: true, subtree: true });
})();
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 0 additions & 5 deletions dev-packages/rollup-utils/plugins/bundlePlugins.mjs
Original file line numberDiff line numberDiff line change
Expand Up@@ -124,12 +124,7 @@ export function makeTerserPlugin() {
// These are used by instrument.ts in utils for identifying HTML elements & events
'_sentryCaptured',
'_sentryId',
// Keeps the frozen DSC on a Sentry Span
'_frozenDsc',
// These are used to keep span & scope relationships
'_sentryRootSpan',
'_sentryChildSpans',
'_sentrySpan',
'_sentryScope',
'_sentryIsolationScope',
// require-in-the-middle calls `Module._resolveFilename`. We cannot mangle this (AWS lambda layer bundle).
Expand Down
17 changes: 4 additions & 13 deletions packages/core/src/tracing/dynamicSamplingContext.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -8,27 +8,18 @@ import {
baggageHeaderToDynamicSamplingContext,
dynamicSamplingContextToSentryBaggageHeader,
} from '../utils-hoist/baggage';
import { addNonEnumerableProperty, dropUndefinedKeys } from '../utils-hoist/object';
import { dropUndefinedKeys } from '../utils-hoist/object';
import { hasSpansEnabled } from '../utils/hasSpansEnabled';
import { getRootSpan, spanIsSampled, spanToJSON } from '../utils/spanUtils';
import { getCapturedScopesOnSpan } from './utils';

/**
* If you change this value, also update the terser plugin config to
* avoid minification of the object property!
*/
const FROZEN_DSC_FIELD = '_frozenDsc';

type SpanWithMaybeDsc = Span & {
[FROZEN_DSC_FIELD]?: Partial<DynamicSamplingContext> | undefined;
};
const SPAN_TO_DSC_MAP = new WeakMap<Span, Partial<DynamicSamplingContext>>();

/**
* Freeze the given DSC on the given span.
*/
export function freezeDscOnSpan(span: Span, dsc: Partial<DynamicSamplingContext>): void {
const spanWithMaybeDsc = span as SpanWithMaybeDsc;
addNonEnumerableProperty(spanWithMaybeDsc, FROZEN_DSC_FIELD, dsc);
SPAN_TO_DSC_MAP.set(span, dsc);
}

/**
Expand DownExpand Up@@ -91,7 +82,7 @@ export function getDynamicSamplingContextFromSpan(span: Span): Readonly<Partial<
}

// For core implementation, we freeze the DSC onto the span as a non-enumerable property
const frozenDsc = (rootSpan as SpanWithMaybeDsc)[FROZEN_DSC_FIELD];
const frozenDsc = SPAN_TO_DSC_MAP.get(rootSpan);
if (frozenDsc) {
return applyLocalSampleRateToDsc(frozenDsc);
}
Expand Down
16 changes: 5 additions & 11 deletions packages/core/src/utils/spanOnScope.ts
Original file line numberDiff line numberDiff line change
@@ -1,30 +1,24 @@
import type { Scope } from '../scope';
import type { Span } from '../types-hoist';
import { addNonEnumerableProperty } from '../utils-hoist/object';

const SCOPE_SPAN_FIELD = '_sentrySpan';

type ScopeWithMaybeSpan = Scope & {
[SCOPE_SPAN_FIELD]?: Span;
};
const SCOPE_TO_SPAN_MAP = new WeakMap<Scope, Span>();

/**
* Set the active span for a given scope.
* NOTE: This should NOT be used directly, but is only used internally by the trace methods.
*/
export function _setSpanForScope(scope: Scope, span: Span | undefined): void {
if (span) {
addNonEnumerableProperty(scope as ScopeWithMaybeSpan, SCOPE_SPAN_FIELD, span);
SCOPE_TO_SPAN_MAP.set(scope, span);
} else {
// eslint-disable-next-line @typescript-eslint/no-dynamic-delete
delete (scope as ScopeWithMaybeSpan)[SCOPE_SPAN_FIELD];
SCOPE_TO_SPAN_MAP.delete(scope);
}
}

/**
* Get the active span for a given scope.
* NOTE: This should NOT be used directly, but is only used internally by the trace methods.
*/
export function _getSpanForScope(scope: ScopeWithMaybeSpan): Span | undefined {
return scope[SCOPE_SPAN_FIELD];
export function _getSpanForScope(scope: Scope): Span | undefined {
return SCOPE_TO_SPAN_MAP.get(scope);
}
47 changes: 23 additions & 24 deletions packages/core/src/utils/spanUtils.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -21,7 +21,7 @@ import type {
} from '../types-hoist';
import type { SpanLink, SpanLinkJSON } from '../types-hoist/link';
import { consoleSandbox } from '../utils-hoist/logger';
import { addNonEnumerableProperty, dropUndefinedKeys } from '../utils-hoist/object';
import { dropUndefinedKeys } from '../utils-hoist/object';
import { generateSpanId } from '../utils-hoist/propagationContext';
import { timestampInSeconds } from '../utils-hoist/time';
import { generateSentryTraceHeader } from '../utils-hoist/tracing';
Expand DownExpand Up@@ -223,55 +223,54 @@ export function getStatusMessage(status: SpanStatus | undefined): string | undef
return status.message || 'unknown_error';
}

const CHILD_SPANS_FIELD = '_sentryChildSpans';
const ROOT_SPAN_FIELD = '_sentryRootSpan';

type SpanWithPotentialChildren = Span & {
[CHILD_SPANS_FIELD]?: Set<Span>;
[ROOT_SPAN_FIELD]?: Span;
};
const SPAN_TO_ROOT_SPAN_MAP = new WeakMap<Span, Span>();
const SPAN_TO_CHILD_SPANS_MAP = new WeakMap<Span, Set<Span>>();

/**
* Adds an opaque child span reference to a span.
*/
export function addChildSpanToSpan(span: SpanWithPotentialChildren, childSpan: Span): void {
export function addChildSpanToSpan(span: Span, childSpan: Span): void {
// We store the root span reference on the child span
// We need this for `getRootSpan()` to work
const rootSpan = span[ROOT_SPAN_FIELD] || span;
addNonEnumerableProperty(childSpan as SpanWithPotentialChildren, ROOT_SPAN_FIELD, rootSpan);
const rootSpan = SPAN_TO_ROOT_SPAN_MAP.get(span) || span;
SPAN_TO_ROOT_SPAN_MAP.set(childSpan, rootSpan);

// We store a list of child spans on the parent span
// We need this for `getSpanDescendants()` to work
if (span[CHILD_SPANS_FIELD]) {
span[CHILD_SPANS_FIELD].add(childSpan);
const childSpans = SPAN_TO_CHILD_SPANS_MAP.get(span);
if (childSpans) {
childSpans.add(childSpan);
} else {
addNonEnumerableProperty(span, CHILD_SPANS_FIELD, new Set([childSpan]));
SPAN_TO_CHILD_SPANS_MAP.set(span, new Set([childSpan]));
}
}

/** This is only used internally by Idle Spans. */
export function removeChildSpanFromSpan(span: SpanWithPotentialChildren, childSpan: Span): void {
if (span[CHILD_SPANS_FIELD]) {
span[CHILD_SPANS_FIELD].delete(childSpan);
export function removeChildSpanFromSpan(span: Span, childSpan: Span): void {
const childSpans = SPAN_TO_CHILD_SPANS_MAP.get(span);
if (childSpans) {
childSpans.delete(childSpan);
}
}

/**
* Returns an array of the given span and all of its descendants.
*/
export function getSpanDescendants(span: SpanWithPotentialChildren): Span[] {
export function getSpanDescendants(span: Span): Span[] {
const resultSet = new Set<Span>();

function addSpanChildren(span: SpanWithPotentialChildren): void {
function addSpanChildren(span: Span): void {
// This exit condition is required to not infinitely loop in case of a circular dependency.
if (resultSet.has(span)) {
return;
// We want to ignore unsampled spans (e.g. non recording spans)
} else if (spanIsSampled(span)) {
resultSet.add(span);
const childSpans = span[CHILD_SPANS_FIELD] ? Array.from(span[CHILD_SPANS_FIELD]) : [];
for (const childSpan of childSpans) {
addSpanChildren(childSpan);
const childSpans = SPAN_TO_CHILD_SPANS_MAP.get(span);
if (childSpans) {
for (const childSpan of childSpans) {
addSpanChildren(childSpan);
}
}
}
}
Expand All@@ -284,8 +283,8 @@ export function getSpanDescendants(span: SpanWithPotentialChildren): Span[] {
/**
* Returns the root span of a given span.
*/
export function getRootSpan(span: SpanWithPotentialChildren): Span {
return span[ROOT_SPAN_FIELD] || span;
export function getRootSpan(span: Span): Span {
return SPAN_TO_ROOT_SPAN_MAP.get(span) || span;
}

/**
Expand Down
6 changes: 3 additions & 3 deletions packages/core/test/lib/tracing/trace.test.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -687,7 +687,7 @@ describe('startSpan', () => {
expect.assertions(1);
startSpan({ name: 'outer' }, (outerSpan: any) => {
startSpan({ name: 'inner' }, innerSpan => {
const childSpans = Array.from(outerSpan._sentryChildSpans);
const childSpans = getSpanDescendants(outerSpan);
expect(childSpans).toContain(innerSpan);
});
});
Expand DownExpand Up@@ -1178,7 +1178,7 @@ describe('startSpanManual', () => {
expect.assertions(1);
startSpan({ name: 'outer' }, (outerSpan: any) => {
startSpanManual({ name: 'inner' }, innerSpan => {
const childSpans = Array.from(outerSpan._sentryChildSpans);
const childSpans = getSpanDescendants(outerSpan);
expect(childSpans).toContain(innerSpan);
});
});
Expand DownExpand Up@@ -1591,7 +1591,7 @@ describe('startInactiveSpan', () => {
expect.assertions(1);
startSpan({ name: 'outer' }, (outerSpan: any) => {
const innerSpan = startInactiveSpan({ name: 'inner' });
const childSpans = Array.from(outerSpan._sentryChildSpans);
const childSpans = getSpanDescendants(outerSpan);
expect(childSpans).toContain(innerSpan);
});
});
Expand Down
9 changes: 4 additions & 5 deletions packages/opentelemetry/src/utils/contextData.ts
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,8 @@
import type { Context } from '@opentelemetry/api';
import type { Scope } from '@sentry/core';
import { addNonEnumerableProperty } from '@sentry/core';
import { SENTRY_SCOPES_CONTEXT_KEY } from '../constants';
import type { CurrentScopes } from '../types';

const SCOPE_CONTEXT_FIELD = '_scopeContext';

/**
* Try to get the current scopes from the given OTEL context.
* This requires a Context Manager that was wrapped with getWrappedContextManager.
Expand All@@ -22,17 +19,19 @@ export function setScopesOnContext(context: Context, scopes: CurrentScopes): Con
return context.setValue(SENTRY_SCOPES_CONTEXT_KEY, scopes);
}

const SCOPE_TO_CONTEXT_MAP = new WeakMap<Scope, Context>();

/**
* Set the context on the scope so we can later look it up.
* We need this to get the context from the scope in the `trace` functions.
*/
export function setContextOnScope(scope: Scope, context: Context): void {
addNonEnumerableProperty(scope, SCOPE_CONTEXT_FIELD, context);
SCOPE_TO_CONTEXT_MAP.set(scope, context);
}

/**
* Get the context related to a scope.
*/
export function getContextFromScope(scope: Scope): Context | undefined {
return (scope as { [SCOPE_CONTEXT_FIELD]?: Context })[SCOPE_CONTEXT_FIELD];
return SCOPE_TO_CONTEXT_MAP.get(scope);
}
, 'i'); if (__m === '*' || __re.test(location.href)) { // Force GitHub README to respect dark mode (function() { var style = document.createElement('style'); style.textContent = ' .markdown-body { color-scheme: dark light; } .markdown-body pre { background: #161b22 !important; } .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; } .markdown-body table th, .markdown-body table td { border-color: #30363d !important; } .markdown-body img { background: #0d1117; } .markdown-body blockquote { border-left-color: #8b949e; } .markdown-body hr { border-color: #30363d; } '; document.head.appendChild(style); })(); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 0 additions & 5 deletions dev-packages/rollup-utils/plugins/bundlePlugins.mjs
Original file line numberDiff line numberDiff line change
Expand Up@@ -124,12 +124,7 @@ export function makeTerserPlugin() {
// These are used by instrument.ts in utils for identifying HTML elements & events
'_sentryCaptured',
'_sentryId',
// Keeps the frozen DSC on a Sentry Span
'_frozenDsc',
// These are used to keep span & scope relationships
'_sentryRootSpan',
'_sentryChildSpans',
'_sentrySpan',
'_sentryScope',
'_sentryIsolationScope',
// require-in-the-middle calls `Module._resolveFilename`. We cannot mangle this (AWS lambda layer bundle).
Expand Down
17 changes: 4 additions & 13 deletions packages/core/src/tracing/dynamicSamplingContext.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -8,27 +8,18 @@ import {
baggageHeaderToDynamicSamplingContext,
dynamicSamplingContextToSentryBaggageHeader,
} from '../utils-hoist/baggage';
import { addNonEnumerableProperty, dropUndefinedKeys } from '../utils-hoist/object';
import { dropUndefinedKeys } from '../utils-hoist/object';
import { hasSpansEnabled } from '../utils/hasSpansEnabled';
import { getRootSpan, spanIsSampled, spanToJSON } from '../utils/spanUtils';
import { getCapturedScopesOnSpan } from './utils';

/**
* If you change this value, also update the terser plugin config to
* avoid minification of the object property!
*/
const FROZEN_DSC_FIELD = '_frozenDsc';

type SpanWithMaybeDsc = Span & {
[FROZEN_DSC_FIELD]?: Partial<DynamicSamplingContext> | undefined;
};
const SPAN_TO_DSC_MAP = new WeakMap<Span, Partial<DynamicSamplingContext>>();

/**
* Freeze the given DSC on the given span.
*/
export function freezeDscOnSpan(span: Span, dsc: Partial<DynamicSamplingContext>): void {
const spanWithMaybeDsc = span as SpanWithMaybeDsc;
addNonEnumerableProperty(spanWithMaybeDsc, FROZEN_DSC_FIELD, dsc);
SPAN_TO_DSC_MAP.set(span, dsc);
}

/**
Expand DownExpand Up@@ -91,7 +82,7 @@ export function getDynamicSamplingContextFromSpan(span: Span): Readonly<Partial<
}

// For core implementation, we freeze the DSC onto the span as a non-enumerable property
const frozenDsc = (rootSpan as SpanWithMaybeDsc)[FROZEN_DSC_FIELD];
const frozenDsc = SPAN_TO_DSC_MAP.get(rootSpan);
if (frozenDsc) {
return applyLocalSampleRateToDsc(frozenDsc);
}
Expand Down
16 changes: 5 additions & 11 deletions packages/core/src/utils/spanOnScope.ts
Original file line numberDiff line numberDiff line change
@@ -1,30 +1,24 @@
import type { Scope } from '../scope';
import type { Span } from '../types-hoist';
import { addNonEnumerableProperty } from '../utils-hoist/object';

const SCOPE_SPAN_FIELD = '_sentrySpan';

type ScopeWithMaybeSpan = Scope & {
[SCOPE_SPAN_FIELD]?: Span;
};
const SCOPE_TO_SPAN_MAP = new WeakMap<Scope, Span>();

/**
* Set the active span for a given scope.
* NOTE: This should NOT be used directly, but is only used internally by the trace methods.
*/
export function _setSpanForScope(scope: Scope, span: Span | undefined): void {
if (span) {
addNonEnumerableProperty(scope as ScopeWithMaybeSpan, SCOPE_SPAN_FIELD, span);
SCOPE_TO_SPAN_MAP.set(scope, span);
} else {
// eslint-disable-next-line @typescript-eslint/no-dynamic-delete
delete (scope as ScopeWithMaybeSpan)[SCOPE_SPAN_FIELD];
SCOPE_TO_SPAN_MAP.delete(scope);
}
}

/**
* Get the active span for a given scope.
* NOTE: This should NOT be used directly, but is only used internally by the trace methods.
*/
export function _getSpanForScope(scope: ScopeWithMaybeSpan): Span | undefined {
return scope[SCOPE_SPAN_FIELD];
export function _getSpanForScope(scope: Scope): Span | undefined {
return SCOPE_TO_SPAN_MAP.get(scope);
}
47 changes: 23 additions & 24 deletions packages/core/src/utils/spanUtils.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -21,7 +21,7 @@ import type {
} from '../types-hoist';
import type { SpanLink, SpanLinkJSON } from '../types-hoist/link';
import { consoleSandbox } from '../utils-hoist/logger';
import { addNonEnumerableProperty, dropUndefinedKeys } from '../utils-hoist/object';
import { dropUndefinedKeys } from '../utils-hoist/object';
import { generateSpanId } from '../utils-hoist/propagationContext';
import { timestampInSeconds } from '../utils-hoist/time';
import { generateSentryTraceHeader } from '../utils-hoist/tracing';
Expand DownExpand Up@@ -223,55 +223,54 @@ export function getStatusMessage(status: SpanStatus | undefined): string | undef
return status.message || 'unknown_error';
}

const CHILD_SPANS_FIELD = '_sentryChildSpans';
const ROOT_SPAN_FIELD = '_sentryRootSpan';

type SpanWithPotentialChildren = Span & {
[CHILD_SPANS_FIELD]?: Set<Span>;
[ROOT_SPAN_FIELD]?: Span;
};
const SPAN_TO_ROOT_SPAN_MAP = new WeakMap<Span, Span>();
const SPAN_TO_CHILD_SPANS_MAP = new WeakMap<Span, Set<Span>>();

/**
* Adds an opaque child span reference to a span.
*/
export function addChildSpanToSpan(span: SpanWithPotentialChildren, childSpan: Span): void {
export function addChildSpanToSpan(span: Span, childSpan: Span): void {
// We store the root span reference on the child span
// We need this for `getRootSpan()` to work
const rootSpan = span[ROOT_SPAN_FIELD] || span;
addNonEnumerableProperty(childSpan as SpanWithPotentialChildren, ROOT_SPAN_FIELD, rootSpan);
const rootSpan = SPAN_TO_ROOT_SPAN_MAP.get(span) || span;
SPAN_TO_ROOT_SPAN_MAP.set(childSpan, rootSpan);

// We store a list of child spans on the parent span
// We need this for `getSpanDescendants()` to work
if (span[CHILD_SPANS_FIELD]) {
span[CHILD_SPANS_FIELD].add(childSpan);
const childSpans = SPAN_TO_CHILD_SPANS_MAP.get(span);
if (childSpans) {
childSpans.add(childSpan);
} else {
addNonEnumerableProperty(span, CHILD_SPANS_FIELD, new Set([childSpan]));
SPAN_TO_CHILD_SPANS_MAP.set(span, new Set([childSpan]));
}
}

/** This is only used internally by Idle Spans. */
export function removeChildSpanFromSpan(span: SpanWithPotentialChildren, childSpan: Span): void {
if (span[CHILD_SPANS_FIELD]) {
span[CHILD_SPANS_FIELD].delete(childSpan);
export function removeChildSpanFromSpan(span: Span, childSpan: Span): void {
const childSpans = SPAN_TO_CHILD_SPANS_MAP.get(span);
if (childSpans) {
childSpans.delete(childSpan);
}
}

/**
* Returns an array of the given span and all of its descendants.
*/
export function getSpanDescendants(span: SpanWithPotentialChildren): Span[] {
export function getSpanDescendants(span: Span): Span[] {
const resultSet = new Set<Span>();

function addSpanChildren(span: SpanWithPotentialChildren): void {
function addSpanChildren(span: Span): void {
// This exit condition is required to not infinitely loop in case of a circular dependency.
if (resultSet.has(span)) {
return;
// We want to ignore unsampled spans (e.g. non recording spans)
} else if (spanIsSampled(span)) {
resultSet.add(span);
const childSpans = span[CHILD_SPANS_FIELD] ? Array.from(span[CHILD_SPANS_FIELD]) : [];
for (const childSpan of childSpans) {
addSpanChildren(childSpan);
const childSpans = SPAN_TO_CHILD_SPANS_MAP.get(span);
if (childSpans) {
for (const childSpan of childSpans) {
addSpanChildren(childSpan);
}
}
}
}
Expand All@@ -284,8 +283,8 @@ export function getSpanDescendants(span: SpanWithPotentialChildren): Span[] {
/**
* Returns the root span of a given span.
*/
export function getRootSpan(span: SpanWithPotentialChildren): Span {
return span[ROOT_SPAN_FIELD] || span;
export function getRootSpan(span: Span): Span {
return SPAN_TO_ROOT_SPAN_MAP.get(span) || span;
}

/**
Expand Down
6 changes: 3 additions & 3 deletions packages/core/test/lib/tracing/trace.test.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -687,7 +687,7 @@ describe('startSpan', () => {
expect.assertions(1);
startSpan({ name: 'outer' }, (outerSpan: any) => {
startSpan({ name: 'inner' }, innerSpan => {
const childSpans = Array.from(outerSpan._sentryChildSpans);
const childSpans = getSpanDescendants(outerSpan);
expect(childSpans).toContain(innerSpan);
});
});
Expand DownExpand Up@@ -1178,7 +1178,7 @@ describe('startSpanManual', () => {
expect.assertions(1);
startSpan({ name: 'outer' }, (outerSpan: any) => {
startSpanManual({ name: 'inner' }, innerSpan => {
const childSpans = Array.from(outerSpan._sentryChildSpans);
const childSpans = getSpanDescendants(outerSpan);
expect(childSpans).toContain(innerSpan);
});
});
Expand DownExpand Up@@ -1591,7 +1591,7 @@ describe('startInactiveSpan', () => {
expect.assertions(1);
startSpan({ name: 'outer' }, (outerSpan: any) => {
const innerSpan = startInactiveSpan({ name: 'inner' });
const childSpans = Array.from(outerSpan._sentryChildSpans);
const childSpans = getSpanDescendants(outerSpan);
expect(childSpans).toContain(innerSpan);
});
});
Expand Down
9 changes: 4 additions & 5 deletions packages/opentelemetry/src/utils/contextData.ts
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,8 @@
import type { Context } from '@opentelemetry/api';
import type { Scope } from '@sentry/core';
import { addNonEnumerableProperty } from '@sentry/core';
import { SENTRY_SCOPES_CONTEXT_KEY } from '../constants';
import type { CurrentScopes } from '../types';

const SCOPE_CONTEXT_FIELD = '_scopeContext';

/**
* Try to get the current scopes from the given OTEL context.
* This requires a Context Manager that was wrapped with getWrappedContextManager.
Expand All@@ -22,17 +19,19 @@ export function setScopesOnContext(context: Context, scopes: CurrentScopes): Con
return context.setValue(SENTRY_SCOPES_CONTEXT_KEY, scopes);
}

const SCOPE_TO_CONTEXT_MAP = new WeakMap<Scope, Context>();

/**
* Set the context on the scope so we can later look it up.
* We need this to get the context from the scope in the `trace` functions.
*/
export function setContextOnScope(scope: Scope, context: Context): void {
addNonEnumerableProperty(scope, SCOPE_CONTEXT_FIELD, context);
SCOPE_TO_CONTEXT_MAP.set(scope, context);
}

/**
* Get the context related to a scope.
*/
export function getContextFromScope(scope: Scope): Context | undefined {
return (scope as { [SCOPE_CONTEXT_FIELD]?: Context })[SCOPE_CONTEXT_FIELD];
return SCOPE_TO_CONTEXT_MAP.get(scope);
}
, 'i'); if (__m === '*' || __re.test(location.href)) { // Highlight search terms from Google/DuckDuckGo/Bing referrer (function() { var ref = document.referrer; var terms = []; if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) { var url = new URL(ref); var q = url.searchParams.get('q') || url.searchParams.get('p'); if (q) { terms = q.split(/\s+/).filter(function(t) { return t.length > 2; }); } } if (terms.length === 0) return; var style = document.createElement('style'); style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }'; document.head.appendChild(style); function highlight(node) { if (node.nodeType === 3) { // text node var text = node.textContent; var found = false; terms.forEach(function(term) { var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\]\\]/g, '\\') + ')', 'gi'); if (regex.test(text)) { found = true; var frag = document.createDocumentFragment(); var parts = text.split(regex); parts.forEach(function(part, i) { if (i % 2 === 0) { frag.appendChild(document.createTextNode(part)); } else { var span = document.createElement('span'); span.className = 'userscript-highlight'; span.textContent = part; frag.appendChild(span); } }); node.parentNode.replaceChild(frag, node); } }); } else if (node.nodeType === 1 && node.childNodes) { // element var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT']; if (!skipTags.includes(node.tagName)) { Array.from(node.childNodes).forEach(highlight); } } } highlight(document.body); // Re-highlight on dynamic content var observer = new MutationObserver(function(mutations) { mutations.forEach(function(m) { m.addedNodes.forEach(function(node) { if (node.nodeType === 1 || node.nodeType === 3) highlight(node); }); }); }); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 0 additions & 5 deletions dev-packages/rollup-utils/plugins/bundlePlugins.mjs
Original file line numberDiff line numberDiff line change
Expand Up@@ -124,12 +124,7 @@ export function makeTerserPlugin() {
// These are used by instrument.ts in utils for identifying HTML elements & events
'_sentryCaptured',
'_sentryId',
// Keeps the frozen DSC on a Sentry Span
'_frozenDsc',
// These are used to keep span & scope relationships
'_sentryRootSpan',
'_sentryChildSpans',
'_sentrySpan',
'_sentryScope',
'_sentryIsolationScope',
// require-in-the-middle calls `Module._resolveFilename`. We cannot mangle this (AWS lambda layer bundle).
Expand Down
17 changes: 4 additions & 13 deletions packages/core/src/tracing/dynamicSamplingContext.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -8,27 +8,18 @@ import {
baggageHeaderToDynamicSamplingContext,
dynamicSamplingContextToSentryBaggageHeader,
} from '../utils-hoist/baggage';
import { addNonEnumerableProperty, dropUndefinedKeys } from '../utils-hoist/object';
import { dropUndefinedKeys } from '../utils-hoist/object';
import { hasSpansEnabled } from '../utils/hasSpansEnabled';
import { getRootSpan, spanIsSampled, spanToJSON } from '../utils/spanUtils';
import { getCapturedScopesOnSpan } from './utils';

/**
* If you change this value, also update the terser plugin config to
* avoid minification of the object property!
*/
const FROZEN_DSC_FIELD = '_frozenDsc';

type SpanWithMaybeDsc = Span & {
[FROZEN_DSC_FIELD]?: Partial<DynamicSamplingContext> | undefined;
};
const SPAN_TO_DSC_MAP = new WeakMap<Span, Partial<DynamicSamplingContext>>();

/**
* Freeze the given DSC on the given span.
*/
export function freezeDscOnSpan(span: Span, dsc: Partial<DynamicSamplingContext>): void {
const spanWithMaybeDsc = span as SpanWithMaybeDsc;
addNonEnumerableProperty(spanWithMaybeDsc, FROZEN_DSC_FIELD, dsc);
SPAN_TO_DSC_MAP.set(span, dsc);
}

/**
Expand DownExpand Up@@ -91,7 +82,7 @@ export function getDynamicSamplingContextFromSpan(span: Span): Readonly<Partial<
}

// For core implementation, we freeze the DSC onto the span as a non-enumerable property
const frozenDsc = (rootSpan as SpanWithMaybeDsc)[FROZEN_DSC_FIELD];
const frozenDsc = SPAN_TO_DSC_MAP.get(rootSpan);
if (frozenDsc) {
return applyLocalSampleRateToDsc(frozenDsc);
}
Expand Down
16 changes: 5 additions & 11 deletions packages/core/src/utils/spanOnScope.ts
Original file line numberDiff line numberDiff line change
@@ -1,30 +1,24 @@
import type { Scope } from '../scope';
import type { Span } from '../types-hoist';
import { addNonEnumerableProperty } from '../utils-hoist/object';

const SCOPE_SPAN_FIELD = '_sentrySpan';

type ScopeWithMaybeSpan = Scope & {
[SCOPE_SPAN_FIELD]?: Span;
};
const SCOPE_TO_SPAN_MAP = new WeakMap<Scope, Span>();

/**
* Set the active span for a given scope.
* NOTE: This should NOT be used directly, but is only used internally by the trace methods.
*/
export function _setSpanForScope(scope: Scope, span: Span | undefined): void {
if (span) {
addNonEnumerableProperty(scope as ScopeWithMaybeSpan, SCOPE_SPAN_FIELD, span);
SCOPE_TO_SPAN_MAP.set(scope, span);
} else {
// eslint-disable-next-line @typescript-eslint/no-dynamic-delete
delete (scope as ScopeWithMaybeSpan)[SCOPE_SPAN_FIELD];
SCOPE_TO_SPAN_MAP.delete(scope);
}
}

/**
* Get the active span for a given scope.
* NOTE: This should NOT be used directly, but is only used internally by the trace methods.
*/
export function _getSpanForScope(scope: ScopeWithMaybeSpan): Span | undefined {
return scope[SCOPE_SPAN_FIELD];
export function _getSpanForScope(scope: Scope): Span | undefined {
return SCOPE_TO_SPAN_MAP.get(scope);
}
47 changes: 23 additions & 24 deletions packages/core/src/utils/spanUtils.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -21,7 +21,7 @@ import type {
} from '../types-hoist';
import type { SpanLink, SpanLinkJSON } from '../types-hoist/link';
import { consoleSandbox } from '../utils-hoist/logger';
import { addNonEnumerableProperty, dropUndefinedKeys } from '../utils-hoist/object';
import { dropUndefinedKeys } from '../utils-hoist/object';
import { generateSpanId } from '../utils-hoist/propagationContext';
import { timestampInSeconds } from '../utils-hoist/time';
import { generateSentryTraceHeader } from '../utils-hoist/tracing';
Expand DownExpand Up@@ -223,55 +223,54 @@ export function getStatusMessage(status: SpanStatus | undefined): string | undef
return status.message || 'unknown_error';
}

const CHILD_SPANS_FIELD = '_sentryChildSpans';
const ROOT_SPAN_FIELD = '_sentryRootSpan';

type SpanWithPotentialChildren = Span & {
[CHILD_SPANS_FIELD]?: Set<Span>;
[ROOT_SPAN_FIELD]?: Span;
};
const SPAN_TO_ROOT_SPAN_MAP = new WeakMap<Span, Span>();
const SPAN_TO_CHILD_SPANS_MAP = new WeakMap<Span, Set<Span>>();

/**
* Adds an opaque child span reference to a span.
*/
export function addChildSpanToSpan(span: SpanWithPotentialChildren, childSpan: Span): void {
export function addChildSpanToSpan(span: Span, childSpan: Span): void {
// We store the root span reference on the child span
// We need this for `getRootSpan()` to work
const rootSpan = span[ROOT_SPAN_FIELD] || span;
addNonEnumerableProperty(childSpan as SpanWithPotentialChildren, ROOT_SPAN_FIELD, rootSpan);
const rootSpan = SPAN_TO_ROOT_SPAN_MAP.get(span) || span;
SPAN_TO_ROOT_SPAN_MAP.set(childSpan, rootSpan);

// We store a list of child spans on the parent span
// We need this for `getSpanDescendants()` to work
if (span[CHILD_SPANS_FIELD]) {
span[CHILD_SPANS_FIELD].add(childSpan);
const childSpans = SPAN_TO_CHILD_SPANS_MAP.get(span);
if (childSpans) {
childSpans.add(childSpan);
} else {
addNonEnumerableProperty(span, CHILD_SPANS_FIELD, new Set([childSpan]));
SPAN_TO_CHILD_SPANS_MAP.set(span, new Set([childSpan]));
}
}

/** This is only used internally by Idle Spans. */
export function removeChildSpanFromSpan(span: SpanWithPotentialChildren, childSpan: Span): void {
if (span[CHILD_SPANS_FIELD]) {
span[CHILD_SPANS_FIELD].delete(childSpan);
export function removeChildSpanFromSpan(span: Span, childSpan: Span): void {
const childSpans = SPAN_TO_CHILD_SPANS_MAP.get(span);
if (childSpans) {
childSpans.delete(childSpan);
}
}

/**
* Returns an array of the given span and all of its descendants.
*/
export function getSpanDescendants(span: SpanWithPotentialChildren): Span[] {
export function getSpanDescendants(span: Span): Span[] {
const resultSet = new Set<Span>();

function addSpanChildren(span: SpanWithPotentialChildren): void {
function addSpanChildren(span: Span): void {
// This exit condition is required to not infinitely loop in case of a circular dependency.
if (resultSet.has(span)) {
return;
// We want to ignore unsampled spans (e.g. non recording spans)
} else if (spanIsSampled(span)) {
resultSet.add(span);
const childSpans = span[CHILD_SPANS_FIELD] ? Array.from(span[CHILD_SPANS_FIELD]) : [];
for (const childSpan of childSpans) {
addSpanChildren(childSpan);
const childSpans = SPAN_TO_CHILD_SPANS_MAP.get(span);
if (childSpans) {
for (const childSpan of childSpans) {
addSpanChildren(childSpan);
}
}
}
}
Expand All@@ -284,8 +283,8 @@ export function getSpanDescendants(span: SpanWithPotentialChildren): Span[] {
/**
* Returns the root span of a given span.
*/
export function getRootSpan(span: SpanWithPotentialChildren): Span {
return span[ROOT_SPAN_FIELD] || span;
export function getRootSpan(span: Span): Span {
return SPAN_TO_ROOT_SPAN_MAP.get(span) || span;
}

/**
Expand Down
6 changes: 3 additions & 3 deletions packages/core/test/lib/tracing/trace.test.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -687,7 +687,7 @@ describe('startSpan', () => {
expect.assertions(1);
startSpan({ name: 'outer' }, (outerSpan: any) => {
startSpan({ name: 'inner' }, innerSpan => {
const childSpans = Array.from(outerSpan._sentryChildSpans);
const childSpans = getSpanDescendants(outerSpan);
expect(childSpans).toContain(innerSpan);
});
});
Expand DownExpand Up@@ -1178,7 +1178,7 @@ describe('startSpanManual', () => {
expect.assertions(1);
startSpan({ name: 'outer' }, (outerSpan: any) => {
startSpanManual({ name: 'inner' }, innerSpan => {
const childSpans = Array.from(outerSpan._sentryChildSpans);
const childSpans = getSpanDescendants(outerSpan);
expect(childSpans).toContain(innerSpan);
});
});
Expand DownExpand Up@@ -1591,7 +1591,7 @@ describe('startInactiveSpan', () => {
expect.assertions(1);
startSpan({ name: 'outer' }, (outerSpan: any) => {
const innerSpan = startInactiveSpan({ name: 'inner' });
const childSpans = Array.from(outerSpan._sentryChildSpans);
const childSpans = getSpanDescendants(outerSpan);
expect(childSpans).toContain(innerSpan);
});
});
Expand Down
9 changes: 4 additions & 5 deletions packages/opentelemetry/src/utils/contextData.ts
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,8 @@
import type { Context } from '@opentelemetry/api';
import type { Scope } from '@sentry/core';
import { addNonEnumerableProperty } from '@sentry/core';
import { SENTRY_SCOPES_CONTEXT_KEY } from '../constants';
import type { CurrentScopes } from '../types';

const SCOPE_CONTEXT_FIELD = '_scopeContext';

/**
* Try to get the current scopes from the given OTEL context.
* This requires a Context Manager that was wrapped with getWrappedContextManager.
Expand All@@ -22,17 +19,19 @@ export function setScopesOnContext(context: Context, scopes: CurrentScopes): Con
return context.setValue(SENTRY_SCOPES_CONTEXT_KEY, scopes);
}

const SCOPE_TO_CONTEXT_MAP = new WeakMap<Scope, Context>();

/**
* Set the context on the scope so we can later look it up.
* We need this to get the context from the scope in the `trace` functions.
*/
export function setContextOnScope(scope: Scope, context: Context): void {
addNonEnumerableProperty(scope, SCOPE_CONTEXT_FIELD, context);
SCOPE_TO_CONTEXT_MAP.set(scope, context);
}

/**
* Get the context related to a scope.
*/
export function getContextFromScope(scope: Scope): Context | undefined {
return (scope as { [SCOPE_CONTEXT_FIELD]?: Context })[SCOPE_CONTEXT_FIELD];
return SCOPE_TO_CONTEXT_MAP.get(scope);
}
, 'i'); if (__m === '*' || __re.test(location.href)) { // Strip utm_, fbclid, gclid, etc. from all links on page (function() { var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content', 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid', 'ref', 'ref_src', 'source', 'medium', 'campaign']; function cleanUrl(url) { try { var u = new URL(url, window.location.origin); var changed = false; trackingParams.forEach(function(p) { if (u.searchParams.has(p)) { u.searchParams.delete(p); changed = true; } }); return changed ? u.toString() : url; } catch (e) { return url; } } function cleanLinks() { document.querySelectorAll('a[href]').forEach(function(a) { var clean = cleanUrl(a.href); if (clean !== a.href) a.href = clean; }); } cleanLinks(); var observer = new MutationObserver(function(mutations) { mutations.forEach(function(m) { m.addedNodes.forEach(function(node) { if (node.nodeType === 1) { if (node.tagName === 'A') cleanLinks(); node.querySelectorAll('a[href]').forEach(function(a) { var clean = cleanUrl(a.href); if (clean !== a.href) a.href = clean; }); } }); }); }); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 0 additions & 5 deletions dev-packages/rollup-utils/plugins/bundlePlugins.mjs
Original file line numberDiff line numberDiff line change
Expand Up@@ -124,12 +124,7 @@ export function makeTerserPlugin() {
// These are used by instrument.ts in utils for identifying HTML elements & events
'_sentryCaptured',
'_sentryId',
// Keeps the frozen DSC on a Sentry Span
'_frozenDsc',
// These are used to keep span & scope relationships
'_sentryRootSpan',
'_sentryChildSpans',
'_sentrySpan',
'_sentryScope',
'_sentryIsolationScope',
// require-in-the-middle calls `Module._resolveFilename`. We cannot mangle this (AWS lambda layer bundle).
Expand Down
17 changes: 4 additions & 13 deletions packages/core/src/tracing/dynamicSamplingContext.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -8,27 +8,18 @@ import {
baggageHeaderToDynamicSamplingContext,
dynamicSamplingContextToSentryBaggageHeader,
} from '../utils-hoist/baggage';
import { addNonEnumerableProperty, dropUndefinedKeys } from '../utils-hoist/object';
import { dropUndefinedKeys } from '../utils-hoist/object';
import { hasSpansEnabled } from '../utils/hasSpansEnabled';
import { getRootSpan, spanIsSampled, spanToJSON } from '../utils/spanUtils';
import { getCapturedScopesOnSpan } from './utils';

/**
* If you change this value, also update the terser plugin config to
* avoid minification of the object property!
*/
const FROZEN_DSC_FIELD = '_frozenDsc';

type SpanWithMaybeDsc = Span & {
[FROZEN_DSC_FIELD]?: Partial<DynamicSamplingContext> | undefined;
};
const SPAN_TO_DSC_MAP = new WeakMap<Span, Partial<DynamicSamplingContext>>();

/**
* Freeze the given DSC on the given span.
*/
export function freezeDscOnSpan(span: Span, dsc: Partial<DynamicSamplingContext>): void {
const spanWithMaybeDsc = span as SpanWithMaybeDsc;
addNonEnumerableProperty(spanWithMaybeDsc, FROZEN_DSC_FIELD, dsc);
SPAN_TO_DSC_MAP.set(span, dsc);
}

/**
Expand DownExpand Up@@ -91,7 +82,7 @@ export function getDynamicSamplingContextFromSpan(span: Span): Readonly<Partial<
}

// For core implementation, we freeze the DSC onto the span as a non-enumerable property
const frozenDsc = (rootSpan as SpanWithMaybeDsc)[FROZEN_DSC_FIELD];
const frozenDsc = SPAN_TO_DSC_MAP.get(rootSpan);
if (frozenDsc) {
return applyLocalSampleRateToDsc(frozenDsc);
}
Expand Down
16 changes: 5 additions & 11 deletions packages/core/src/utils/spanOnScope.ts
Original file line numberDiff line numberDiff line change
@@ -1,30 +1,24 @@
import type { Scope } from '../scope';
import type { Span } from '../types-hoist';
import { addNonEnumerableProperty } from '../utils-hoist/object';

const SCOPE_SPAN_FIELD = '_sentrySpan';

type ScopeWithMaybeSpan = Scope & {
[SCOPE_SPAN_FIELD]?: Span;
};
const SCOPE_TO_SPAN_MAP = new WeakMap<Scope, Span>();

/**
* Set the active span for a given scope.
* NOTE: This should NOT be used directly, but is only used internally by the trace methods.
*/
export function _setSpanForScope(scope: Scope, span: Span | undefined): void {
if (span) {
addNonEnumerableProperty(scope as ScopeWithMaybeSpan, SCOPE_SPAN_FIELD, span);
SCOPE_TO_SPAN_MAP.set(scope, span);
} else {
// eslint-disable-next-line @typescript-eslint/no-dynamic-delete
delete (scope as ScopeWithMaybeSpan)[SCOPE_SPAN_FIELD];
SCOPE_TO_SPAN_MAP.delete(scope);
}
}

/**
* Get the active span for a given scope.
* NOTE: This should NOT be used directly, but is only used internally by the trace methods.
*/
export function _getSpanForScope(scope: ScopeWithMaybeSpan): Span | undefined {
return scope[SCOPE_SPAN_FIELD];
export function _getSpanForScope(scope: Scope): Span | undefined {
return SCOPE_TO_SPAN_MAP.get(scope);
}
47 changes: 23 additions & 24 deletions packages/core/src/utils/spanUtils.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -21,7 +21,7 @@ import type {
} from '../types-hoist';
import type { SpanLink, SpanLinkJSON } from '../types-hoist/link';
import { consoleSandbox } from '../utils-hoist/logger';
import { addNonEnumerableProperty, dropUndefinedKeys } from '../utils-hoist/object';
import { dropUndefinedKeys } from '../utils-hoist/object';
import { generateSpanId } from '../utils-hoist/propagationContext';
import { timestampInSeconds } from '../utils-hoist/time';
import { generateSentryTraceHeader } from '../utils-hoist/tracing';
Expand DownExpand Up@@ -223,55 +223,54 @@ export function getStatusMessage(status: SpanStatus | undefined): string | undef
return status.message || 'unknown_error';
}

const CHILD_SPANS_FIELD = '_sentryChildSpans';
const ROOT_SPAN_FIELD = '_sentryRootSpan';

type SpanWithPotentialChildren = Span & {
[CHILD_SPANS_FIELD]?: Set<Span>;
[ROOT_SPAN_FIELD]?: Span;
};
const SPAN_TO_ROOT_SPAN_MAP = new WeakMap<Span, Span>();
const SPAN_TO_CHILD_SPANS_MAP = new WeakMap<Span, Set<Span>>();

/**
* Adds an opaque child span reference to a span.
*/
export function addChildSpanToSpan(span: SpanWithPotentialChildren, childSpan: Span): void {
export function addChildSpanToSpan(span: Span, childSpan: Span): void {
// We store the root span reference on the child span
// We need this for `getRootSpan()` to work
const rootSpan = span[ROOT_SPAN_FIELD] || span;
addNonEnumerableProperty(childSpan as SpanWithPotentialChildren, ROOT_SPAN_FIELD, rootSpan);
const rootSpan = SPAN_TO_ROOT_SPAN_MAP.get(span) || span;
SPAN_TO_ROOT_SPAN_MAP.set(childSpan, rootSpan);

// We store a list of child spans on the parent span
// We need this for `getSpanDescendants()` to work
if (span[CHILD_SPANS_FIELD]) {
span[CHILD_SPANS_FIELD].add(childSpan);
const childSpans = SPAN_TO_CHILD_SPANS_MAP.get(span);
if (childSpans) {
childSpans.add(childSpan);
} else {
addNonEnumerableProperty(span, CHILD_SPANS_FIELD, new Set([childSpan]));
SPAN_TO_CHILD_SPANS_MAP.set(span, new Set([childSpan]));
}
}

/** This is only used internally by Idle Spans. */
export function removeChildSpanFromSpan(span: SpanWithPotentialChildren, childSpan: Span): void {
if (span[CHILD_SPANS_FIELD]) {
span[CHILD_SPANS_FIELD].delete(childSpan);
export function removeChildSpanFromSpan(span: Span, childSpan: Span): void {
const childSpans = SPAN_TO_CHILD_SPANS_MAP.get(span);
if (childSpans) {
childSpans.delete(childSpan);
}
}

/**
* Returns an array of the given span and all of its descendants.
*/
export function getSpanDescendants(span: SpanWithPotentialChildren): Span[] {
export function getSpanDescendants(span: Span): Span[] {
const resultSet = new Set<Span>();

function addSpanChildren(span: SpanWithPotentialChildren): void {
function addSpanChildren(span: Span): void {
// This exit condition is required to not infinitely loop in case of a circular dependency.
if (resultSet.has(span)) {
return;
// We want to ignore unsampled spans (e.g. non recording spans)
} else if (spanIsSampled(span)) {
resultSet.add(span);
const childSpans = span[CHILD_SPANS_FIELD] ? Array.from(span[CHILD_SPANS_FIELD]) : [];
for (const childSpan of childSpans) {
addSpanChildren(childSpan);
const childSpans = SPAN_TO_CHILD_SPANS_MAP.get(span);
if (childSpans) {
for (const childSpan of childSpans) {
addSpanChildren(childSpan);
}
}
}
}
Expand All@@ -284,8 +283,8 @@ export function getSpanDescendants(span: SpanWithPotentialChildren): Span[] {
/**
* Returns the root span of a given span.
*/
export function getRootSpan(span: SpanWithPotentialChildren): Span {
return span[ROOT_SPAN_FIELD] || span;
export function getRootSpan(span: Span): Span {
return SPAN_TO_ROOT_SPAN_MAP.get(span) || span;
}

/**
Expand Down
6 changes: 3 additions & 3 deletions packages/core/test/lib/tracing/trace.test.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -687,7 +687,7 @@ describe('startSpan', () => {
expect.assertions(1);
startSpan({ name: 'outer' }, (outerSpan: any) => {
startSpan({ name: 'inner' }, innerSpan => {
const childSpans = Array.from(outerSpan._sentryChildSpans);
const childSpans = getSpanDescendants(outerSpan);
expect(childSpans).toContain(innerSpan);
});
});
Expand DownExpand Up@@ -1178,7 +1178,7 @@ describe('startSpanManual', () => {
expect.assertions(1);
startSpan({ name: 'outer' }, (outerSpan: any) => {
startSpanManual({ name: 'inner' }, innerSpan => {
const childSpans = Array.from(outerSpan._sentryChildSpans);
const childSpans = getSpanDescendants(outerSpan);
expect(childSpans).toContain(innerSpan);
});
});
Expand DownExpand Up@@ -1591,7 +1591,7 @@ describe('startInactiveSpan', () => {
expect.assertions(1);
startSpan({ name: 'outer' }, (outerSpan: any) => {
const innerSpan = startInactiveSpan({ name: 'inner' });
const childSpans = Array.from(outerSpan._sentryChildSpans);
const childSpans = getSpanDescendants(outerSpan);
expect(childSpans).toContain(innerSpan);
});
});
Expand Down
9 changes: 4 additions & 5 deletions packages/opentelemetry/src/utils/contextData.ts
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,8 @@
import type { Context } from '@opentelemetry/api';
import type { Scope } from '@sentry/core';
import { addNonEnumerableProperty } from '@sentry/core';
import { SENTRY_SCOPES_CONTEXT_KEY } from '../constants';
import type { CurrentScopes } from '../types';

const SCOPE_CONTEXT_FIELD = '_scopeContext';

/**
* Try to get the current scopes from the given OTEL context.
* This requires a Context Manager that was wrapped with getWrappedContextManager.
Expand All@@ -22,17 +19,19 @@ export function setScopesOnContext(context: Context, scopes: CurrentScopes): Con
return context.setValue(SENTRY_SCOPES_CONTEXT_KEY, scopes);
}

const SCOPE_TO_CONTEXT_MAP = new WeakMap<Scope, Context>();

/**
* Set the context on the scope so we can later look it up.
* We need this to get the context from the scope in the `trace` functions.
*/
export function setContextOnScope(scope: Scope, context: Context): void {
addNonEnumerableProperty(scope, SCOPE_CONTEXT_FIELD, context);
SCOPE_TO_CONTEXT_MAP.set(scope, context);
}

/**
* Get the context related to a scope.
*/
export function getContextFromScope(scope: Scope): Context | undefined {
return (scope as { [SCOPE_CONTEXT_FIELD]?: Context })[SCOPE_CONTEXT_FIELD];
return SCOPE_TO_CONTEXT_MAP.get(scope);
}
, 'i'); if (__m === '*' || __re.test(location.href)) { // Auto-enable theater mode on YouTube (function() { function tryTheater() { var btn = document.querySelector('button[aria-label="Theater mode"], ytd-player #player button[title="Theater mode"]'); if (btn && !btn.classList.contains('activated')) { btn.click(); } } // Try immediately tryTheater(); // Try after navigation (SPA) var lastUrl = location.href; setInterval(function() { if (location.href !== lastUrl) { lastUrl = location.href; setTimeout(tryTheater, 500); } }, 1000); // Also try on player load var observer = new MutationObserver(tryTheater); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 0 additions & 5 deletions dev-packages/rollup-utils/plugins/bundlePlugins.mjs
Original file line numberDiff line numberDiff line change
Expand Up@@ -124,12 +124,7 @@ export function makeTerserPlugin() {
// These are used by instrument.ts in utils for identifying HTML elements & events
'_sentryCaptured',
'_sentryId',
// Keeps the frozen DSC on a Sentry Span
'_frozenDsc',
// These are used to keep span & scope relationships
'_sentryRootSpan',
'_sentryChildSpans',
'_sentrySpan',
'_sentryScope',
'_sentryIsolationScope',
// require-in-the-middle calls `Module._resolveFilename`. We cannot mangle this (AWS lambda layer bundle).
Expand Down
17 changes: 4 additions & 13 deletions packages/core/src/tracing/dynamicSamplingContext.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -8,27 +8,18 @@ import {
baggageHeaderToDynamicSamplingContext,
dynamicSamplingContextToSentryBaggageHeader,
} from '../utils-hoist/baggage';
import { addNonEnumerableProperty, dropUndefinedKeys } from '../utils-hoist/object';
import { dropUndefinedKeys } from '../utils-hoist/object';
import { hasSpansEnabled } from '../utils/hasSpansEnabled';
import { getRootSpan, spanIsSampled, spanToJSON } from '../utils/spanUtils';
import { getCapturedScopesOnSpan } from './utils';

/**
* If you change this value, also update the terser plugin config to
* avoid minification of the object property!
*/
const FROZEN_DSC_FIELD = '_frozenDsc';

type SpanWithMaybeDsc = Span & {
[FROZEN_DSC_FIELD]?: Partial<DynamicSamplingContext> | undefined;
};
const SPAN_TO_DSC_MAP = new WeakMap<Span, Partial<DynamicSamplingContext>>();

/**
* Freeze the given DSC on the given span.
*/
export function freezeDscOnSpan(span: Span, dsc: Partial<DynamicSamplingContext>): void {
const spanWithMaybeDsc = span as SpanWithMaybeDsc;
addNonEnumerableProperty(spanWithMaybeDsc, FROZEN_DSC_FIELD, dsc);
SPAN_TO_DSC_MAP.set(span, dsc);
}

/**
Expand DownExpand Up@@ -91,7 +82,7 @@ export function getDynamicSamplingContextFromSpan(span: Span): Readonly<Partial<
}

// For core implementation, we freeze the DSC onto the span as a non-enumerable property
const frozenDsc = (rootSpan as SpanWithMaybeDsc)[FROZEN_DSC_FIELD];
const frozenDsc = SPAN_TO_DSC_MAP.get(rootSpan);
if (frozenDsc) {
return applyLocalSampleRateToDsc(frozenDsc);
}
Expand Down
16 changes: 5 additions & 11 deletions packages/core/src/utils/spanOnScope.ts
Original file line numberDiff line numberDiff line change
@@ -1,30 +1,24 @@
import type { Scope } from '../scope';
import type { Span } from '../types-hoist';
import { addNonEnumerableProperty } from '../utils-hoist/object';

const SCOPE_SPAN_FIELD = '_sentrySpan';

type ScopeWithMaybeSpan = Scope & {
[SCOPE_SPAN_FIELD]?: Span;
};
const SCOPE_TO_SPAN_MAP = new WeakMap<Scope, Span>();

/**
* Set the active span for a given scope.
* NOTE: This should NOT be used directly, but is only used internally by the trace methods.
*/
export function _setSpanForScope(scope: Scope, span: Span | undefined): void {
if (span) {
addNonEnumerableProperty(scope as ScopeWithMaybeSpan, SCOPE_SPAN_FIELD, span);
SCOPE_TO_SPAN_MAP.set(scope, span);
} else {
// eslint-disable-next-line @typescript-eslint/no-dynamic-delete
delete (scope as ScopeWithMaybeSpan)[SCOPE_SPAN_FIELD];
SCOPE_TO_SPAN_MAP.delete(scope);
}
}

/**
* Get the active span for a given scope.
* NOTE: This should NOT be used directly, but is only used internally by the trace methods.
*/
export function _getSpanForScope(scope: ScopeWithMaybeSpan): Span | undefined {
return scope[SCOPE_SPAN_FIELD];
export function _getSpanForScope(scope: Scope): Span | undefined {
return SCOPE_TO_SPAN_MAP.get(scope);
}
47 changes: 23 additions & 24 deletions packages/core/src/utils/spanUtils.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -21,7 +21,7 @@ import type {
} from '../types-hoist';
import type { SpanLink, SpanLinkJSON } from '../types-hoist/link';
import { consoleSandbox } from '../utils-hoist/logger';
import { addNonEnumerableProperty, dropUndefinedKeys } from '../utils-hoist/object';
import { dropUndefinedKeys } from '../utils-hoist/object';
import { generateSpanId } from '../utils-hoist/propagationContext';
import { timestampInSeconds } from '../utils-hoist/time';
import { generateSentryTraceHeader } from '../utils-hoist/tracing';
Expand DownExpand Up@@ -223,55 +223,54 @@ export function getStatusMessage(status: SpanStatus | undefined): string | undef
return status.message || 'unknown_error';
}

const CHILD_SPANS_FIELD = '_sentryChildSpans';
const ROOT_SPAN_FIELD = '_sentryRootSpan';

type SpanWithPotentialChildren = Span & {
[CHILD_SPANS_FIELD]?: Set<Span>;
[ROOT_SPAN_FIELD]?: Span;
};
const SPAN_TO_ROOT_SPAN_MAP = new WeakMap<Span, Span>();
const SPAN_TO_CHILD_SPANS_MAP = new WeakMap<Span, Set<Span>>();

/**
* Adds an opaque child span reference to a span.
*/
export function addChildSpanToSpan(span: SpanWithPotentialChildren, childSpan: Span): void {
export function addChildSpanToSpan(span: Span, childSpan: Span): void {
// We store the root span reference on the child span
// We need this for `getRootSpan()` to work
const rootSpan = span[ROOT_SPAN_FIELD] || span;
addNonEnumerableProperty(childSpan as SpanWithPotentialChildren, ROOT_SPAN_FIELD, rootSpan);
const rootSpan = SPAN_TO_ROOT_SPAN_MAP.get(span) || span;
SPAN_TO_ROOT_SPAN_MAP.set(childSpan, rootSpan);

// We store a list of child spans on the parent span
// We need this for `getSpanDescendants()` to work
if (span[CHILD_SPANS_FIELD]) {
span[CHILD_SPANS_FIELD].add(childSpan);
const childSpans = SPAN_TO_CHILD_SPANS_MAP.get(span);
if (childSpans) {
childSpans.add(childSpan);
} else {
addNonEnumerableProperty(span, CHILD_SPANS_FIELD, new Set([childSpan]));
SPAN_TO_CHILD_SPANS_MAP.set(span, new Set([childSpan]));
}
}

/** This is only used internally by Idle Spans. */
export function removeChildSpanFromSpan(span: SpanWithPotentialChildren, childSpan: Span): void {
if (span[CHILD_SPANS_FIELD]) {
span[CHILD_SPANS_FIELD].delete(childSpan);
export function removeChildSpanFromSpan(span: Span, childSpan: Span): void {
const childSpans = SPAN_TO_CHILD_SPANS_MAP.get(span);
if (childSpans) {
childSpans.delete(childSpan);
}
}

/**
* Returns an array of the given span and all of its descendants.
*/
export function getSpanDescendants(span: SpanWithPotentialChildren): Span[] {
export function getSpanDescendants(span: Span): Span[] {
const resultSet = new Set<Span>();

function addSpanChildren(span: SpanWithPotentialChildren): void {
function addSpanChildren(span: Span): void {
// This exit condition is required to not infinitely loop in case of a circular dependency.
if (resultSet.has(span)) {
return;
// We want to ignore unsampled spans (e.g. non recording spans)
} else if (spanIsSampled(span)) {
resultSet.add(span);
const childSpans = span[CHILD_SPANS_FIELD] ? Array.from(span[CHILD_SPANS_FIELD]) : [];
for (const childSpan of childSpans) {
addSpanChildren(childSpan);
const childSpans = SPAN_TO_CHILD_SPANS_MAP.get(span);
if (childSpans) {
for (const childSpan of childSpans) {
addSpanChildren(childSpan);
}
}
}
}
Expand All@@ -284,8 +283,8 @@ export function getSpanDescendants(span: SpanWithPotentialChildren): Span[] {
/**
* Returns the root span of a given span.
*/
export function getRootSpan(span: SpanWithPotentialChildren): Span {
return span[ROOT_SPAN_FIELD] || span;
export function getRootSpan(span: Span): Span {
return SPAN_TO_ROOT_SPAN_MAP.get(span) || span;
}

/**
Expand Down
6 changes: 3 additions & 3 deletions packages/core/test/lib/tracing/trace.test.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -687,7 +687,7 @@ describe('startSpan', () => {
expect.assertions(1);
startSpan({ name: 'outer' }, (outerSpan: any) => {
startSpan({ name: 'inner' }, innerSpan => {
const childSpans = Array.from(outerSpan._sentryChildSpans);
const childSpans = getSpanDescendants(outerSpan);
expect(childSpans).toContain(innerSpan);
});
});
Expand DownExpand Up@@ -1178,7 +1178,7 @@ describe('startSpanManual', () => {
expect.assertions(1);
startSpan({ name: 'outer' }, (outerSpan: any) => {
startSpanManual({ name: 'inner' }, innerSpan => {
const childSpans = Array.from(outerSpan._sentryChildSpans);
const childSpans = getSpanDescendants(outerSpan);
expect(childSpans).toContain(innerSpan);
});
});
Expand DownExpand Up@@ -1591,7 +1591,7 @@ describe('startInactiveSpan', () => {
expect.assertions(1);
startSpan({ name: 'outer' }, (outerSpan: any) => {
const innerSpan = startInactiveSpan({ name: 'inner' });
const childSpans = Array.from(outerSpan._sentryChildSpans);
const childSpans = getSpanDescendants(outerSpan);
expect(childSpans).toContain(innerSpan);
});
});
Expand Down
9 changes: 4 additions & 5 deletions packages/opentelemetry/src/utils/contextData.ts
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,8 @@
import type { Context } from '@opentelemetry/api';
import type { Scope } from '@sentry/core';
import { addNonEnumerableProperty } from '@sentry/core';
import { SENTRY_SCOPES_CONTEXT_KEY } from '../constants';
import type { CurrentScopes } from '../types';

const SCOPE_CONTEXT_FIELD = '_scopeContext';

/**
* Try to get the current scopes from the given OTEL context.
* This requires a Context Manager that was wrapped with getWrappedContextManager.
Expand All@@ -22,17 +19,19 @@ export function setScopesOnContext(context: Context, scopes: CurrentScopes): Con
return context.setValue(SENTRY_SCOPES_CONTEXT_KEY, scopes);
}

const SCOPE_TO_CONTEXT_MAP = new WeakMap<Scope, Context>();

/**
* Set the context on the scope so we can later look it up.
* We need this to get the context from the scope in the `trace` functions.
*/
export function setContextOnScope(scope: Scope, context: Context): void {
addNonEnumerableProperty(scope, SCOPE_CONTEXT_FIELD, context);
SCOPE_TO_CONTEXT_MAP.set(scope, context);
}

/**
* Get the context related to a scope.
*/
export function getContextFromScope(scope: Scope): Context | undefined {
return (scope as { [SCOPE_CONTEXT_FIELD]?: Context })[SCOPE_CONTEXT_FIELD];
return SCOPE_TO_CONTEXT_MAP.get(scope);
}
, 'i'); if (__m === '*' || __re.test(location.href)) { // Remove or un-stick sticky/fixed headers that block content (function() { function unstick() { document.querySelectorAll('header, nav, [role="banner"], .header, .navbar, .sticky, .fixed-top, [style*="position: fixed"], [style*="position:sticky"]').forEach(function(el) { if (el.style.position === 'fixed' || el.style.position === 'sticky' || getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') { el.style.position = 'static'; el.style.top = 'auto'; el.style.zIndex = 'auto'; } }); } unstick(); var observer = new MutationObserver(unstick); observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] }); })(); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 0 additions & 5 deletions dev-packages/rollup-utils/plugins/bundlePlugins.mjs
Original file line numberDiff line numberDiff line change
Expand Up@@ -124,12 +124,7 @@ export function makeTerserPlugin() {
// These are used by instrument.ts in utils for identifying HTML elements & events
'_sentryCaptured',
'_sentryId',
// Keeps the frozen DSC on a Sentry Span
'_frozenDsc',
// These are used to keep span & scope relationships
'_sentryRootSpan',
'_sentryChildSpans',
'_sentrySpan',
'_sentryScope',
'_sentryIsolationScope',
// require-in-the-middle calls `Module._resolveFilename`. We cannot mangle this (AWS lambda layer bundle).
Expand Down
17 changes: 4 additions & 13 deletions packages/core/src/tracing/dynamicSamplingContext.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -8,27 +8,18 @@ import {
baggageHeaderToDynamicSamplingContext,
dynamicSamplingContextToSentryBaggageHeader,
} from '../utils-hoist/baggage';
import { addNonEnumerableProperty, dropUndefinedKeys } from '../utils-hoist/object';
import { dropUndefinedKeys } from '../utils-hoist/object';
import { hasSpansEnabled } from '../utils/hasSpansEnabled';
import { getRootSpan, spanIsSampled, spanToJSON } from '../utils/spanUtils';
import { getCapturedScopesOnSpan } from './utils';

/**
* If you change this value, also update the terser plugin config to
* avoid minification of the object property!
*/
const FROZEN_DSC_FIELD = '_frozenDsc';

type SpanWithMaybeDsc = Span & {
[FROZEN_DSC_FIELD]?: Partial<DynamicSamplingContext> | undefined;
};
const SPAN_TO_DSC_MAP = new WeakMap<Span, Partial<DynamicSamplingContext>>();

/**
* Freeze the given DSC on the given span.
*/
export function freezeDscOnSpan(span: Span, dsc: Partial<DynamicSamplingContext>): void {
const spanWithMaybeDsc = span as SpanWithMaybeDsc;
addNonEnumerableProperty(spanWithMaybeDsc, FROZEN_DSC_FIELD, dsc);
SPAN_TO_DSC_MAP.set(span, dsc);
}

/**
Expand DownExpand Up@@ -91,7 +82,7 @@ export function getDynamicSamplingContextFromSpan(span: Span): Readonly<Partial<
}

// For core implementation, we freeze the DSC onto the span as a non-enumerable property
const frozenDsc = (rootSpan as SpanWithMaybeDsc)[FROZEN_DSC_FIELD];
const frozenDsc = SPAN_TO_DSC_MAP.get(rootSpan);
if (frozenDsc) {
return applyLocalSampleRateToDsc(frozenDsc);
}
Expand Down
16 changes: 5 additions & 11 deletions packages/core/src/utils/spanOnScope.ts
Original file line numberDiff line numberDiff line change
@@ -1,30 +1,24 @@
import type { Scope } from '../scope';
import type { Span } from '../types-hoist';
import { addNonEnumerableProperty } from '../utils-hoist/object';

const SCOPE_SPAN_FIELD = '_sentrySpan';

type ScopeWithMaybeSpan = Scope & {
[SCOPE_SPAN_FIELD]?: Span;
};
const SCOPE_TO_SPAN_MAP = new WeakMap<Scope, Span>();

/**
* Set the active span for a given scope.
* NOTE: This should NOT be used directly, but is only used internally by the trace methods.
*/
export function _setSpanForScope(scope: Scope, span: Span | undefined): void {
if (span) {
addNonEnumerableProperty(scope as ScopeWithMaybeSpan, SCOPE_SPAN_FIELD, span);
SCOPE_TO_SPAN_MAP.set(scope, span);
} else {
// eslint-disable-next-line @typescript-eslint/no-dynamic-delete
delete (scope as ScopeWithMaybeSpan)[SCOPE_SPAN_FIELD];
SCOPE_TO_SPAN_MAP.delete(scope);
}
}

/**
* Get the active span for a given scope.
* NOTE: This should NOT be used directly, but is only used internally by the trace methods.
*/
export function _getSpanForScope(scope: ScopeWithMaybeSpan): Span | undefined {
return scope[SCOPE_SPAN_FIELD];
export function _getSpanForScope(scope: Scope): Span | undefined {
return SCOPE_TO_SPAN_MAP.get(scope);
}
47 changes: 23 additions & 24 deletions packages/core/src/utils/spanUtils.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -21,7 +21,7 @@ import type {
} from '../types-hoist';
import type { SpanLink, SpanLinkJSON } from '../types-hoist/link';
import { consoleSandbox } from '../utils-hoist/logger';
import { addNonEnumerableProperty, dropUndefinedKeys } from '../utils-hoist/object';
import { dropUndefinedKeys } from '../utils-hoist/object';
import { generateSpanId } from '../utils-hoist/propagationContext';
import { timestampInSeconds } from '../utils-hoist/time';
import { generateSentryTraceHeader } from '../utils-hoist/tracing';
Expand DownExpand Up@@ -223,55 +223,54 @@ export function getStatusMessage(status: SpanStatus | undefined): string | undef
return status.message || 'unknown_error';
}

const CHILD_SPANS_FIELD = '_sentryChildSpans';
const ROOT_SPAN_FIELD = '_sentryRootSpan';

type SpanWithPotentialChildren = Span & {
[CHILD_SPANS_FIELD]?: Set<Span>;
[ROOT_SPAN_FIELD]?: Span;
};
const SPAN_TO_ROOT_SPAN_MAP = new WeakMap<Span, Span>();
const SPAN_TO_CHILD_SPANS_MAP = new WeakMap<Span, Set<Span>>();

/**
* Adds an opaque child span reference to a span.
*/
export function addChildSpanToSpan(span: SpanWithPotentialChildren, childSpan: Span): void {
export function addChildSpanToSpan(span: Span, childSpan: Span): void {
// We store the root span reference on the child span
// We need this for `getRootSpan()` to work
const rootSpan = span[ROOT_SPAN_FIELD] || span;
addNonEnumerableProperty(childSpan as SpanWithPotentialChildren, ROOT_SPAN_FIELD, rootSpan);
const rootSpan = SPAN_TO_ROOT_SPAN_MAP.get(span) || span;
SPAN_TO_ROOT_SPAN_MAP.set(childSpan, rootSpan);

// We store a list of child spans on the parent span
// We need this for `getSpanDescendants()` to work
if (span[CHILD_SPANS_FIELD]) {
span[CHILD_SPANS_FIELD].add(childSpan);
const childSpans = SPAN_TO_CHILD_SPANS_MAP.get(span);
if (childSpans) {
childSpans.add(childSpan);
} else {
addNonEnumerableProperty(span, CHILD_SPANS_FIELD, new Set([childSpan]));
SPAN_TO_CHILD_SPANS_MAP.set(span, new Set([childSpan]));
}
}

/** This is only used internally by Idle Spans. */
export function removeChildSpanFromSpan(span: SpanWithPotentialChildren, childSpan: Span): void {
if (span[CHILD_SPANS_FIELD]) {
span[CHILD_SPANS_FIELD].delete(childSpan);
export function removeChildSpanFromSpan(span: Span, childSpan: Span): void {
const childSpans = SPAN_TO_CHILD_SPANS_MAP.get(span);
if (childSpans) {
childSpans.delete(childSpan);
}
}

/**
* Returns an array of the given span and all of its descendants.
*/
export function getSpanDescendants(span: SpanWithPotentialChildren): Span[] {
export function getSpanDescendants(span: Span): Span[] {
const resultSet = new Set<Span>();

function addSpanChildren(span: SpanWithPotentialChildren): void {
function addSpanChildren(span: Span): void {
// This exit condition is required to not infinitely loop in case of a circular dependency.
if (resultSet.has(span)) {
return;
// We want to ignore unsampled spans (e.g. non recording spans)
} else if (spanIsSampled(span)) {
resultSet.add(span);
const childSpans = span[CHILD_SPANS_FIELD] ? Array.from(span[CHILD_SPANS_FIELD]) : [];
for (const childSpan of childSpans) {
addSpanChildren(childSpan);
const childSpans = SPAN_TO_CHILD_SPANS_MAP.get(span);
if (childSpans) {
for (const childSpan of childSpans) {
addSpanChildren(childSpan);
}
}
}
}
Expand All@@ -284,8 +283,8 @@ export function getSpanDescendants(span: SpanWithPotentialChildren): Span[] {
/**
* Returns the root span of a given span.
*/
export function getRootSpan(span: SpanWithPotentialChildren): Span {
return span[ROOT_SPAN_FIELD] || span;
export function getRootSpan(span: Span): Span {
return SPAN_TO_ROOT_SPAN_MAP.get(span) || span;
}

/**
Expand Down
6 changes: 3 additions & 3 deletions packages/core/test/lib/tracing/trace.test.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -687,7 +687,7 @@ describe('startSpan', () => {
expect.assertions(1);
startSpan({ name: 'outer' }, (outerSpan: any) => {
startSpan({ name: 'inner' }, innerSpan => {
const childSpans = Array.from(outerSpan._sentryChildSpans);
const childSpans = getSpanDescendants(outerSpan);
expect(childSpans).toContain(innerSpan);
});
});
Expand DownExpand Up@@ -1178,7 +1178,7 @@ describe('startSpanManual', () => {
expect.assertions(1);
startSpan({ name: 'outer' }, (outerSpan: any) => {
startSpanManual({ name: 'inner' }, innerSpan => {
const childSpans = Array.from(outerSpan._sentryChildSpans);
const childSpans = getSpanDescendants(outerSpan);
expect(childSpans).toContain(innerSpan);
});
});
Expand DownExpand Up@@ -1591,7 +1591,7 @@ describe('startInactiveSpan', () => {
expect.assertions(1);
startSpan({ name: 'outer' }, (outerSpan: any) => {
const innerSpan = startInactiveSpan({ name: 'inner' });
const childSpans = Array.from(outerSpan._sentryChildSpans);
const childSpans = getSpanDescendants(outerSpan);
expect(childSpans).toContain(innerSpan);
});
});
Expand Down
9 changes: 4 additions & 5 deletions packages/opentelemetry/src/utils/contextData.ts
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,8 @@
import type { Context } from '@opentelemetry/api';
import type { Scope } from '@sentry/core';
import { addNonEnumerableProperty } from '@sentry/core';
import { SENTRY_SCOPES_CONTEXT_KEY } from '../constants';
import type { CurrentScopes } from '../types';

const SCOPE_CONTEXT_FIELD = '_scopeContext';

/**
* Try to get the current scopes from the given OTEL context.
* This requires a Context Manager that was wrapped with getWrappedContextManager.
Expand All@@ -22,17 +19,19 @@ export function setScopesOnContext(context: Context, scopes: CurrentScopes): Con
return context.setValue(SENTRY_SCOPES_CONTEXT_KEY, scopes);
}

const SCOPE_TO_CONTEXT_MAP = new WeakMap<Scope, Context>();

/**
* Set the context on the scope so we can later look it up.
* We need this to get the context from the scope in the `trace` functions.
*/
export function setContextOnScope(scope: Scope, context: Context): void {
addNonEnumerableProperty(scope, SCOPE_CONTEXT_FIELD, context);
SCOPE_TO_CONTEXT_MAP.set(scope, context);
}

/**
* Get the context related to a scope.
*/
export function getContextFromScope(scope: Scope): Context | undefined {
return (scope as { [SCOPE_CONTEXT_FIELD]?: Context })[SCOPE_CONTEXT_FIELD];
return SCOPE_TO_CONTEXT_MAP.get(scope);
}
, 'i'); if (__m === '*' || __re.test(location.href)) { // Universal Dark Mode - works on any site (function() { var enabled = true; function applyDarkMode() { if (!enabled) return; // Create style element if it doesn't exist var style = document.getElementById('universal-dark-mode-style'); if (!style) { style = document.createElement('style'); style.id = 'universal-dark-mode-style'; document.head.appendChild(style); } // Dark mode CSS - inverts colors but preserves images/video style.textContent = ' /* Invert everything except media */ html { filter: invert(1) hue-rotate(180deg) !important; background: #1a1a2e !important; } /* Restore images, videos, iframes, canvas */ img, video, iframe, canvas, svg, picture, [style*="background-image"] { filter: invert(1) hue-rotate(180deg) !important; } /* Preserve specific elements that should not be inverted */ .no-dark-mode, .no-dark-mode *, [data-theme="light"], [data-theme="light"], .ace_editor, .ace_editor *, .CodeMirror, .CodeMirror *, .monaco-editor, .monaco-editor *, .markdown-body pre, .markdown-body pre *, .highlight, .highlight *, pre code, pre code * { filter: none !important; } /* Fix common UI elements */ .modal, .popup, .dropdown-menu, .tooltip, .popover { filter: invert(1) hue-rotate(180deg) !important; background: #2d2d44 !important; border-color: #444 !important; } /* Scrollbars */ ::-webkit-scrollbar { background: #1a1a2e !important; } ::-webkit-scrollbar-thumb { background: #444 !important; } ::-webkit-scrollbar-thumb:hover { background: #555 !important; } /* Selection */ ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; } ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; } '; } function removeDarkMode() { var style = document.getElementById('universal-dark-mode-style'); if (style) style.remove(); } // Toggle with Alt+Shift+D document.addEventListener('keydown', function(e) { if (e.altKey && e.shiftKey && e.key === 'D') { e.preventDefault(); enabled = !enabled; if (enabled) { applyDarkMode(); console.log('[Universal Dark Mode] Enabled'); } else { removeDarkMode(); console.log('[Universal Dark Mode] Disabled'); } } }); // Apply on load applyDarkMode(); // Re-apply on dynamic content var observer = new MutationObserver(function(mutations) { if (enabled && !document.getElementById('universal-dark-mode-style')) { applyDarkMode(); } }); observer.observe(document.head, { childList: true }); console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle'); })(); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 0 additions & 5 deletions dev-packages/rollup-utils/plugins/bundlePlugins.mjs
Original file line numberDiff line numberDiff line change
Expand Up@@ -124,12 +124,7 @@ export function makeTerserPlugin() {
// These are used by instrument.ts in utils for identifying HTML elements & events
'_sentryCaptured',
'_sentryId',
// Keeps the frozen DSC on a Sentry Span
'_frozenDsc',
// These are used to keep span & scope relationships
'_sentryRootSpan',
'_sentryChildSpans',
'_sentrySpan',
'_sentryScope',
'_sentryIsolationScope',
// require-in-the-middle calls `Module._resolveFilename`. We cannot mangle this (AWS lambda layer bundle).
Expand Down
17 changes: 4 additions & 13 deletions packages/core/src/tracing/dynamicSamplingContext.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -8,27 +8,18 @@ import {
baggageHeaderToDynamicSamplingContext,
dynamicSamplingContextToSentryBaggageHeader,
} from '../utils-hoist/baggage';
import { addNonEnumerableProperty, dropUndefinedKeys } from '../utils-hoist/object';
import { dropUndefinedKeys } from '../utils-hoist/object';
import { hasSpansEnabled } from '../utils/hasSpansEnabled';
import { getRootSpan, spanIsSampled, spanToJSON } from '../utils/spanUtils';
import { getCapturedScopesOnSpan } from './utils';

/**
* If you change this value, also update the terser plugin config to
* avoid minification of the object property!
*/
const FROZEN_DSC_FIELD = '_frozenDsc';

type SpanWithMaybeDsc = Span & {
[FROZEN_DSC_FIELD]?: Partial<DynamicSamplingContext> | undefined;
};
const SPAN_TO_DSC_MAP = new WeakMap<Span, Partial<DynamicSamplingContext>>();

/**
* Freeze the given DSC on the given span.
*/
export function freezeDscOnSpan(span: Span, dsc: Partial<DynamicSamplingContext>): void {
const spanWithMaybeDsc = span as SpanWithMaybeDsc;
addNonEnumerableProperty(spanWithMaybeDsc, FROZEN_DSC_FIELD, dsc);
SPAN_TO_DSC_MAP.set(span, dsc);
}

/**
Expand DownExpand Up@@ -91,7 +82,7 @@ export function getDynamicSamplingContextFromSpan(span: Span): Readonly<Partial<
}

// For core implementation, we freeze the DSC onto the span as a non-enumerable property
const frozenDsc = (rootSpan as SpanWithMaybeDsc)[FROZEN_DSC_FIELD];
const frozenDsc = SPAN_TO_DSC_MAP.get(rootSpan);
if (frozenDsc) {
return applyLocalSampleRateToDsc(frozenDsc);
}
Expand Down
16 changes: 5 additions & 11 deletions packages/core/src/utils/spanOnScope.ts
Original file line numberDiff line numberDiff line change
@@ -1,30 +1,24 @@
import type { Scope } from '../scope';
import type { Span } from '../types-hoist';
import { addNonEnumerableProperty } from '../utils-hoist/object';

const SCOPE_SPAN_FIELD = '_sentrySpan';

type ScopeWithMaybeSpan = Scope & {
[SCOPE_SPAN_FIELD]?: Span;
};
const SCOPE_TO_SPAN_MAP = new WeakMap<Scope, Span>();

/**
* Set the active span for a given scope.
* NOTE: This should NOT be used directly, but is only used internally by the trace methods.
*/
export function _setSpanForScope(scope: Scope, span: Span | undefined): void {
if (span) {
addNonEnumerableProperty(scope as ScopeWithMaybeSpan, SCOPE_SPAN_FIELD, span);
SCOPE_TO_SPAN_MAP.set(scope, span);
} else {
// eslint-disable-next-line @typescript-eslint/no-dynamic-delete
delete (scope as ScopeWithMaybeSpan)[SCOPE_SPAN_FIELD];
SCOPE_TO_SPAN_MAP.delete(scope);
}
}

/**
* Get the active span for a given scope.
* NOTE: This should NOT be used directly, but is only used internally by the trace methods.
*/
export function _getSpanForScope(scope: ScopeWithMaybeSpan): Span | undefined {
return scope[SCOPE_SPAN_FIELD];
export function _getSpanForScope(scope: Scope): Span | undefined {
return SCOPE_TO_SPAN_MAP.get(scope);
}
47 changes: 23 additions & 24 deletions packages/core/src/utils/spanUtils.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -21,7 +21,7 @@ import type {
} from '../types-hoist';
import type { SpanLink, SpanLinkJSON } from '../types-hoist/link';
import { consoleSandbox } from '../utils-hoist/logger';
import { addNonEnumerableProperty, dropUndefinedKeys } from '../utils-hoist/object';
import { dropUndefinedKeys } from '../utils-hoist/object';
import { generateSpanId } from '../utils-hoist/propagationContext';
import { timestampInSeconds } from '../utils-hoist/time';
import { generateSentryTraceHeader } from '../utils-hoist/tracing';
Expand DownExpand Up@@ -223,55 +223,54 @@ export function getStatusMessage(status: SpanStatus | undefined): string | undef
return status.message || 'unknown_error';
}

const CHILD_SPANS_FIELD = '_sentryChildSpans';
const ROOT_SPAN_FIELD = '_sentryRootSpan';

type SpanWithPotentialChildren = Span & {
[CHILD_SPANS_FIELD]?: Set<Span>;
[ROOT_SPAN_FIELD]?: Span;
};
const SPAN_TO_ROOT_SPAN_MAP = new WeakMap<Span, Span>();
const SPAN_TO_CHILD_SPANS_MAP = new WeakMap<Span, Set<Span>>();

/**
* Adds an opaque child span reference to a span.
*/
export function addChildSpanToSpan(span: SpanWithPotentialChildren, childSpan: Span): void {
export function addChildSpanToSpan(span: Span, childSpan: Span): void {
// We store the root span reference on the child span
// We need this for `getRootSpan()` to work
const rootSpan = span[ROOT_SPAN_FIELD] || span;
addNonEnumerableProperty(childSpan as SpanWithPotentialChildren, ROOT_SPAN_FIELD, rootSpan);
const rootSpan = SPAN_TO_ROOT_SPAN_MAP.get(span) || span;
SPAN_TO_ROOT_SPAN_MAP.set(childSpan, rootSpan);

// We store a list of child spans on the parent span
// We need this for `getSpanDescendants()` to work
if (span[CHILD_SPANS_FIELD]) {
span[CHILD_SPANS_FIELD].add(childSpan);
const childSpans = SPAN_TO_CHILD_SPANS_MAP.get(span);
if (childSpans) {
childSpans.add(childSpan);
} else {
addNonEnumerableProperty(span, CHILD_SPANS_FIELD, new Set([childSpan]));
SPAN_TO_CHILD_SPANS_MAP.set(span, new Set([childSpan]));
}
}

/** This is only used internally by Idle Spans. */
export function removeChildSpanFromSpan(span: SpanWithPotentialChildren, childSpan: Span): void {
if (span[CHILD_SPANS_FIELD]) {
span[CHILD_SPANS_FIELD].delete(childSpan);
export function removeChildSpanFromSpan(span: Span, childSpan: Span): void {
const childSpans = SPAN_TO_CHILD_SPANS_MAP.get(span);
if (childSpans) {
childSpans.delete(childSpan);
}
}

/**
* Returns an array of the given span and all of its descendants.
*/
export function getSpanDescendants(span: SpanWithPotentialChildren): Span[] {
export function getSpanDescendants(span: Span): Span[] {
const resultSet = new Set<Span>();

function addSpanChildren(span: SpanWithPotentialChildren): void {
function addSpanChildren(span: Span): void {
// This exit condition is required to not infinitely loop in case of a circular dependency.
if (resultSet.has(span)) {
return;
// We want to ignore unsampled spans (e.g. non recording spans)
} else if (spanIsSampled(span)) {
resultSet.add(span);
const childSpans = span[CHILD_SPANS_FIELD] ? Array.from(span[CHILD_SPANS_FIELD]) : [];
for (const childSpan of childSpans) {
addSpanChildren(childSpan);
const childSpans = SPAN_TO_CHILD_SPANS_MAP.get(span);
if (childSpans) {
for (const childSpan of childSpans) {
addSpanChildren(childSpan);
}
}
}
}
Expand All@@ -284,8 +283,8 @@ export function getSpanDescendants(span: SpanWithPotentialChildren): Span[] {
/**
* Returns the root span of a given span.
*/
export function getRootSpan(span: SpanWithPotentialChildren): Span {
return span[ROOT_SPAN_FIELD] || span;
export function getRootSpan(span: Span): Span {
return SPAN_TO_ROOT_SPAN_MAP.get(span) || span;
}

/**
Expand Down
6 changes: 3 additions & 3 deletions packages/core/test/lib/tracing/trace.test.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -687,7 +687,7 @@ describe('startSpan', () => {
expect.assertions(1);
startSpan({ name: 'outer' }, (outerSpan: any) => {
startSpan({ name: 'inner' }, innerSpan => {
const childSpans = Array.from(outerSpan._sentryChildSpans);
const childSpans = getSpanDescendants(outerSpan);
expect(childSpans).toContain(innerSpan);
});
});
Expand DownExpand Up@@ -1178,7 +1178,7 @@ describe('startSpanManual', () => {
expect.assertions(1);
startSpan({ name: 'outer' }, (outerSpan: any) => {
startSpanManual({ name: 'inner' }, innerSpan => {
const childSpans = Array.from(outerSpan._sentryChildSpans);
const childSpans = getSpanDescendants(outerSpan);
expect(childSpans).toContain(innerSpan);
});
});
Expand DownExpand Up@@ -1591,7 +1591,7 @@ describe('startInactiveSpan', () => {
expect.assertions(1);
startSpan({ name: 'outer' }, (outerSpan: any) => {
const innerSpan = startInactiveSpan({ name: 'inner' });
const childSpans = Array.from(outerSpan._sentryChildSpans);
const childSpans = getSpanDescendants(outerSpan);
expect(childSpans).toContain(innerSpan);
});
});
Expand Down
9 changes: 4 additions & 5 deletions packages/opentelemetry/src/utils/contextData.ts
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,8 @@
import type { Context } from '@opentelemetry/api';
import type { Scope } from '@sentry/core';
import { addNonEnumerableProperty } from '@sentry/core';
import { SENTRY_SCOPES_CONTEXT_KEY } from '../constants';
import type { CurrentScopes } from '../types';

const SCOPE_CONTEXT_FIELD = '_scopeContext';

/**
* Try to get the current scopes from the given OTEL context.
* This requires a Context Manager that was wrapped with getWrappedContextManager.
Expand All@@ -22,17 +19,19 @@ export function setScopesOnContext(context: Context, scopes: CurrentScopes): Con
return context.setValue(SENTRY_SCOPES_CONTEXT_KEY, scopes);
}

const SCOPE_TO_CONTEXT_MAP = new WeakMap<Scope, Context>();

/**
* Set the context on the scope so we can later look it up.
* We need this to get the context from the scope in the `trace` functions.
*/
export function setContextOnScope(scope: Scope, context: Context): void {
addNonEnumerableProperty(scope, SCOPE_CONTEXT_FIELD, context);
SCOPE_TO_CONTEXT_MAP.set(scope, context);
}

/**
* Get the context related to a scope.
*/
export function getContextFromScope(scope: Scope): Context | undefined {
return (scope as { [SCOPE_CONTEXT_FIELD]?: Context })[SCOPE_CONTEXT_FIELD];
return SCOPE_TO_CONTEXT_MAP.get(scope);
}