@sentry/apm
Advanced tools
Comparing version 5.16.0-beta.3 to 5.16.0-beta.4
Object.defineProperty(exports, "__esModule", { value: true }); | ||
var hub_1 = require("@sentry/hub"); | ||
var utils_1 = require("@sentry/utils"); | ||
var span_1 = require("./span"); | ||
var transaction_1 = require("./transaction"); | ||
/** Returns all trace headers that are currently on the top scope. */ | ||
function traceHeaders() { | ||
// @ts-ignore | ||
var that = this; | ||
var scope = that.getScope(); | ||
var scope = this.getScope(); | ||
if (scope) { | ||
@@ -24,35 +24,43 @@ var span = scope.getSpan(); | ||
* | ||
* @param spanContext Properties with which the span should be created | ||
* @param context Properties with which the span should be created | ||
*/ | ||
function startSpan(spanContext) { | ||
// @ts-ignore | ||
var hub = this; | ||
var scope = hub.getScope(); | ||
var client = hub.getClient(); | ||
var span; | ||
// This flag determines if we already added the span as a child to the span that currently lives on the scope | ||
// If we do not have this, we will add it later on twice to the span recorder and therefore have too many spans | ||
var addedAsChild = false; | ||
function startSpan(context) { | ||
// This is our safeguard so people always get a Transaction in return. | ||
// We set `_isTransaction: true` in {@link Sentry.startTransaction} to have a runtime check | ||
// if the user really wanted to create a Transaction. | ||
if (context._isTransaction && !context.name) { | ||
utils_1.logger.warn('You are trying to start a Transaction but forgot to provide a `name` property.'); | ||
utils_1.logger.warn('Will fall back to <unlabeled transaction>, use `transaction.setName()` to change it.'); | ||
context.name = '<unlabeled transaction>'; | ||
} | ||
if (context.name) { | ||
// We are dealing with a Transaction | ||
var transaction = new transaction_1.Transaction(context, this); | ||
var client = this.getClient(); | ||
// We only roll the dice on sampling for root spans of transactions because all child spans inherit this state | ||
if (transaction.sampled === undefined) { | ||
var sampleRate = (client && client.getOptions().tracesSampleRate) || 0; | ||
// if true = we want to have the transaction | ||
// if false = we don't want to have it | ||
// Math.random (inclusive of 0, but not 1) | ||
transaction.sampled = Math.random() < sampleRate; | ||
} | ||
// We only want to create a span list if we sampled the transaction | ||
// If sampled == false, we will discard the span anyway, so we can save memory by not storing child spans | ||
if (transaction.sampled) { | ||
var experimentsOptions = (client && client.getOptions()._experiments) || {}; | ||
transaction.initSpanRecorder(experimentsOptions.maxSpans); | ||
} | ||
return transaction; | ||
} | ||
var scope = this.getScope(); | ||
if (scope) { | ||
// If there is a Span on the Scope we start a child and return that instead | ||
var parentSpan = scope.getSpan(); | ||
if (parentSpan) { | ||
span = parentSpan.child(spanContext); | ||
addedAsChild = true; | ||
return parentSpan.startChild(context); | ||
} | ||
} | ||
if (!span) { | ||
span = new span_1.Span(spanContext, hub); | ||
} | ||
// We only roll the dice on sampling for "root" spans (transactions) because the childs inherit this state | ||
if (span.sampled === undefined && span.isRootSpan()) { | ||
var sampleRate = (client && client.getOptions().tracesSampleRate) || 0; | ||
span.sampled = Math.random() < sampleRate; | ||
} | ||
// We only want to create a span list if we sampled the transaction | ||
// in case we will discard the span anyway because sampled == false, we safe memory and do not store child spans | ||
if (span.sampled && !addedAsChild) { | ||
var experimentsOptions = (client && client.getOptions()._experiments) || {}; | ||
span.initSpanRecorder(experimentsOptions.maxSpans); | ||
} | ||
return span; | ||
// Otherwise we return a new Span | ||
return new span_1.Span(context); | ||
} | ||
@@ -59,0 +67,0 @@ /** |
import * as ApmIntegrations from './integrations'; | ||
export { ApmIntegrations as Integrations }; | ||
export { Span, TRACEPARENT_REGEXP } from './span'; | ||
export { Transaction } from './transaction'; | ||
export { SpanStatus } from './spanstatus'; | ||
//# sourceMappingURL=index.d.ts.map |
@@ -8,2 +8,4 @@ Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.TRACEPARENT_REGEXP = span_1.TRACEPARENT_REGEXP; | ||
var transaction_1 = require("./transaction"); | ||
exports.Transaction = transaction_1.Transaction; | ||
var spanstatus_1 = require("./spanstatus"); | ||
@@ -10,0 +12,0 @@ exports.SpanStatus = spanstatus_1.SpanStatus; |
@@ -1,2 +0,2 @@ | ||
import { EventProcessor, Hub, Integration } from '@sentry/types'; | ||
import { Integration } from '@sentry/types'; | ||
import { Application } from 'express'; | ||
@@ -31,4 +31,4 @@ /** | ||
*/ | ||
setupOnce(_addGlobalEventProcessor: (callback: EventProcessor) => void, getCurrentHub: () => Hub): void; | ||
setupOnce(): void; | ||
} | ||
//# sourceMappingURL=express.d.ts.map |
@@ -24,3 +24,3 @@ Object.defineProperty(exports, "__esModule", { value: true }); | ||
*/ | ||
Express.prototype.setupOnce = function (_addGlobalEventProcessor, getCurrentHub) { | ||
Express.prototype.setupOnce = function () { | ||
if (!this._app) { | ||
@@ -30,3 +30,3 @@ utils_1.logger.error('ExpressIntegration is missing an Express instance'); | ||
} | ||
instrumentMiddlewares(this._app, getCurrentHub); | ||
instrumentMiddlewares(this._app); | ||
}; | ||
@@ -52,3 +52,3 @@ /** | ||
*/ | ||
function wrap(fn, getCurrentHub) { | ||
function wrap(fn) { | ||
var arrity = fn.length; | ||
@@ -58,7 +58,12 @@ switch (arrity) { | ||
return function (_req, res) { | ||
var span = getCurrentHub().startSpan({ | ||
description: fn.name, | ||
op: 'middleware', | ||
}); | ||
res.once('finish', function () { return span.finish(); }); | ||
var transaction = res.__sentry_transaction; | ||
if (transaction) { | ||
var span_1 = transaction.startChild({ | ||
description: fn.name, | ||
op: 'middleware', | ||
}); | ||
res.once('finish', function () { | ||
span_1.finish(); | ||
}); | ||
} | ||
return fn.apply(this, arguments); | ||
@@ -69,8 +74,12 @@ }; | ||
return function (req, res, next) { | ||
var span = getCurrentHub().startSpan({ | ||
description: fn.name, | ||
op: 'middleware', | ||
}); | ||
var transaction = res.__sentry_transaction; | ||
var span = transaction && | ||
transaction.startChild({ | ||
description: fn.name, | ||
op: 'middleware', | ||
}); | ||
fn.call(this, req, res, function () { | ||
span.finish(); | ||
if (span) { | ||
span.finish(); | ||
} | ||
return next.apply(this, arguments); | ||
@@ -82,8 +91,12 @@ }); | ||
return function (err, req, res, next) { | ||
var span = getCurrentHub().startSpan({ | ||
description: fn.name, | ||
op: 'middleware', | ||
}); | ||
var transaction = res.__sentry_transaction; | ||
var span = transaction && | ||
transaction.startChild({ | ||
description: fn.name, | ||
op: 'middleware', | ||
}); | ||
fn.call(this, err, req, res, function () { | ||
span.finish(); | ||
if (span) { | ||
span.finish(); | ||
} | ||
return next.apply(this, arguments); | ||
@@ -108,6 +121,6 @@ }); | ||
*/ | ||
function wrapUseArgs(args, getCurrentHub) { | ||
function wrapUseArgs(args) { | ||
return Array.from(args).map(function (arg) { | ||
if (typeof arg === 'function') { | ||
return wrap(arg, getCurrentHub); | ||
return wrap(arg); | ||
} | ||
@@ -117,3 +130,3 @@ if (Array.isArray(arg)) { | ||
if (typeof a === 'function') { | ||
return wrap(a, getCurrentHub); | ||
return wrap(a); | ||
} | ||
@@ -129,6 +142,6 @@ return a; | ||
*/ | ||
function instrumentMiddlewares(app, getCurrentHub) { | ||
function instrumentMiddlewares(app) { | ||
var originalAppUse = app.use; | ||
app.use = function () { | ||
return originalAppUse.apply(this, wrapUseArgs(arguments, getCurrentHub)); | ||
return originalAppUse.apply(this, wrapUseArgs(arguments)); | ||
}; | ||
@@ -135,0 +148,0 @@ return app; |
import { Hub } from '@sentry/hub'; | ||
import { EventProcessor, Integration, Span, SpanContext } from '@sentry/types'; | ||
import { EventProcessor, Integration, Span, SpanContext, TransactionContext } from '@sentry/types'; | ||
import { SpanStatus } from '../spanstatus'; | ||
import { Transaction } from '../transaction'; | ||
/** | ||
@@ -50,6 +51,4 @@ * Options for Tracing integration | ||
/** | ||
* The maximum duration of a transaction before it will be discarded. This is for some edge cases where a browser | ||
* completely freezes the JS state and picks it up later (background tabs). | ||
* So after this duration, the SDK will not send the event. | ||
* If you want to have an unlimited duration set it to 0. | ||
* The maximum duration of a transaction before it will be marked as "deadline_exceeded". | ||
* If you never want to mark a transaction set it to 0. | ||
* Time is in seconds. | ||
@@ -61,5 +60,4 @@ * | ||
/** | ||
* Flag to discard all spans that occur in background. This includes transactions. Browser background tab timing is | ||
* not suited towards doing precise measurements of operations. That's why this option discards any active transaction | ||
* and also doesn't add any spans that happen in the background. Background spans/transaction can mess up your | ||
* Flag Transactions where tabs moved to background with "cancelled". Browser background tab timing is | ||
* not suited towards doing precise measurements of operations. Background transaction can mess up your | ||
* statistics in non deterministic ways that's why we by default recommend leaving this opition enabled. | ||
@@ -69,3 +67,3 @@ * | ||
*/ | ||
discardBackgroundSpans: boolean; | ||
markBackgroundTransactions: boolean; | ||
/** | ||
@@ -120,3 +118,3 @@ * This is only if you want to debug in prod. | ||
}; | ||
private static _debounce; | ||
private static _idleTransactionEndTimestamp; | ||
private readonly _emitOptionsWarning; | ||
@@ -177,3 +175,3 @@ private static _performanceCursor; | ||
*/ | ||
static startIdleTransaction(name: string, spanContext?: SpanContext): Span | undefined; | ||
static startIdleTransaction(transactionContext: TransactionContext): Transaction | undefined; | ||
/** | ||
@@ -196,2 +194,6 @@ * Finshes the current active transaction | ||
/** | ||
* Returns the current active idle transaction if there is one | ||
*/ | ||
static getTransaction(): Transaction | undefined; | ||
/** | ||
* Converts from milliseconds to seconds | ||
@@ -198,0 +200,0 @@ * @param time time in ms |
@@ -31,4 +31,4 @@ Object.defineProperty(exports, "__esModule", { value: true }); | ||
}, | ||
discardBackgroundSpans: true, | ||
idleTimeout: 500, | ||
markBackgroundTransactions: true, | ||
maxTransactionDuration: 600, | ||
@@ -63,3 +63,4 @@ shouldCreateSpanForRequest: function (url) { | ||
// Use `${global.location.href}` as transaction name | ||
Tracing.startIdleTransaction(global.location.href, { | ||
Tracing.startIdleTransaction({ | ||
name: global.location.href, | ||
op: 'pageload', | ||
@@ -85,3 +86,3 @@ }); | ||
if (Tracing.options.maxTransactionDuration !== 0 && event.type === 'transaction' && isOutdatedTransaction) { | ||
Tracing._log('[Tracing] Discarded transaction since it maxed out maxTransactionDuration'); | ||
Tracing._log("[Tracing] Transaction: " + spanstatus_1.SpanStatus.Cancelled + " since it maxed out maxTransactionDuration"); | ||
if (event.contexts && event.contexts.trace) { | ||
@@ -120,3 +121,3 @@ event.contexts.trace = tslib_1.__assign({}, event.contexts.trace, { status: spanstatus_1.SpanStatus.DeadlineExceeded }); | ||
if (Tracing._activeTransaction) { | ||
Tracing._log("[Tracing] Heartbeat safeguard kicked in, finishing transaction since activities content hasn't changed for 3 beats"); | ||
Tracing._log("[Tracing] Transaction: " + spanstatus_1.SpanStatus.Cancelled + " -> Heartbeat safeguard kicked in since content hasn't changed for 3 beats"); | ||
Tracing._activeTransaction.setStatus(spanstatus_1.SpanStatus.DeadlineExceeded); | ||
@@ -135,6 +136,6 @@ Tracing._activeTransaction.setTag('heartbeat', 'failed'); | ||
Tracing.prototype._setupBackgroundTabDetection = function () { | ||
if (Tracing.options.discardBackgroundSpans && global.document) { | ||
if (Tracing.options && Tracing.options.markBackgroundTransactions && global.document) { | ||
document.addEventListener('visibilitychange', function () { | ||
if (document.hidden && Tracing._activeTransaction) { | ||
Tracing._log('[Tracing] Discarded active transaction incl. activities since tab moved to the background'); | ||
Tracing._log("[Tracing] Transaction: " + spanstatus_1.SpanStatus.Cancelled + " -> since tab moved to the background"); | ||
Tracing._activeTransaction.setStatus(spanstatus_1.SpanStatus.Cancelled); | ||
@@ -210,3 +211,3 @@ Tracing._activeTransaction.setTag('visibilitychange', 'document.hidden'); | ||
*/ | ||
Tracing._log("[Tracing] Global error occured, setting status in transaction: " + spanstatus_1.SpanStatus.InternalError); | ||
Tracing._log("[Tracing] Transaction: " + spanstatus_1.SpanStatus.InternalError + " -> Global error occured"); | ||
Tracing._activeTransaction.setStatus(spanstatus_1.SpanStatus.InternalError); | ||
@@ -244,3 +245,3 @@ } | ||
} | ||
utils_1.logger.log(args); | ||
utils_1.logger.log.apply(utils_1.logger, tslib_1.__spread(args)); | ||
}; | ||
@@ -250,3 +251,3 @@ /** | ||
*/ | ||
Tracing.startIdleTransaction = function (name, spanContext) { | ||
Tracing.startIdleTransaction = function (transactionContext) { | ||
// If we already have an active transaction it means one of two things | ||
@@ -256,3 +257,3 @@ // a) The user did rapid navigation changes and didn't wait until the transaction was finished | ||
Tracing.finishIdleTransaction(); | ||
Tracing._log('[Tracing] startIdleTransaction, name:', name); | ||
Tracing._log('[Tracing] startIdleTransaction'); | ||
var _getCurrentHub = Tracing._getCurrentHub; | ||
@@ -266,9 +267,3 @@ if (!_getCurrentHub) { | ||
} | ||
Tracing._activeTransaction = hub.startSpan(tslib_1.__assign({}, spanContext, { transaction: name })); | ||
// We set the transaction on the scope so if there are any other spans started outside of this integration | ||
// we also add them to this transaction. | ||
// Once the idle transaction is finished, we make sure to remove it again. | ||
hub.configureScope(function (scope) { | ||
scope.setSpan(Tracing._activeTransaction); | ||
}); | ||
Tracing._activeTransaction = hub.startSpan(tslib_1.__assign({ trimEnd: true }, transactionContext)); | ||
// The reason we do this here is because of cached responses | ||
@@ -289,4 +284,14 @@ // If we start and transaction without an activity it would never finish since there is no activity | ||
Tracing._addPerformanceEntries(active); | ||
Tracing._log('[Tracing] finishIdleTransaction', active.transaction); | ||
active.finish(/*trimEnd*/ true); | ||
Tracing._log('[Tracing] finishIdleTransaction'); | ||
if (active.spanRecorder) { | ||
var timeout_1 = (Tracing.options && Tracing.options.idleTimeout) || 100; | ||
active.spanRecorder.spans = active.spanRecorder.spans.filter(function (finishedSpan) { | ||
var keepSpan = finishedSpan.startTimestamp < Tracing._idleTransactionEndTimestamp + timeout_1; | ||
if (!keepSpan) { | ||
Tracing._log('[Tracing] discarding Span since it happened after Transaction was finished', finishedSpan.toJSON()); | ||
} | ||
return keepSpan; | ||
}); | ||
} | ||
active.finish(); | ||
Tracing._resetActiveTransaction(); | ||
@@ -311,3 +316,3 @@ } | ||
function addPerformanceNavigationTiming(parent, entry, event) { | ||
var span = parent.child({ | ||
var span = parent.startChild({ | ||
description: event, | ||
@@ -317,7 +322,7 @@ op: 'browser', | ||
span.startTimestamp = timeOrigin + Tracing._msToSec(entry[event + "Start"]); | ||
span.timestamp = timeOrigin + Tracing._msToSec(entry[event + "End"]); | ||
span.endTimestamp = timeOrigin + Tracing._msToSec(entry[event + "End"]); | ||
} | ||
// tslint:disable-next-line: completed-docs | ||
function addRequest(parent, entry) { | ||
var request = parent.child({ | ||
var request = parent.startChild({ | ||
description: 'request', | ||
@@ -327,4 +332,4 @@ op: 'browser', | ||
request.startTimestamp = timeOrigin + Tracing._msToSec(entry.requestStart); | ||
request.timestamp = timeOrigin + Tracing._msToSec(entry.responseEnd); | ||
var response = parent.child({ | ||
request.endTimestamp = timeOrigin + Tracing._msToSec(entry.responseEnd); | ||
var response = parent.startChild({ | ||
description: 'response', | ||
@@ -334,3 +339,3 @@ op: 'browser', | ||
response.startTimestamp = timeOrigin + Tracing._msToSec(entry.responseStart); | ||
response.timestamp = timeOrigin + Tracing._msToSec(entry.responseEnd); | ||
response.endTimestamp = timeOrigin + Tracing._msToSec(entry.responseEnd); | ||
} | ||
@@ -374,3 +379,3 @@ var entryScriptSrc; | ||
case 'measure': | ||
var mark = transactionSpan.child({ | ||
var mark = transactionSpan.startChild({ | ||
description: entry.name, | ||
@@ -380,3 +385,3 @@ op: entry.entryType, | ||
mark.startTimestamp = timeOrigin + startTime; | ||
mark.timestamp = mark.startTimestamp + duration; | ||
mark.endTimestamp = mark.startTimestamp + duration; | ||
if (tracingInitMarkStartTime === undefined && entry.name === 'sentry-tracing-init') { | ||
@@ -394,3 +399,3 @@ tracingInitMarkStartTime = mark.startTimestamp; | ||
finishedSpan.startTimestamp = timeOrigin + startTime; | ||
finishedSpan.timestamp = finishedSpan.startTimestamp + duration; | ||
finishedSpan.endTimestamp = finishedSpan.startTimestamp + duration; | ||
} | ||
@@ -401,3 +406,3 @@ }); | ||
else { | ||
var resource = transactionSpan.child({ | ||
var resource = transactionSpan.startChild({ | ||
description: entry.initiatorType + " " + resourceName_1, | ||
@@ -407,6 +412,6 @@ op: "resource", | ||
resource.startTimestamp = timeOrigin + startTime; | ||
resource.timestamp = resource.startTimestamp + duration; | ||
resource.endTimestamp = resource.startTimestamp + duration; | ||
// We remember the entry script end time to calculate the difference to the first init mark | ||
if (entryScriptStartEndTime === undefined && (entryScriptSrc || '').includes(resourceName_1)) { | ||
entryScriptStartEndTime = resource.timestamp; | ||
entryScriptStartEndTime = resource.endTimestamp; | ||
} | ||
@@ -420,3 +425,3 @@ } | ||
if (entryScriptStartEndTime !== undefined && tracingInitMarkStartTime !== undefined) { | ||
var evaluation = transactionSpan.child({ | ||
var evaluation = transactionSpan.startChild({ | ||
description: 'evaluation', | ||
@@ -426,3 +431,3 @@ op: "script", | ||
evaluation.startTimestamp = entryScriptStartEndTime; | ||
evaluation.timestamp = tracingInitMarkStartTime; | ||
evaluation.endTimestamp = tracingInitMarkStartTime; | ||
} | ||
@@ -443,2 +448,8 @@ Tracing._performanceCursor = Math.max(performance.getEntries().length - 1, 0); | ||
/** | ||
* Returns the current active idle transaction if there is one | ||
*/ | ||
Tracing.getTransaction = function () { | ||
return Tracing._activeTransaction; | ||
}; | ||
/** | ||
* Converts from milliseconds to seconds | ||
@@ -486,4 +497,2 @@ * @param time time in ms | ||
} | ||
// We want to clear the timeout also here since we push a new activity | ||
clearTimeout(Tracing._debounce); | ||
var _getCurrentHub = Tracing._getCurrentHub; | ||
@@ -493,3 +502,3 @@ if (spanContext && _getCurrentHub) { | ||
if (hub) { | ||
var span = activeTransaction.child(spanContext); | ||
var span = activeTransaction.startChild(spanContext); | ||
Tracing._activities[Tracing._currentIndex] = { | ||
@@ -554,3 +563,2 @@ name: name, | ||
var count = Object.keys(Tracing._activities).length; | ||
clearTimeout(Tracing._debounce); | ||
Tracing._log('[Tracing] activies count', count); | ||
@@ -560,3 +568,4 @@ if (count === 0 && Tracing._activeTransaction) { | ||
Tracing._log("[Tracing] Flushing Transaction in " + timeout + "ms"); | ||
Tracing._debounce = setTimeout(function () { | ||
Tracing._idleTransactionEndTimestamp = utils_1.timestampWithMs(); | ||
setTimeout(function () { | ||
Tracing.finishIdleTransaction(); | ||
@@ -572,3 +581,3 @@ }, timeout); | ||
Tracing._activities = {}; | ||
Tracing._debounce = 0; | ||
Tracing._idleTransactionEndTimestamp = 0; | ||
Tracing._performanceCursor = 0; | ||
@@ -670,3 +679,4 @@ Tracing._heartbeatTimer = 0; | ||
if (Tracing.options.startTransactionOnLocationChange && global && global.location) { | ||
Tracing.startIdleTransaction(global.location.href, { | ||
Tracing.startIdleTransaction({ | ||
name: global.location.href, | ||
op: 'navigation', | ||
@@ -673,0 +683,0 @@ }); |
@@ -1,21 +0,6 @@ | ||
import { Hub } from '@sentry/hub'; | ||
import { Span as SpanInterface, SpanContext } from '@sentry/types'; | ||
import { SpanStatus } from './spanstatus'; | ||
import { SpanRecorder } from './transaction'; | ||
export declare const TRACEPARENT_REGEXP: RegExp; | ||
/** | ||
* Keeps track of finished spans for a given transaction | ||
*/ | ||
declare class SpanRecorder { | ||
private readonly _maxlen; | ||
spans: Span[]; | ||
constructor(maxlen?: number); | ||
/** | ||
* This is just so that we don't run out of memory while recording a lot | ||
* of spans. At some point we just stop and flush out the start of the | ||
* trace tree (i.e.the first n spans with the smallest | ||
* start_timestamp). | ||
*/ | ||
add(span: Span): void; | ||
} | ||
/** | ||
* Span contains all data about a span | ||
@@ -25,21 +10,17 @@ */ | ||
/** | ||
* The reference to the current hub. | ||
*/ | ||
private readonly _hub; | ||
/** | ||
* @inheritDoc | ||
*/ | ||
private readonly _traceId; | ||
traceId: string; | ||
/** | ||
* @inheritDoc | ||
*/ | ||
private readonly _spanId; | ||
spanId: string; | ||
/** | ||
* @inheritDoc | ||
*/ | ||
private readonly _parentSpanId?; | ||
parentSpanId?: string; | ||
/** | ||
* Internal keeper of the status | ||
*/ | ||
private _status?; | ||
status?: SpanStatus | string; | ||
/** | ||
@@ -56,10 +37,6 @@ * @inheritDoc | ||
*/ | ||
timestamp?: number; | ||
endTimestamp?: number; | ||
/** | ||
* @inheritDoc | ||
*/ | ||
transaction?: string; | ||
/** | ||
* @inheritDoc | ||
*/ | ||
op?: string; | ||
@@ -92,10 +69,6 @@ /** | ||
*/ | ||
constructor(spanContext?: SpanContext, hub?: Hub); | ||
constructor(spanContext?: SpanContext); | ||
/** | ||
* Attaches SpanRecorder to the span itself | ||
* @param maxlen maximum number of spans that can be recorded | ||
*/ | ||
initSpanRecorder(maxlen?: number): void; | ||
/** | ||
* @inheritDoc | ||
* @deprecated | ||
*/ | ||
@@ -106,3 +79,3 @@ child(spanContext?: Pick<SpanContext, Exclude<keyof SpanContext, 'spanId' | 'sampled' | 'traceId' | 'parentSpanId'>>): Span; | ||
*/ | ||
isRootSpan(): boolean; | ||
startChild(spanContext?: Pick<SpanContext, Exclude<keyof SpanContext, 'spanId' | 'sampled' | 'traceId' | 'parentSpanId'>>): Span; | ||
/** | ||
@@ -134,9 +107,5 @@ * Continues a trace from a string (usually the header). | ||
/** | ||
* Sets the finish timestamp on the current span. | ||
* @param trimEnd If true, sets the end timestamp of the transaction to the highest timestamp of child spans, trimming | ||
* the duration of the transaction span. This is useful to discard extra time in the transaction span that is not | ||
* accounted for in child spans, like what happens in the idle transaction Tracing integration, where we finish the | ||
* transaction after a given "idle time" and we don't want this "idle time" to be part of the transaction. | ||
* @inheritDoc | ||
*/ | ||
finish(trimEnd?: boolean): string | undefined; | ||
finish(endTimestamp?: number): void; | ||
/** | ||
@@ -181,6 +150,4 @@ * @inheritDoc | ||
trace_id: string; | ||
transaction?: string; | ||
}; | ||
} | ||
export {}; | ||
//# sourceMappingURL=span.d.ts.map |
153
dist/span.js
@@ -1,8 +0,5 @@ | ||
// tslint:disable:max-classes-per-file | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
var tslib_1 = require("tslib"); | ||
var hub_1 = require("@sentry/hub"); | ||
var utils_1 = require("@sentry/utils"); | ||
var spanstatus_1 = require("./spanstatus"); | ||
// TODO: Should this be exported? | ||
exports.TRACEPARENT_REGEXP = new RegExp('^[ \\t]*' + // whitespace | ||
@@ -14,27 +11,2 @@ '([0-9a-f]{32})?' + // trace_id | ||
/** | ||
* Keeps track of finished spans for a given transaction | ||
*/ | ||
var SpanRecorder = /** @class */ (function () { | ||
function SpanRecorder(maxlen) { | ||
if (maxlen === void 0) { maxlen = 1000; } | ||
this.spans = []; | ||
this._maxlen = maxlen; | ||
} | ||
/** | ||
* This is just so that we don't run out of memory while recording a lot | ||
* of spans. At some point we just stop and flush out the start of the | ||
* trace tree (i.e.the first n spans with the smallest | ||
* start_timestamp). | ||
*/ | ||
SpanRecorder.prototype.add = function (span) { | ||
if (this.spans.length > this._maxlen) { | ||
span.spanRecorder = undefined; | ||
} | ||
else { | ||
this.spans.push(span); | ||
} | ||
}; | ||
return SpanRecorder; | ||
}()); | ||
/** | ||
* Span contains all data about a span | ||
@@ -49,15 +21,11 @@ */ | ||
*/ | ||
function Span(spanContext, hub) { | ||
function Span(spanContext) { | ||
/** | ||
* The reference to the current hub. | ||
*/ | ||
this._hub = hub_1.getCurrentHub(); | ||
/** | ||
* @inheritDoc | ||
*/ | ||
this._traceId = utils_1.uuid4(); | ||
this.traceId = utils_1.uuid4(); | ||
/** | ||
* @inheritDoc | ||
*/ | ||
this._spanId = utils_1.uuid4().substring(16); | ||
this.spanId = utils_1.uuid4().substring(16); | ||
/** | ||
@@ -75,5 +43,2 @@ * Timestamp in seconds when the span was created. | ||
this.data = {}; | ||
if (utils_1.isInstanceOf(hub, hub_1.Hub)) { | ||
this._hub = hub; | ||
} | ||
if (!spanContext) { | ||
@@ -83,9 +48,9 @@ return this; | ||
if (spanContext.traceId) { | ||
this._traceId = spanContext.traceId; | ||
this.traceId = spanContext.traceId; | ||
} | ||
if (spanContext.spanId) { | ||
this._spanId = spanContext.spanId; | ||
this.spanId = spanContext.spanId; | ||
} | ||
if (spanContext.parentSpanId) { | ||
this._parentSpanId = spanContext.parentSpanId; | ||
this.parentSpanId = spanContext.parentSpanId; | ||
} | ||
@@ -96,5 +61,2 @@ // We want to include booleans as well here | ||
} | ||
if (spanContext.transaction) { | ||
this.transaction = spanContext.transaction; | ||
} | ||
if (spanContext.op) { | ||
@@ -113,15 +75,17 @@ this.op = spanContext.op; | ||
if (spanContext.status) { | ||
this._status = spanContext.status; | ||
this.status = spanContext.status; | ||
} | ||
if (spanContext.startTimestamp) { | ||
this.startTimestamp = spanContext.startTimestamp; | ||
} | ||
if (spanContext.endTimestamp) { | ||
this.endTimestamp = spanContext.endTimestamp; | ||
} | ||
} | ||
/** | ||
* Attaches SpanRecorder to the span itself | ||
* @param maxlen maximum number of spans that can be recorded | ||
* @inheritDoc | ||
* @deprecated | ||
*/ | ||
Span.prototype.initSpanRecorder = function (maxlen) { | ||
if (maxlen === void 0) { maxlen = 1000; } | ||
if (!this.spanRecorder) { | ||
this.spanRecorder = new SpanRecorder(maxlen); | ||
} | ||
this.spanRecorder.add(this); | ||
Span.prototype.child = function (spanContext) { | ||
return this.startChild(spanContext); | ||
}; | ||
@@ -131,4 +95,4 @@ /** | ||
*/ | ||
Span.prototype.child = function (spanContext) { | ||
var span = new Span(tslib_1.__assign({}, spanContext, { parentSpanId: this._spanId, sampled: this.sampled, traceId: this._traceId })); | ||
Span.prototype.startChild = function (spanContext) { | ||
var span = new Span(tslib_1.__assign({}, spanContext, { parentSpanId: this.spanId, sampled: this.sampled, traceId: this.traceId })); | ||
span.spanRecorder = this.spanRecorder; | ||
@@ -141,8 +105,2 @@ if (span.spanRecorder) { | ||
/** | ||
* @inheritDoc | ||
*/ | ||
Span.prototype.isRootSpan = function () { | ||
return this._parentSpanId === undefined; | ||
}; | ||
/** | ||
* Continues a trace from a string (usually the header). | ||
@@ -185,3 +143,3 @@ * @param traceparent Traceparent string | ||
Span.prototype.setStatus = function (value) { | ||
this._status = value; | ||
this.status = value; | ||
return this; | ||
@@ -204,53 +162,9 @@ }; | ||
Span.prototype.isSuccess = function () { | ||
return this._status === spanstatus_1.SpanStatus.Ok; | ||
return this.status === spanstatus_1.SpanStatus.Ok; | ||
}; | ||
/** | ||
* Sets the finish timestamp on the current span. | ||
* @param trimEnd If true, sets the end timestamp of the transaction to the highest timestamp of child spans, trimming | ||
* the duration of the transaction span. This is useful to discard extra time in the transaction span that is not | ||
* accounted for in child spans, like what happens in the idle transaction Tracing integration, where we finish the | ||
* transaction after a given "idle time" and we don't want this "idle time" to be part of the transaction. | ||
* @inheritDoc | ||
*/ | ||
Span.prototype.finish = function (trimEnd) { | ||
var _this = this; | ||
if (trimEnd === void 0) { trimEnd = false; } | ||
// This transaction is already finished, so we should not flush it again. | ||
if (this.timestamp !== undefined) { | ||
return undefined; | ||
} | ||
this.timestamp = utils_1.timestampWithMs(); | ||
// We will not send any child spans | ||
if (!this.isRootSpan()) { | ||
return undefined; | ||
} | ||
// This happens if a span was initiated outside of `hub.startSpan` | ||
// Also if the span was sampled (sampled = false) in `hub.startSpan` already | ||
if (this.spanRecorder === undefined) { | ||
return undefined; | ||
} | ||
if (this.sampled !== true) { | ||
// At this point if `sampled !== true` we want to discard the transaction. | ||
utils_1.logger.warn('Discarding transaction Span because it was span.sampled !== true'); | ||
return undefined; | ||
} | ||
var finishedSpans = this.spanRecorder ? this.spanRecorder.spans.filter(function (s) { return s !== _this && s.timestamp; }) : []; | ||
if (trimEnd && finishedSpans.length > 0) { | ||
this.timestamp = finishedSpans.reduce(function (prev, current) { | ||
if (prev.timestamp && current.timestamp) { | ||
return prev.timestamp > current.timestamp ? prev : current; | ||
} | ||
return prev; | ||
}).timestamp; | ||
} | ||
return this._hub.captureEvent({ | ||
contexts: { | ||
trace: this.getTraceContext(), | ||
}, | ||
spans: finishedSpans, | ||
start_timestamp: this.startTimestamp, | ||
tags: this.tags, | ||
timestamp: this.timestamp, | ||
transaction: this.transaction, | ||
type: 'transaction', | ||
}); | ||
Span.prototype.finish = function (endTimestamp) { | ||
this.endTimestamp = typeof endTimestamp === 'number' ? endTimestamp : utils_1.timestampWithMs(); | ||
}; | ||
@@ -265,3 +179,3 @@ /** | ||
} | ||
return this._traceId + "-" + this._spanId + sampledString; | ||
return this.traceId + "-" + this.spanId + sampledString; | ||
}; | ||
@@ -276,7 +190,7 @@ /** | ||
op: this.op, | ||
parent_span_id: this._parentSpanId, | ||
span_id: this._spanId, | ||
status: this._status, | ||
parent_span_id: this.parentSpanId, | ||
span_id: this.spanId, | ||
status: this.status, | ||
tags: Object.keys(this.tags).length > 0 ? this.tags : undefined, | ||
trace_id: this._traceId, | ||
trace_id: this.traceId, | ||
}); | ||
@@ -292,10 +206,9 @@ }; | ||
op: this.op, | ||
parent_span_id: this._parentSpanId, | ||
parent_span_id: this.parentSpanId, | ||
sampled: this.sampled, | ||
span_id: this._spanId, | ||
span_id: this.spanId, | ||
start_timestamp: this.startTimestamp, | ||
tags: Object.keys(this.tags).length > 0 ? this.tags : undefined, | ||
timestamp: this.timestamp, | ||
trace_id: this._traceId, | ||
transaction: this.transaction, | ||
timestamp: this.endTimestamp, | ||
trace_id: this.traceId, | ||
}); | ||
@@ -302,0 +215,0 @@ }; |
import { getMainCarrier } from '@sentry/hub'; | ||
import { logger } from '@sentry/utils'; | ||
import { Span } from './span'; | ||
import { Transaction } from './transaction'; | ||
/** Returns all trace headers that are currently on the top scope. */ | ||
function traceHeaders() { | ||
// @ts-ignore | ||
var that = this; | ||
var scope = that.getScope(); | ||
var scope = this.getScope(); | ||
if (scope) { | ||
@@ -23,35 +23,43 @@ var span = scope.getSpan(); | ||
* | ||
* @param spanContext Properties with which the span should be created | ||
* @param context Properties with which the span should be created | ||
*/ | ||
function startSpan(spanContext) { | ||
// @ts-ignore | ||
var hub = this; | ||
var scope = hub.getScope(); | ||
var client = hub.getClient(); | ||
var span; | ||
// This flag determines if we already added the span as a child to the span that currently lives on the scope | ||
// If we do not have this, we will add it later on twice to the span recorder and therefore have too many spans | ||
var addedAsChild = false; | ||
function startSpan(context) { | ||
// This is our safeguard so people always get a Transaction in return. | ||
// We set `_isTransaction: true` in {@link Sentry.startTransaction} to have a runtime check | ||
// if the user really wanted to create a Transaction. | ||
if (context._isTransaction && !context.name) { | ||
logger.warn('You are trying to start a Transaction but forgot to provide a `name` property.'); | ||
logger.warn('Will fall back to <unlabeled transaction>, use `transaction.setName()` to change it.'); | ||
context.name = '<unlabeled transaction>'; | ||
} | ||
if (context.name) { | ||
// We are dealing with a Transaction | ||
var transaction = new Transaction(context, this); | ||
var client = this.getClient(); | ||
// We only roll the dice on sampling for root spans of transactions because all child spans inherit this state | ||
if (transaction.sampled === undefined) { | ||
var sampleRate = (client && client.getOptions().tracesSampleRate) || 0; | ||
// if true = we want to have the transaction | ||
// if false = we don't want to have it | ||
// Math.random (inclusive of 0, but not 1) | ||
transaction.sampled = Math.random() < sampleRate; | ||
} | ||
// We only want to create a span list if we sampled the transaction | ||
// If sampled == false, we will discard the span anyway, so we can save memory by not storing child spans | ||
if (transaction.sampled) { | ||
var experimentsOptions = (client && client.getOptions()._experiments) || {}; | ||
transaction.initSpanRecorder(experimentsOptions.maxSpans); | ||
} | ||
return transaction; | ||
} | ||
var scope = this.getScope(); | ||
if (scope) { | ||
// If there is a Span on the Scope we start a child and return that instead | ||
var parentSpan = scope.getSpan(); | ||
if (parentSpan) { | ||
span = parentSpan.child(spanContext); | ||
addedAsChild = true; | ||
return parentSpan.startChild(context); | ||
} | ||
} | ||
if (!span) { | ||
span = new Span(spanContext, hub); | ||
} | ||
// We only roll the dice on sampling for "root" spans (transactions) because the childs inherit this state | ||
if (span.sampled === undefined && span.isRootSpan()) { | ||
var sampleRate = (client && client.getOptions().tracesSampleRate) || 0; | ||
span.sampled = Math.random() < sampleRate; | ||
} | ||
// We only want to create a span list if we sampled the transaction | ||
// in case we will discard the span anyway because sampled == false, we safe memory and do not store child spans | ||
if (span.sampled && !addedAsChild) { | ||
var experimentsOptions = (client && client.getOptions()._experiments) || {}; | ||
span.initSpanRecorder(experimentsOptions.maxSpans); | ||
} | ||
return span; | ||
// Otherwise we return a new Span | ||
return new Span(context); | ||
} | ||
@@ -58,0 +66,0 @@ /** |
import * as ApmIntegrations from './integrations'; | ||
export { ApmIntegrations as Integrations }; | ||
export { Span, TRACEPARENT_REGEXP } from './span'; | ||
export { Transaction } from './transaction'; | ||
export { SpanStatus } from './spanstatus'; | ||
//# sourceMappingURL=index.d.ts.map |
@@ -5,2 +5,3 @@ import { addExtensionMethods } from './hubextensions'; | ||
export { Span, TRACEPARENT_REGEXP } from './span'; | ||
export { Transaction } from './transaction'; | ||
export { SpanStatus } from './spanstatus'; | ||
@@ -7,0 +8,0 @@ // We are patching the global object with our hub extension methods |
@@ -1,2 +0,2 @@ | ||
import { EventProcessor, Hub, Integration } from '@sentry/types'; | ||
import { Integration } from '@sentry/types'; | ||
import { Application } from 'express'; | ||
@@ -31,4 +31,4 @@ /** | ||
*/ | ||
setupOnce(_addGlobalEventProcessor: (callback: EventProcessor) => void, getCurrentHub: () => Hub): void; | ||
setupOnce(): void; | ||
} | ||
//# sourceMappingURL=express.d.ts.map |
@@ -23,3 +23,3 @@ import { logger } from '@sentry/utils'; | ||
*/ | ||
Express.prototype.setupOnce = function (_addGlobalEventProcessor, getCurrentHub) { | ||
Express.prototype.setupOnce = function () { | ||
if (!this._app) { | ||
@@ -29,3 +29,3 @@ logger.error('ExpressIntegration is missing an Express instance'); | ||
} | ||
instrumentMiddlewares(this._app, getCurrentHub); | ||
instrumentMiddlewares(this._app); | ||
}; | ||
@@ -51,3 +51,3 @@ /** | ||
*/ | ||
function wrap(fn, getCurrentHub) { | ||
function wrap(fn) { | ||
var arrity = fn.length; | ||
@@ -57,7 +57,12 @@ switch (arrity) { | ||
return function (_req, res) { | ||
var span = getCurrentHub().startSpan({ | ||
description: fn.name, | ||
op: 'middleware', | ||
}); | ||
res.once('finish', function () { return span.finish(); }); | ||
var transaction = res.__sentry_transaction; | ||
if (transaction) { | ||
var span_1 = transaction.startChild({ | ||
description: fn.name, | ||
op: 'middleware', | ||
}); | ||
res.once('finish', function () { | ||
span_1.finish(); | ||
}); | ||
} | ||
return fn.apply(this, arguments); | ||
@@ -68,8 +73,12 @@ }; | ||
return function (req, res, next) { | ||
var span = getCurrentHub().startSpan({ | ||
description: fn.name, | ||
op: 'middleware', | ||
}); | ||
var transaction = res.__sentry_transaction; | ||
var span = transaction && | ||
transaction.startChild({ | ||
description: fn.name, | ||
op: 'middleware', | ||
}); | ||
fn.call(this, req, res, function () { | ||
span.finish(); | ||
if (span) { | ||
span.finish(); | ||
} | ||
return next.apply(this, arguments); | ||
@@ -81,8 +90,12 @@ }); | ||
return function (err, req, res, next) { | ||
var span = getCurrentHub().startSpan({ | ||
description: fn.name, | ||
op: 'middleware', | ||
}); | ||
var transaction = res.__sentry_transaction; | ||
var span = transaction && | ||
transaction.startChild({ | ||
description: fn.name, | ||
op: 'middleware', | ||
}); | ||
fn.call(this, err, req, res, function () { | ||
span.finish(); | ||
if (span) { | ||
span.finish(); | ||
} | ||
return next.apply(this, arguments); | ||
@@ -107,6 +120,6 @@ }); | ||
*/ | ||
function wrapUseArgs(args, getCurrentHub) { | ||
function wrapUseArgs(args) { | ||
return Array.from(args).map(function (arg) { | ||
if (typeof arg === 'function') { | ||
return wrap(arg, getCurrentHub); | ||
return wrap(arg); | ||
} | ||
@@ -116,3 +129,3 @@ if (Array.isArray(arg)) { | ||
if (typeof a === 'function') { | ||
return wrap(a, getCurrentHub); | ||
return wrap(a); | ||
} | ||
@@ -128,6 +141,6 @@ return a; | ||
*/ | ||
function instrumentMiddlewares(app, getCurrentHub) { | ||
function instrumentMiddlewares(app) { | ||
var originalAppUse = app.use; | ||
app.use = function () { | ||
return originalAppUse.apply(this, wrapUseArgs(arguments, getCurrentHub)); | ||
return originalAppUse.apply(this, wrapUseArgs(arguments)); | ||
}; | ||
@@ -134,0 +147,0 @@ return app; |
import { Hub } from '@sentry/hub'; | ||
import { EventProcessor, Integration, Span, SpanContext } from '@sentry/types'; | ||
import { EventProcessor, Integration, Span, SpanContext, TransactionContext } from '@sentry/types'; | ||
import { SpanStatus } from '../spanstatus'; | ||
import { Transaction } from '../transaction'; | ||
/** | ||
@@ -50,6 +51,4 @@ * Options for Tracing integration | ||
/** | ||
* The maximum duration of a transaction before it will be discarded. This is for some edge cases where a browser | ||
* completely freezes the JS state and picks it up later (background tabs). | ||
* So after this duration, the SDK will not send the event. | ||
* If you want to have an unlimited duration set it to 0. | ||
* The maximum duration of a transaction before it will be marked as "deadline_exceeded". | ||
* If you never want to mark a transaction set it to 0. | ||
* Time is in seconds. | ||
@@ -61,5 +60,4 @@ * | ||
/** | ||
* Flag to discard all spans that occur in background. This includes transactions. Browser background tab timing is | ||
* not suited towards doing precise measurements of operations. That's why this option discards any active transaction | ||
* and also doesn't add any spans that happen in the background. Background spans/transaction can mess up your | ||
* Flag Transactions where tabs moved to background with "cancelled". Browser background tab timing is | ||
* not suited towards doing precise measurements of operations. Background transaction can mess up your | ||
* statistics in non deterministic ways that's why we by default recommend leaving this opition enabled. | ||
@@ -69,3 +67,3 @@ * | ||
*/ | ||
discardBackgroundSpans: boolean; | ||
markBackgroundTransactions: boolean; | ||
/** | ||
@@ -120,3 +118,3 @@ * This is only if you want to debug in prod. | ||
}; | ||
private static _debounce; | ||
private static _idleTransactionEndTimestamp; | ||
private readonly _emitOptionsWarning; | ||
@@ -177,3 +175,3 @@ private static _performanceCursor; | ||
*/ | ||
static startIdleTransaction(name: string, spanContext?: SpanContext): Span | undefined; | ||
static startIdleTransaction(transactionContext: TransactionContext): Transaction | undefined; | ||
/** | ||
@@ -196,2 +194,6 @@ * Finshes the current active transaction | ||
/** | ||
* Returns the current active idle transaction if there is one | ||
*/ | ||
static getTransaction(): Transaction | undefined; | ||
/** | ||
* Converts from milliseconds to seconds | ||
@@ -198,0 +200,0 @@ * @param time time in ms |
import * as tslib_1 from "tslib"; | ||
import { Severity } from '@sentry/types'; | ||
import { addInstrumentationHandler, getGlobalObject, isMatchingPattern, logger, safeJoin, supportsNativeFetch, } from '@sentry/utils'; | ||
import { addInstrumentationHandler, getGlobalObject, isMatchingPattern, logger, safeJoin, supportsNativeFetch, timestampWithMs, } from '@sentry/utils'; | ||
import { SpanStatus } from '../spanstatus'; | ||
@@ -30,4 +30,4 @@ var global = getGlobalObject(); | ||
}, | ||
discardBackgroundSpans: true, | ||
idleTimeout: 500, | ||
markBackgroundTransactions: true, | ||
maxTransactionDuration: 600, | ||
@@ -62,3 +62,4 @@ shouldCreateSpanForRequest: function (url) { | ||
// Use `${global.location.href}` as transaction name | ||
Tracing.startIdleTransaction(global.location.href, { | ||
Tracing.startIdleTransaction({ | ||
name: global.location.href, | ||
op: 'pageload', | ||
@@ -84,3 +85,3 @@ }); | ||
if (Tracing.options.maxTransactionDuration !== 0 && event.type === 'transaction' && isOutdatedTransaction) { | ||
Tracing._log('[Tracing] Discarded transaction since it maxed out maxTransactionDuration'); | ||
Tracing._log("[Tracing] Transaction: " + SpanStatus.Cancelled + " since it maxed out maxTransactionDuration"); | ||
if (event.contexts && event.contexts.trace) { | ||
@@ -119,3 +120,3 @@ event.contexts.trace = tslib_1.__assign({}, event.contexts.trace, { status: SpanStatus.DeadlineExceeded }); | ||
if (Tracing._activeTransaction) { | ||
Tracing._log("[Tracing] Heartbeat safeguard kicked in, finishing transaction since activities content hasn't changed for 3 beats"); | ||
Tracing._log("[Tracing] Transaction: " + SpanStatus.Cancelled + " -> Heartbeat safeguard kicked in since content hasn't changed for 3 beats"); | ||
Tracing._activeTransaction.setStatus(SpanStatus.DeadlineExceeded); | ||
@@ -134,6 +135,6 @@ Tracing._activeTransaction.setTag('heartbeat', 'failed'); | ||
Tracing.prototype._setupBackgroundTabDetection = function () { | ||
if (Tracing.options.discardBackgroundSpans && global.document) { | ||
if (Tracing.options && Tracing.options.markBackgroundTransactions && global.document) { | ||
document.addEventListener('visibilitychange', function () { | ||
if (document.hidden && Tracing._activeTransaction) { | ||
Tracing._log('[Tracing] Discarded active transaction incl. activities since tab moved to the background'); | ||
Tracing._log("[Tracing] Transaction: " + SpanStatus.Cancelled + " -> since tab moved to the background"); | ||
Tracing._activeTransaction.setStatus(SpanStatus.Cancelled); | ||
@@ -209,3 +210,3 @@ Tracing._activeTransaction.setTag('visibilitychange', 'document.hidden'); | ||
*/ | ||
Tracing._log("[Tracing] Global error occured, setting status in transaction: " + SpanStatus.InternalError); | ||
Tracing._log("[Tracing] Transaction: " + SpanStatus.InternalError + " -> Global error occured"); | ||
Tracing._activeTransaction.setStatus(SpanStatus.InternalError); | ||
@@ -243,3 +244,3 @@ } | ||
} | ||
logger.log(args); | ||
logger.log.apply(logger, tslib_1.__spread(args)); | ||
}; | ||
@@ -249,3 +250,3 @@ /** | ||
*/ | ||
Tracing.startIdleTransaction = function (name, spanContext) { | ||
Tracing.startIdleTransaction = function (transactionContext) { | ||
// If we already have an active transaction it means one of two things | ||
@@ -255,3 +256,3 @@ // a) The user did rapid navigation changes and didn't wait until the transaction was finished | ||
Tracing.finishIdleTransaction(); | ||
Tracing._log('[Tracing] startIdleTransaction, name:', name); | ||
Tracing._log('[Tracing] startIdleTransaction'); | ||
var _getCurrentHub = Tracing._getCurrentHub; | ||
@@ -265,9 +266,3 @@ if (!_getCurrentHub) { | ||
} | ||
Tracing._activeTransaction = hub.startSpan(tslib_1.__assign({}, spanContext, { transaction: name })); | ||
// We set the transaction on the scope so if there are any other spans started outside of this integration | ||
// we also add them to this transaction. | ||
// Once the idle transaction is finished, we make sure to remove it again. | ||
hub.configureScope(function (scope) { | ||
scope.setSpan(Tracing._activeTransaction); | ||
}); | ||
Tracing._activeTransaction = hub.startSpan(tslib_1.__assign({ trimEnd: true }, transactionContext)); | ||
// The reason we do this here is because of cached responses | ||
@@ -288,4 +283,14 @@ // If we start and transaction without an activity it would never finish since there is no activity | ||
Tracing._addPerformanceEntries(active); | ||
Tracing._log('[Tracing] finishIdleTransaction', active.transaction); | ||
active.finish(/*trimEnd*/ true); | ||
Tracing._log('[Tracing] finishIdleTransaction'); | ||
if (active.spanRecorder) { | ||
var timeout_1 = (Tracing.options && Tracing.options.idleTimeout) || 100; | ||
active.spanRecorder.spans = active.spanRecorder.spans.filter(function (finishedSpan) { | ||
var keepSpan = finishedSpan.startTimestamp < Tracing._idleTransactionEndTimestamp + timeout_1; | ||
if (!keepSpan) { | ||
Tracing._log('[Tracing] discarding Span since it happened after Transaction was finished', finishedSpan.toJSON()); | ||
} | ||
return keepSpan; | ||
}); | ||
} | ||
active.finish(); | ||
Tracing._resetActiveTransaction(); | ||
@@ -310,3 +315,3 @@ } | ||
function addPerformanceNavigationTiming(parent, entry, event) { | ||
var span = parent.child({ | ||
var span = parent.startChild({ | ||
description: event, | ||
@@ -316,7 +321,7 @@ op: 'browser', | ||
span.startTimestamp = timeOrigin + Tracing._msToSec(entry[event + "Start"]); | ||
span.timestamp = timeOrigin + Tracing._msToSec(entry[event + "End"]); | ||
span.endTimestamp = timeOrigin + Tracing._msToSec(entry[event + "End"]); | ||
} | ||
// tslint:disable-next-line: completed-docs | ||
function addRequest(parent, entry) { | ||
var request = parent.child({ | ||
var request = parent.startChild({ | ||
description: 'request', | ||
@@ -326,4 +331,4 @@ op: 'browser', | ||
request.startTimestamp = timeOrigin + Tracing._msToSec(entry.requestStart); | ||
request.timestamp = timeOrigin + Tracing._msToSec(entry.responseEnd); | ||
var response = parent.child({ | ||
request.endTimestamp = timeOrigin + Tracing._msToSec(entry.responseEnd); | ||
var response = parent.startChild({ | ||
description: 'response', | ||
@@ -333,3 +338,3 @@ op: 'browser', | ||
response.startTimestamp = timeOrigin + Tracing._msToSec(entry.responseStart); | ||
response.timestamp = timeOrigin + Tracing._msToSec(entry.responseEnd); | ||
response.endTimestamp = timeOrigin + Tracing._msToSec(entry.responseEnd); | ||
} | ||
@@ -373,3 +378,3 @@ var entryScriptSrc; | ||
case 'measure': | ||
var mark = transactionSpan.child({ | ||
var mark = transactionSpan.startChild({ | ||
description: entry.name, | ||
@@ -379,3 +384,3 @@ op: entry.entryType, | ||
mark.startTimestamp = timeOrigin + startTime; | ||
mark.timestamp = mark.startTimestamp + duration; | ||
mark.endTimestamp = mark.startTimestamp + duration; | ||
if (tracingInitMarkStartTime === undefined && entry.name === 'sentry-tracing-init') { | ||
@@ -393,3 +398,3 @@ tracingInitMarkStartTime = mark.startTimestamp; | ||
finishedSpan.startTimestamp = timeOrigin + startTime; | ||
finishedSpan.timestamp = finishedSpan.startTimestamp + duration; | ||
finishedSpan.endTimestamp = finishedSpan.startTimestamp + duration; | ||
} | ||
@@ -400,3 +405,3 @@ }); | ||
else { | ||
var resource = transactionSpan.child({ | ||
var resource = transactionSpan.startChild({ | ||
description: entry.initiatorType + " " + resourceName_1, | ||
@@ -406,6 +411,6 @@ op: "resource", | ||
resource.startTimestamp = timeOrigin + startTime; | ||
resource.timestamp = resource.startTimestamp + duration; | ||
resource.endTimestamp = resource.startTimestamp + duration; | ||
// We remember the entry script end time to calculate the difference to the first init mark | ||
if (entryScriptStartEndTime === undefined && (entryScriptSrc || '').includes(resourceName_1)) { | ||
entryScriptStartEndTime = resource.timestamp; | ||
entryScriptStartEndTime = resource.endTimestamp; | ||
} | ||
@@ -419,3 +424,3 @@ } | ||
if (entryScriptStartEndTime !== undefined && tracingInitMarkStartTime !== undefined) { | ||
var evaluation = transactionSpan.child({ | ||
var evaluation = transactionSpan.startChild({ | ||
description: 'evaluation', | ||
@@ -425,3 +430,3 @@ op: "script", | ||
evaluation.startTimestamp = entryScriptStartEndTime; | ||
evaluation.timestamp = tracingInitMarkStartTime; | ||
evaluation.endTimestamp = tracingInitMarkStartTime; | ||
} | ||
@@ -442,2 +447,8 @@ Tracing._performanceCursor = Math.max(performance.getEntries().length - 1, 0); | ||
/** | ||
* Returns the current active idle transaction if there is one | ||
*/ | ||
Tracing.getTransaction = function () { | ||
return Tracing._activeTransaction; | ||
}; | ||
/** | ||
* Converts from milliseconds to seconds | ||
@@ -485,4 +496,2 @@ * @param time time in ms | ||
} | ||
// We want to clear the timeout also here since we push a new activity | ||
clearTimeout(Tracing._debounce); | ||
var _getCurrentHub = Tracing._getCurrentHub; | ||
@@ -492,3 +501,3 @@ if (spanContext && _getCurrentHub) { | ||
if (hub) { | ||
var span = activeTransaction.child(spanContext); | ||
var span = activeTransaction.startChild(spanContext); | ||
Tracing._activities[Tracing._currentIndex] = { | ||
@@ -553,3 +562,2 @@ name: name, | ||
var count = Object.keys(Tracing._activities).length; | ||
clearTimeout(Tracing._debounce); | ||
Tracing._log('[Tracing] activies count', count); | ||
@@ -559,3 +567,4 @@ if (count === 0 && Tracing._activeTransaction) { | ||
Tracing._log("[Tracing] Flushing Transaction in " + timeout + "ms"); | ||
Tracing._debounce = setTimeout(function () { | ||
Tracing._idleTransactionEndTimestamp = timestampWithMs(); | ||
setTimeout(function () { | ||
Tracing.finishIdleTransaction(); | ||
@@ -571,3 +580,3 @@ }, timeout); | ||
Tracing._activities = {}; | ||
Tracing._debounce = 0; | ||
Tracing._idleTransactionEndTimestamp = 0; | ||
Tracing._performanceCursor = 0; | ||
@@ -669,3 +678,4 @@ Tracing._heartbeatTimer = 0; | ||
if (Tracing.options.startTransactionOnLocationChange && global && global.location) { | ||
Tracing.startIdleTransaction(global.location.href, { | ||
Tracing.startIdleTransaction({ | ||
name: global.location.href, | ||
op: 'navigation', | ||
@@ -672,0 +682,0 @@ }); |
@@ -1,21 +0,6 @@ | ||
import { Hub } from '@sentry/hub'; | ||
import { Span as SpanInterface, SpanContext } from '@sentry/types'; | ||
import { SpanStatus } from './spanstatus'; | ||
import { SpanRecorder } from './transaction'; | ||
export declare const TRACEPARENT_REGEXP: RegExp; | ||
/** | ||
* Keeps track of finished spans for a given transaction | ||
*/ | ||
declare class SpanRecorder { | ||
private readonly _maxlen; | ||
spans: Span[]; | ||
constructor(maxlen?: number); | ||
/** | ||
* This is just so that we don't run out of memory while recording a lot | ||
* of spans. At some point we just stop and flush out the start of the | ||
* trace tree (i.e.the first n spans with the smallest | ||
* start_timestamp). | ||
*/ | ||
add(span: Span): void; | ||
} | ||
/** | ||
* Span contains all data about a span | ||
@@ -25,21 +10,17 @@ */ | ||
/** | ||
* The reference to the current hub. | ||
*/ | ||
private readonly _hub; | ||
/** | ||
* @inheritDoc | ||
*/ | ||
private readonly _traceId; | ||
traceId: string; | ||
/** | ||
* @inheritDoc | ||
*/ | ||
private readonly _spanId; | ||
spanId: string; | ||
/** | ||
* @inheritDoc | ||
*/ | ||
private readonly _parentSpanId?; | ||
parentSpanId?: string; | ||
/** | ||
* Internal keeper of the status | ||
*/ | ||
private _status?; | ||
status?: SpanStatus | string; | ||
/** | ||
@@ -56,10 +37,6 @@ * @inheritDoc | ||
*/ | ||
timestamp?: number; | ||
endTimestamp?: number; | ||
/** | ||
* @inheritDoc | ||
*/ | ||
transaction?: string; | ||
/** | ||
* @inheritDoc | ||
*/ | ||
op?: string; | ||
@@ -92,10 +69,6 @@ /** | ||
*/ | ||
constructor(spanContext?: SpanContext, hub?: Hub); | ||
constructor(spanContext?: SpanContext); | ||
/** | ||
* Attaches SpanRecorder to the span itself | ||
* @param maxlen maximum number of spans that can be recorded | ||
*/ | ||
initSpanRecorder(maxlen?: number): void; | ||
/** | ||
* @inheritDoc | ||
* @deprecated | ||
*/ | ||
@@ -106,3 +79,3 @@ child(spanContext?: Pick<SpanContext, Exclude<keyof SpanContext, 'spanId' | 'sampled' | 'traceId' | 'parentSpanId'>>): Span; | ||
*/ | ||
isRootSpan(): boolean; | ||
startChild(spanContext?: Pick<SpanContext, Exclude<keyof SpanContext, 'spanId' | 'sampled' | 'traceId' | 'parentSpanId'>>): Span; | ||
/** | ||
@@ -134,9 +107,5 @@ * Continues a trace from a string (usually the header). | ||
/** | ||
* Sets the finish timestamp on the current span. | ||
* @param trimEnd If true, sets the end timestamp of the transaction to the highest timestamp of child spans, trimming | ||
* the duration of the transaction span. This is useful to discard extra time in the transaction span that is not | ||
* accounted for in child spans, like what happens in the idle transaction Tracing integration, where we finish the | ||
* transaction after a given "idle time" and we don't want this "idle time" to be part of the transaction. | ||
* @inheritDoc | ||
*/ | ||
finish(trimEnd?: boolean): string | undefined; | ||
finish(endTimestamp?: number): void; | ||
/** | ||
@@ -181,6 +150,4 @@ * @inheritDoc | ||
trace_id: string; | ||
transaction?: string; | ||
}; | ||
} | ||
export {}; | ||
//# sourceMappingURL=span.d.ts.map |
155
esm/span.js
@@ -1,7 +0,4 @@ | ||
// tslint:disable:max-classes-per-file | ||
import * as tslib_1 from "tslib"; | ||
import { getCurrentHub, Hub } from '@sentry/hub'; | ||
import { dropUndefinedKeys, isInstanceOf, logger, timestampWithMs, uuid4 } from '@sentry/utils'; | ||
import { dropUndefinedKeys, timestampWithMs, uuid4 } from '@sentry/utils'; | ||
import { SpanStatus } from './spanstatus'; | ||
// TODO: Should this be exported? | ||
export var TRACEPARENT_REGEXP = new RegExp('^[ \\t]*' + // whitespace | ||
@@ -13,27 +10,2 @@ '([0-9a-f]{32})?' + // trace_id | ||
/** | ||
* Keeps track of finished spans for a given transaction | ||
*/ | ||
var SpanRecorder = /** @class */ (function () { | ||
function SpanRecorder(maxlen) { | ||
if (maxlen === void 0) { maxlen = 1000; } | ||
this.spans = []; | ||
this._maxlen = maxlen; | ||
} | ||
/** | ||
* This is just so that we don't run out of memory while recording a lot | ||
* of spans. At some point we just stop and flush out the start of the | ||
* trace tree (i.e.the first n spans with the smallest | ||
* start_timestamp). | ||
*/ | ||
SpanRecorder.prototype.add = function (span) { | ||
if (this.spans.length > this._maxlen) { | ||
span.spanRecorder = undefined; | ||
} | ||
else { | ||
this.spans.push(span); | ||
} | ||
}; | ||
return SpanRecorder; | ||
}()); | ||
/** | ||
* Span contains all data about a span | ||
@@ -48,15 +20,11 @@ */ | ||
*/ | ||
function Span(spanContext, hub) { | ||
function Span(spanContext) { | ||
/** | ||
* The reference to the current hub. | ||
*/ | ||
this._hub = getCurrentHub(); | ||
/** | ||
* @inheritDoc | ||
*/ | ||
this._traceId = uuid4(); | ||
this.traceId = uuid4(); | ||
/** | ||
* @inheritDoc | ||
*/ | ||
this._spanId = uuid4().substring(16); | ||
this.spanId = uuid4().substring(16); | ||
/** | ||
@@ -74,5 +42,2 @@ * Timestamp in seconds when the span was created. | ||
this.data = {}; | ||
if (isInstanceOf(hub, Hub)) { | ||
this._hub = hub; | ||
} | ||
if (!spanContext) { | ||
@@ -82,9 +47,9 @@ return this; | ||
if (spanContext.traceId) { | ||
this._traceId = spanContext.traceId; | ||
this.traceId = spanContext.traceId; | ||
} | ||
if (spanContext.spanId) { | ||
this._spanId = spanContext.spanId; | ||
this.spanId = spanContext.spanId; | ||
} | ||
if (spanContext.parentSpanId) { | ||
this._parentSpanId = spanContext.parentSpanId; | ||
this.parentSpanId = spanContext.parentSpanId; | ||
} | ||
@@ -95,5 +60,2 @@ // We want to include booleans as well here | ||
} | ||
if (spanContext.transaction) { | ||
this.transaction = spanContext.transaction; | ||
} | ||
if (spanContext.op) { | ||
@@ -112,15 +74,17 @@ this.op = spanContext.op; | ||
if (spanContext.status) { | ||
this._status = spanContext.status; | ||
this.status = spanContext.status; | ||
} | ||
if (spanContext.startTimestamp) { | ||
this.startTimestamp = spanContext.startTimestamp; | ||
} | ||
if (spanContext.endTimestamp) { | ||
this.endTimestamp = spanContext.endTimestamp; | ||
} | ||
} | ||
/** | ||
* Attaches SpanRecorder to the span itself | ||
* @param maxlen maximum number of spans that can be recorded | ||
* @inheritDoc | ||
* @deprecated | ||
*/ | ||
Span.prototype.initSpanRecorder = function (maxlen) { | ||
if (maxlen === void 0) { maxlen = 1000; } | ||
if (!this.spanRecorder) { | ||
this.spanRecorder = new SpanRecorder(maxlen); | ||
} | ||
this.spanRecorder.add(this); | ||
Span.prototype.child = function (spanContext) { | ||
return this.startChild(spanContext); | ||
}; | ||
@@ -130,4 +94,4 @@ /** | ||
*/ | ||
Span.prototype.child = function (spanContext) { | ||
var span = new Span(tslib_1.__assign({}, spanContext, { parentSpanId: this._spanId, sampled: this.sampled, traceId: this._traceId })); | ||
Span.prototype.startChild = function (spanContext) { | ||
var span = new Span(tslib_1.__assign({}, spanContext, { parentSpanId: this.spanId, sampled: this.sampled, traceId: this.traceId })); | ||
span.spanRecorder = this.spanRecorder; | ||
@@ -140,8 +104,2 @@ if (span.spanRecorder) { | ||
/** | ||
* @inheritDoc | ||
*/ | ||
Span.prototype.isRootSpan = function () { | ||
return this._parentSpanId === undefined; | ||
}; | ||
/** | ||
* Continues a trace from a string (usually the header). | ||
@@ -184,3 +142,3 @@ * @param traceparent Traceparent string | ||
Span.prototype.setStatus = function (value) { | ||
this._status = value; | ||
this.status = value; | ||
return this; | ||
@@ -203,53 +161,9 @@ }; | ||
Span.prototype.isSuccess = function () { | ||
return this._status === SpanStatus.Ok; | ||
return this.status === SpanStatus.Ok; | ||
}; | ||
/** | ||
* Sets the finish timestamp on the current span. | ||
* @param trimEnd If true, sets the end timestamp of the transaction to the highest timestamp of child spans, trimming | ||
* the duration of the transaction span. This is useful to discard extra time in the transaction span that is not | ||
* accounted for in child spans, like what happens in the idle transaction Tracing integration, where we finish the | ||
* transaction after a given "idle time" and we don't want this "idle time" to be part of the transaction. | ||
* @inheritDoc | ||
*/ | ||
Span.prototype.finish = function (trimEnd) { | ||
var _this = this; | ||
if (trimEnd === void 0) { trimEnd = false; } | ||
// This transaction is already finished, so we should not flush it again. | ||
if (this.timestamp !== undefined) { | ||
return undefined; | ||
} | ||
this.timestamp = timestampWithMs(); | ||
// We will not send any child spans | ||
if (!this.isRootSpan()) { | ||
return undefined; | ||
} | ||
// This happens if a span was initiated outside of `hub.startSpan` | ||
// Also if the span was sampled (sampled = false) in `hub.startSpan` already | ||
if (this.spanRecorder === undefined) { | ||
return undefined; | ||
} | ||
if (this.sampled !== true) { | ||
// At this point if `sampled !== true` we want to discard the transaction. | ||
logger.warn('Discarding transaction Span because it was span.sampled !== true'); | ||
return undefined; | ||
} | ||
var finishedSpans = this.spanRecorder ? this.spanRecorder.spans.filter(function (s) { return s !== _this && s.timestamp; }) : []; | ||
if (trimEnd && finishedSpans.length > 0) { | ||
this.timestamp = finishedSpans.reduce(function (prev, current) { | ||
if (prev.timestamp && current.timestamp) { | ||
return prev.timestamp > current.timestamp ? prev : current; | ||
} | ||
return prev; | ||
}).timestamp; | ||
} | ||
return this._hub.captureEvent({ | ||
contexts: { | ||
trace: this.getTraceContext(), | ||
}, | ||
spans: finishedSpans, | ||
start_timestamp: this.startTimestamp, | ||
tags: this.tags, | ||
timestamp: this.timestamp, | ||
transaction: this.transaction, | ||
type: 'transaction', | ||
}); | ||
Span.prototype.finish = function (endTimestamp) { | ||
this.endTimestamp = typeof endTimestamp === 'number' ? endTimestamp : timestampWithMs(); | ||
}; | ||
@@ -264,3 +178,3 @@ /** | ||
} | ||
return this._traceId + "-" + this._spanId + sampledString; | ||
return this.traceId + "-" + this.spanId + sampledString; | ||
}; | ||
@@ -275,7 +189,7 @@ /** | ||
op: this.op, | ||
parent_span_id: this._parentSpanId, | ||
span_id: this._spanId, | ||
status: this._status, | ||
parent_span_id: this.parentSpanId, | ||
span_id: this.spanId, | ||
status: this.status, | ||
tags: Object.keys(this.tags).length > 0 ? this.tags : undefined, | ||
trace_id: this._traceId, | ||
trace_id: this.traceId, | ||
}); | ||
@@ -291,10 +205,9 @@ }; | ||
op: this.op, | ||
parent_span_id: this._parentSpanId, | ||
parent_span_id: this.parentSpanId, | ||
sampled: this.sampled, | ||
span_id: this._spanId, | ||
span_id: this.spanId, | ||
start_timestamp: this.startTimestamp, | ||
tags: Object.keys(this.tags).length > 0 ? this.tags : undefined, | ||
timestamp: this.timestamp, | ||
trace_id: this._traceId, | ||
transaction: this.transaction, | ||
timestamp: this.endTimestamp, | ||
trace_id: this.traceId, | ||
}); | ||
@@ -301,0 +214,0 @@ }; |
{ | ||
"name": "@sentry/apm", | ||
"version": "5.16.0-beta.3", | ||
"version": "5.16.0-beta.4", | ||
"description": "Extensions for APM", | ||
"repository": "git://github.com/getsentry/sentry-javascript.git", | ||
"homepage": "https://github.com/getsentry/sentry-javascript/tree/master/packages/core", | ||
"homepage": "https://github.com/getsentry/sentry-javascript/tree/master/packages/apm", | ||
"author": "Sentry", | ||
@@ -19,7 +19,7 @@ "license": "BSD-3-Clause", | ||
"dependencies": { | ||
"@sentry/browser": "5.16.0-beta.3", | ||
"@sentry/hub": "5.16.0-beta.3", | ||
"@sentry/minimal": "5.16.0-beta.3", | ||
"@sentry/types": "5.16.0-beta.3", | ||
"@sentry/utils": "5.16.0-beta.3", | ||
"@sentry/browser": "5.16.0-beta.4", | ||
"@sentry/hub": "5.16.0-beta.4", | ||
"@sentry/minimal": "5.16.0-beta.4", | ||
"@sentry/types": "5.16.0-beta.4", | ||
"@sentry/utils": "5.16.0-beta.4", | ||
"tslib": "^1.9.3" | ||
@@ -26,0 +26,0 @@ }, |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
No website
QualityPackage does not have a website.
Found 1 instance in 1 package
333364
74
3712
2
+ Added@sentry/browser@5.16.0-beta.4(transitive)
+ Added@sentry/core@5.16.0-beta.4(transitive)
+ Added@sentry/hub@5.16.0-beta.4(transitive)
+ Added@sentry/minimal@5.16.0-beta.4(transitive)
+ Added@sentry/types@5.16.0-beta.4(transitive)
+ Added@sentry/utils@5.16.0-beta.4(transitive)
- Removed@sentry/browser@5.16.0-beta.3(transitive)
- Removed@sentry/core@5.16.0-beta.3(transitive)
- Removed@sentry/hub@5.16.0-beta.3(transitive)
- Removed@sentry/minimal@5.16.0-beta.3(transitive)
- Removed@sentry/types@5.16.0-beta.3(transitive)
- Removed@sentry/utils@5.16.0-beta.3(transitive)
Updated@sentry/hub@5.16.0-beta.4
Updated@sentry/types@5.16.0-beta.4
Updated@sentry/utils@5.16.0-beta.4