Skip to content

feat(tracing): Move common tracing code to core #7166

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 14 commits into from
Closed
1 change: 1 addition & 0 deletions packages/core/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ export type { ClientClass } from './sdk';
export type { Carrier, Layer } from './hub';
export type { OfflineStore, OfflineTransportOptions } from './transports/offline';

export * from './tracing';
export {
addBreadcrumb,
captureException,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,17 +1,8 @@
import type { Hub } from '@sentry/core';
import { getMainCarrier } from '@sentry/core';
import type {
ClientOptions,
CustomSamplingContext,
Integration,
IntegrationClass,
Options,
SamplingContext,
TransactionContext,
} from '@sentry/types';
import { dynamicRequire, isNaN, isNodeEnv, loadModule, logger } from '@sentry/utils';
import type { ClientOptions, CustomSamplingContext, Options, SamplingContext, TransactionContext } from '@sentry/types';
import { isNaN, logger } from '@sentry/utils';

import { registerErrorInstrumentation } from './errors';
import type { Hub } from '../';
import { getMainCarrier } from '../';
import { IdleTransaction } from './idletransaction';
import { Transaction } from './transaction';
import { hasTracingEnabled } from './utils';
Expand Down Expand Up @@ -220,9 +211,9 @@ export function startIdleTransaction(
}

/**
* @private
* Adds tracing extensions to the global hub.
*/
export function _addTracingExtensions(): void {
export function addTracingExtensions(): void {
const carrier = getMainCarrier();
if (!carrier.__SENTRY__) {
return;
Expand All @@ -235,70 +226,3 @@ export function _addTracingExtensions(): void {
carrier.__SENTRY__.extensions.traceHeaders = traceHeaders;
}
}

/**
* @private
*/
function _autoloadDatabaseIntegrations(): void {
const carrier = getMainCarrier();
if (!carrier.__SENTRY__) {
return;
}

const packageToIntegrationMapping: Record<string, () => Integration> = {
mongodb() {
const integration = dynamicRequire(module, './integrations/node/mongo') as {
Mongo: IntegrationClass<Integration>;
};
return new integration.Mongo();
},
mongoose() {
const integration = dynamicRequire(module, './integrations/node/mongo') as {
Mongo: IntegrationClass<Integration>;
};
return new integration.Mongo({ mongoose: true });
},
mysql() {
const integration = dynamicRequire(module, './integrations/node/mysql') as {
Mysql: IntegrationClass<Integration>;
};
return new integration.Mysql();
},
pg() {
const integration = dynamicRequire(module, './integrations/node/postgres') as {
Postgres: IntegrationClass<Integration>;
};
return new integration.Postgres();
},
};

const mappedPackages = Object.keys(packageToIntegrationMapping)
.filter(moduleName => !!loadModule(moduleName))
.map(pkg => {
try {
return packageToIntegrationMapping[pkg]();
} catch (e) {
return undefined;
}
})
.filter(p => p) as Integration[];

if (mappedPackages.length > 0) {
carrier.__SENTRY__.integrations = [...(carrier.__SENTRY__.integrations || []), ...mappedPackages];
}
}

/**
* This patches the global object and injects the Tracing extensions methods
*/
export function addExtensionMethods(): void {
_addTracingExtensions();

// Detect and automatically load specified integrations.
if (isNodeEnv()) {
_autoloadDatabaseIntegrations();
}

// If an error happens globally, we should make sure transaction status is set to error.
registerErrorInstrumentation();
}
Original file line number Diff line number Diff line change
@@ -1,15 +1,17 @@
/* eslint-disable max-lines */
import type { Hub } from '@sentry/core';
import type { TransactionContext } from '@sentry/types';
import { logger, timestampWithMs } from '@sentry/utils';

import type { Hub } from '..';
import type { Span } from './span';
import { SpanRecorder } from './span';
import { Transaction } from './transaction';

export const DEFAULT_IDLE_TIMEOUT = 1000;
export const DEFAULT_FINAL_TIMEOUT = 30000;
export const DEFAULT_HEARTBEAT_INTERVAL = 5000;
export const TRACING_DEFAULTS = {
idleTimeout: 1000,
finalTimeout: 30000,
heartbeatInterval: 5000,
};

/**
* @inheritDoc
Expand Down Expand Up @@ -81,12 +83,12 @@ export class IdleTransaction extends Transaction {
* The time to wait in ms until the idle transaction will be finished. This timer is started each time
* there are no active spans on this transaction.
*/
private readonly _idleTimeout: number = DEFAULT_IDLE_TIMEOUT,
private readonly _idleTimeout: number = TRACING_DEFAULTS.idleTimeout,
/**
* The final value in ms that a transaction cannot exceed
*/
private readonly _finalTimeout: number = DEFAULT_FINAL_TIMEOUT,
private readonly _heartbeatInterval: number = DEFAULT_HEARTBEAT_INTERVAL,
private readonly _finalTimeout: number = TRACING_DEFAULTS.finalTimeout,
private readonly _heartbeatInterval: number = TRACING_DEFAULTS.heartbeatInterval,
// Whether or not the transaction should put itself on the scope when it starts and pop itself off when it ends
private readonly _onScope: boolean = false,
) {
Expand Down
14 changes: 14 additions & 0 deletions packages/core/src/tracing/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
export { startIdleTransaction, addTracingExtensions } from './hubextensions';
export { IdleTransaction, TRACING_DEFAULTS } from './idletransaction';
export { Span, spanStatusfromHttpCode } from './span';
export { Transaction } from './transaction';
export {
extractTraceparentData,
getActiveTransaction,
hasTracingEnabled,
stripUrlQueryAndFragment,
TRACEPARENT_REGEXP,
} from './utils';
// eslint-disable-next-line deprecation/deprecation
export { SpanStatus } from './spanstatus';
export type { SpanStatusType } from './span';
File renamed without changes.
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
import type { Hub } from '@sentry/core';
import { getCurrentHub } from '@sentry/core';
import type {
Context,
Contexts,
Expand All @@ -13,6 +11,8 @@ import type {
} from '@sentry/types';
import { dropUndefinedKeys, logger } from '@sentry/utils';

import type { Hub } from '..';
import { getCurrentHub } from '..';
import { Span as SpanClass, SpanRecorder } from './span';

/** JSDoc */
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import type { Hub } from '@sentry/core';
import { getCurrentHub } from '@sentry/core';
import type { Options, Transaction } from '@sentry/types';

import type { Hub } from '..';
import { getCurrentHub } from '..';

/**
* The `extractTraceparentData` function and `TRACEPARENT_REGEXP` constant used
* to be declared in this file. It was later moved into `@sentry/utils` as part of a
Expand Down Expand Up @@ -36,21 +37,5 @@ export function getActiveTransaction<T extends Transaction>(maybeHub?: Hub): T |
return scope && (scope.getTransaction() as T | undefined);
}

/**
* Converts from milliseconds to seconds
* @param time time in ms
*/
export function msToSec(time: number): number {
return time / 1000;
}

/**
* Converts from seconds to milliseconds
* @param time time in seconds
*/
export function secToMs(time: number): number {
return time * 1000;
}

// so it can be used in manual instrumentation without necessitating a hard dependency on @sentry/utils
export { stripUrlQueryAndFragment } from '@sentry/utils';
2 changes: 2 additions & 0 deletions packages/nextjs/src/index.types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,8 @@ export declare const ErrorBoundary: typeof clientSdk.ErrorBoundary;
export declare const showReportDialog: typeof clientSdk.showReportDialog;
export declare const withErrorBoundary: typeof clientSdk.withErrorBoundary;

export declare const Span: typeof edgeSdk.Span;

/**
* @deprecated Use `wrapApiHandlerWithSentry` instead
*/
Expand Down
5 changes: 2 additions & 3 deletions packages/tracing/src/browser/backgroundtab.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
import type { IdleTransaction, SpanStatusType } from '@sentry/core';
import { getActiveTransaction } from '@sentry/core';
import { logger } from '@sentry/utils';

import type { IdleTransaction } from '../idletransaction';
import type { SpanStatusType } from '../span';
import { getActiveTransaction } from '../utils';
import { WINDOW } from './types';

/**
Expand Down
11 changes: 3 additions & 8 deletions packages/tracing/src/browser/browsertracing.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,9 @@
/* eslint-disable max-lines */
import type { Hub } from '@sentry/core';
import type { Hub, IdleTransaction } from '@sentry/core';
import { extractTraceparentData, startIdleTransaction, TRACING_DEFAULTS } from '@sentry/core';
import type { EventProcessor, Integration, Transaction, TransactionContext, TransactionSource } from '@sentry/types';
import { baggageHeaderToDynamicSamplingContext, getDomElement, logger } from '@sentry/utils';

import { startIdleTransaction } from '../hubextensions';
import type { IdleTransaction } from '../idletransaction';
import { DEFAULT_FINAL_TIMEOUT, DEFAULT_HEARTBEAT_INTERVAL, DEFAULT_IDLE_TIMEOUT } from '../idletransaction';
import { extractTraceparentData } from '../utils';
import { registerBackgroundTabDetection } from './backgroundtab';
import { addPerformanceEntries, startTrackingLongTasks, startTrackingWebVitals } from './metrics';
import type { RequestInstrumentationOptions } from './request';
Expand Down Expand Up @@ -127,9 +124,7 @@ export interface BrowserTracingOptions extends RequestInstrumentationOptions {
}

const DEFAULT_BROWSER_TRACING_OPTIONS: BrowserTracingOptions = {
idleTimeout: DEFAULT_IDLE_TIMEOUT,
finalTimeout: DEFAULT_FINAL_TIMEOUT,
heartbeatInterval: DEFAULT_HEARTBEAT_INTERVAL,
...TRACING_DEFAULTS,
markBackgroundTransactions: true,
routingInstrumentation: instrumentRoutingWithDefaults,
startTransactionOnLocationChange: true,
Expand Down
13 changes: 10 additions & 3 deletions packages/tracing/src/browser/metrics/index.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
/* eslint-disable max-lines */
import type { IdleTransaction, Transaction } from '@sentry/core';
import { getActiveTransaction } from '@sentry/core';
import type { Measurements } from '@sentry/types';
import { browserPerformanceTimeOrigin, htmlTreeAsString, logger } from '@sentry/utils';

import type { IdleTransaction } from '../../idletransaction';
import type { Transaction } from '../../transaction';
import { getActiveTransaction, msToSec } from '../../utils';
import { WINDOW } from '../types';
import { onCLS } from '../web-vitals/getCLS';
import { onFID } from '../web-vitals/getFID';
Expand All @@ -14,6 +13,14 @@ import { observe } from '../web-vitals/lib/observe';
import type { NavigatorDeviceMemory, NavigatorNetworkInformation } from '../web-vitals/types';
import { _startChild, isMeasurementValue } from './utils';

/**
* Converts from milliseconds to seconds
* @param time time in ms
*/
function msToSec(time: number): number {
return time / 1000;
}

function getBrowserPerformanceAPI(): Performance | undefined {
return WINDOW && WINDOW.addEventListener && WINDOW.performance;
}
Expand Down
3 changes: 1 addition & 2 deletions packages/tracing/src/browser/metrics/utils.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import type { Transaction } from '@sentry/core';
import type { Span, SpanContext } from '@sentry/types';

import type { Transaction } from '../../transaction';

/**
* Checks if a given value is a valid measurement value.
*/
Expand Down
4 changes: 1 addition & 3 deletions packages/tracing/src/browser/request.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/* eslint-disable max-lines */
import { getCurrentHub } from '@sentry/core';
import { getCurrentHub, hasTracingEnabled } from '@sentry/core';
import type { DynamicSamplingContext, Span } from '@sentry/types';
import {
addInstrumentationHandler,
Expand All @@ -9,8 +9,6 @@ import {
stringMatchesSomePattern,
} from '@sentry/utils';

import { hasTracingEnabled } from '../utils';

export const DEFAULT_TRACE_PROPAGATION_TARGETS = ['localhost', /^\//];

/** Options for Request Instrumentation */
Expand Down
5 changes: 2 additions & 3 deletions packages/tracing/src/errors.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
import type { SpanStatusType } from '@sentry/core';
import { getActiveTransaction } from '@sentry/core';
import { addInstrumentationHandler, logger } from '@sentry/utils';

import type { SpanStatusType } from './span';
import { getActiveTransaction } from './utils';

/**
* Configures global error listeners
*/
Expand Down
72 changes: 72 additions & 0 deletions packages/tracing/src/extensions.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
import { addTracingExtensions, getMainCarrier } from '@sentry/core';
import type { Integration, IntegrationClass } from '@sentry/types';
import { dynamicRequire, isNodeEnv, loadModule } from '@sentry/utils';

import { registerErrorInstrumentation } from './errors';

/**
* @private
*/
function _autoloadDatabaseIntegrations(): void {
const carrier = getMainCarrier();
if (!carrier.__SENTRY__) {
return;
}

const packageToIntegrationMapping: Record<string, () => Integration> = {
mongodb() {
const integration = dynamicRequire(module, './integrations/node/mongo') as {
Mongo: IntegrationClass<Integration>;
};
return new integration.Mongo();
},
mongoose() {
const integration = dynamicRequire(module, './integrations/node/mongo') as {
Mongo: IntegrationClass<Integration>;
};
return new integration.Mongo({ mongoose: true });
},
mysql() {
const integration = dynamicRequire(module, './integrations/node/mysql') as {
Mysql: IntegrationClass<Integration>;
};
return new integration.Mysql();
},
pg() {
const integration = dynamicRequire(module, './integrations/node/postgres') as {
Postgres: IntegrationClass<Integration>;
};
return new integration.Postgres();
},
};

const mappedPackages = Object.keys(packageToIntegrationMapping)
.filter(moduleName => !!loadModule(moduleName))
.map(pkg => {
try {
return packageToIntegrationMapping[pkg]();
} catch (e) {
return undefined;
}
})
.filter(p => p) as Integration[];

if (mappedPackages.length > 0) {
carrier.__SENTRY__.integrations = [...(carrier.__SENTRY__.integrations || []), ...mappedPackages];
}
}

/**
* This patches the global object and injects the Tracing extensions methods
*/
export function addExtensionMethods(): void {
addTracingExtensions();

// Detect and automatically load specified integrations.
if (isNodeEnv()) {
_autoloadDatabaseIntegrations();
}

// If an error happens globally, we should make sure transaction status is set to error.
registerErrorInstrumentation();
}
Loading