Skip to content

Commit 6bd10c7

Browse files
HazATrhcarvalho
andauthored
feat: No longer discard transactions instead mark them deadline exceeded (getsentry#2588)
* feat: No longer discard transactions instead mark them deadline exceeded * ref: Rework debug options * fix: Use SafeJoin * Update packages/apm/src/integrations/tracing.ts Co-authored-by: Rodolfo Carvalho <rodolfo.carvalho@sentry.io> * fix: Use Sentry prefix * ref: SetData * ref: Remove tslint * ref: Revert the durationLimit change * chore: Changelog Co-authored-by: Rodolfo Carvalho <rodolfo.carvalho@sentry.io>
1 parent edbc2df commit 6bd10c7

File tree

2 files changed

+101
-18
lines changed

2 files changed

+101
-18
lines changed

CHANGELOG.md

+1
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
- [apm] fix: Use proper type name for op #2584
88
- [core] fix: sent_at for envelope headers to use same clock #2597
99
- [apm] fix: Improve bundle size by moving span status to @sentry/apm #2589
10+
- [apm] feat: No longer discard transactions instead mark them deadline exceeded #2588
1011

1112
## 5.16.0
1213

packages/apm/src/integrations/tracing.ts

+100-18
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
11
import { Hub, Scope } from '@sentry/hub';
2-
import { Event, EventProcessor, Integration, Span, SpanContext } from '@sentry/types';
2+
import { Event, EventProcessor, Integration, Severity, Span, SpanContext } from '@sentry/types';
33
import {
44
addInstrumentationHandler,
55
getGlobalObject,
66
isMatchingPattern,
77
logger,
8+
safeJoin,
89
supportsNativeFetch,
910
} from '@sentry/utils';
1011

@@ -77,6 +78,27 @@ interface TracingOptions {
7778
* Default: true
7879
*/
7980
discardBackgroundSpans: boolean;
81+
82+
/**
83+
* This is only if you want to debug in prod.
84+
* writeAsBreadcrumbs: Instead of having console.log statements we log messages to breadcrumbs
85+
* so you can investigate whats happening in production with your users to figure why things might not appear the
86+
* way you expect them to.
87+
*
88+
* spanDebugTimingInfo: Add timing info to spans at the point where we create them to figure out browser timing
89+
* issues.
90+
*
91+
* You shouldn't care about this.
92+
*
93+
* Default: {
94+
* writeAsBreadcrumbs: false;
95+
* spanDebugTimingInfo: false;
96+
* }
97+
*/
98+
debug: {
99+
writeAsBreadcrumbs: boolean;
100+
spanDebugTimingInfo: boolean;
101+
};
80102
}
81103

82104
/** JSDoc */
@@ -138,6 +160,10 @@ export class Tracing implements Integration {
138160
global.performance.mark('sentry-tracing-init');
139161
}
140162
const defaults = {
163+
debug: {
164+
spanDebugTimingInfo: false,
165+
writeAsBreadcrumbs: false,
166+
},
141167
discardBackgroundSpans: true,
142168
idleTimeout: 500,
143169
maxTransactionDuration: 600,
@@ -210,8 +236,17 @@ export class Tracing implements Integration {
210236
event.timestamp - event.start_timestamp < 0);
211237

212238
if (Tracing.options.maxTransactionDuration !== 0 && event.type === 'transaction' && isOutdatedTransaction) {
213-
logger.log('[Tracing] Discarded transaction since it maxed out maxTransactionDuration');
214-
return null;
239+
Tracing._log('[Tracing] Discarded transaction since it maxed out maxTransactionDuration');
240+
if (event.contexts && event.contexts.trace) {
241+
event.contexts.trace = {
242+
...event.contexts.trace,
243+
status: SpanStatus.DeadlineExceeded,
244+
};
245+
event.tags = {
246+
...event.tags,
247+
maxTransactionDurationExceeded: 'true',
248+
};
249+
}
215250
}
216251

217252
return event;
@@ -243,7 +278,7 @@ export class Tracing implements Integration {
243278
}
244279
if (Tracing._heartbeatCounter >= 3) {
245280
if (Tracing._activeTransaction) {
246-
logger.log(
281+
Tracing._log(
247282
"[Tracing] Heartbeat safeguard kicked in, finishing transaction since activities content hasn't changed for 3 beats",
248283
);
249284
Tracing._activeTransaction.setStatus(SpanStatus.DeadlineExceeded);
@@ -263,8 +298,10 @@ export class Tracing implements Integration {
263298
if (Tracing.options.discardBackgroundSpans && global.document) {
264299
document.addEventListener('visibilitychange', () => {
265300
if (document.hidden && Tracing._activeTransaction) {
266-
logger.log('[Tracing] Discarded active transaction incl. activities since tab moved to the background');
267-
Tracing._resetActiveTransaction();
301+
Tracing._log('[Tracing] Discarded active transaction incl. activities since tab moved to the background');
302+
Tracing._activeTransaction.setStatus(SpanStatus.Cancelled);
303+
Tracing._activeTransaction.setTag('visibilitychange', 'document.hidden');
304+
Tracing.finishIdleTransaction();
268305
}
269306
});
270307
}
@@ -337,7 +374,7 @@ export class Tracing implements Integration {
337374
/**
338375
* If an error or unhandled promise occurs, we mark the active transaction as failed
339376
*/
340-
logger.log(`[Tracing] Global error occured, setting status in transaction: ${SpanStatus.InternalError}`);
377+
Tracing._log(`[Tracing] Global error occured, setting status in transaction: ${SpanStatus.InternalError}`);
341378
Tracing._activeTransaction.setStatus(SpanStatus.InternalError);
342379
}
343380
}
@@ -351,6 +388,25 @@ export class Tracing implements Integration {
351388
});
352389
}
353390

391+
/**
392+
* Uses logger.log to log things in the SDK or as breadcrumbs if defined in options
393+
*/
394+
private static _log(...args: any[]): void {
395+
if (Tracing.options.debug && Tracing.options.debug.writeAsBreadcrumbs) {
396+
const _getCurrentHub = Tracing._getCurrentHub;
397+
if (_getCurrentHub) {
398+
_getCurrentHub().addBreadcrumb({
399+
category: 'tracing',
400+
level: Severity.Debug,
401+
message: safeJoin(args, ' '),
402+
type: 'debug',
403+
});
404+
return;
405+
}
406+
}
407+
logger.log(args);
408+
}
409+
354410
/**
355411
* Starts a Transaction waiting for activity idle to finish
356412
*/
@@ -360,7 +416,7 @@ export class Tracing implements Integration {
360416
// b) A activity wasn't popped correctly and therefore the transaction is stalling
361417
Tracing.finishIdleTransaction();
362418

363-
logger.log('[Tracing] startIdleTransaction, name:', name);
419+
Tracing._log('[Tracing] startIdleTransaction, name:', name);
364420

365421
const _getCurrentHub = Tracing._getCurrentHub;
366422
if (!_getCurrentHub) {
@@ -401,7 +457,7 @@ export class Tracing implements Integration {
401457
const active = Tracing._activeTransaction as SpanClass;
402458
if (active) {
403459
Tracing._addPerformanceEntries(active);
404-
logger.log('[Tracing] finishIdleTransaction', active.transaction);
460+
Tracing._log('[Tracing] finishIdleTransaction', active.transaction);
405461
active.finish(/*trimEnd*/ true);
406462
Tracing._resetActiveTransaction();
407463
}
@@ -420,7 +476,7 @@ export class Tracing implements Integration {
420476
return;
421477
}
422478

423-
logger.log('[Tracing] Adding & adjusting spans using Performance API');
479+
Tracing._log('[Tracing] Adding & adjusting spans using Performance API');
424480

425481
const timeOrigin = Tracing._msToSec(performance.timeOrigin);
426482

@@ -553,7 +609,7 @@ export class Tracing implements Integration {
553609
public static setTransactionStatus(status: SpanStatus): void {
554610
const active = Tracing._activeTransaction;
555611
if (active) {
556-
logger.log('[Tracing] setTransactionStatus', status);
612+
Tracing._log('[Tracing] setTransactionStatus', status);
557613
active.setStatus(status);
558614
}
559615
}
@@ -566,6 +622,29 @@ export class Tracing implements Integration {
566622
return time / 1000;
567623
}
568624

625+
/**
626+
* Adds debug data to the span
627+
*/
628+
private static _addSpanDebugInfo(span: Span): void {
629+
// tslint:disable: no-unsafe-any
630+
const debugData: any = {};
631+
if (global.performance) {
632+
debugData.performance = true;
633+
debugData['performance.timeOrigin'] = global.performance.timeOrigin;
634+
debugData['performance.now'] = global.performance.now();
635+
// tslint:disable-next-line: deprecation
636+
if (global.performance.timing) {
637+
// tslint:disable-next-line: deprecation
638+
debugData['performance.timing.navigationStart'] = performance.timing.navigationStart;
639+
}
640+
} else {
641+
debugData.performance = false;
642+
}
643+
debugData['Date.now()'] = Date.now();
644+
span.setData('sentry_debug', debugData);
645+
// tslint:enable: no-unsafe-any
646+
}
647+
569648
/**
570649
* Starts tracking for a specifc activity
571650
*
@@ -583,7 +662,7 @@ export class Tracing implements Integration {
583662
const activeTransaction = Tracing._activeTransaction;
584663

585664
if (!activeTransaction) {
586-
logger.log(`[Tracing] Not pushing activity ${name} since there is no active transaction`);
665+
Tracing._log(`[Tracing] Not pushing activity ${name} since there is no active transaction`);
587666
return 0;
588667
}
589668

@@ -606,10 +685,10 @@ export class Tracing implements Integration {
606685
};
607686
}
608687

609-
logger.log(`[Tracing] pushActivity: ${name}#${Tracing._currentIndex}`);
610-
logger.log('[Tracing] activies count', Object.keys(Tracing._activities).length);
688+
Tracing._log(`[Tracing] pushActivity: ${name}#${Tracing._currentIndex}`);
689+
Tracing._log('[Tracing] activies count', Object.keys(Tracing._activities).length);
611690
if (options && typeof options.autoPopAfter === 'number') {
612-
logger.log(`[Tracing] auto pop of: ${name}#${Tracing._currentIndex} in ${options.autoPopAfter}ms`);
691+
Tracing._log(`[Tracing] auto pop of: ${name}#${Tracing._currentIndex} in ${options.autoPopAfter}ms`);
613692
const index = Tracing._currentIndex;
614693
setTimeout(() => {
615694
Tracing.popActivity(index, {
@@ -634,7 +713,7 @@ export class Tracing implements Integration {
634713
const activity = Tracing._activities[id];
635714

636715
if (activity) {
637-
logger.log(`[Tracing] popActivity ${activity.name}#${id}`);
716+
Tracing._log(`[Tracing] popActivity ${activity.name}#${id}`);
638717
const span = activity.span;
639718
if (span) {
640719
if (spanData) {
@@ -648,6 +727,9 @@ export class Tracing implements Integration {
648727
}
649728
});
650729
}
730+
if (Tracing.options.debug && Tracing.options.debug.spanDebugTimingInfo) {
731+
Tracing._addSpanDebugInfo(span);
732+
}
651733
span.finish();
652734
}
653735
// tslint:disable-next-line: no-dynamic-delete
@@ -657,11 +739,11 @@ export class Tracing implements Integration {
657739
const count = Object.keys(Tracing._activities).length;
658740
clearTimeout(Tracing._debounce);
659741

660-
logger.log('[Tracing] activies count', count);
742+
Tracing._log('[Tracing] activies count', count);
661743

662744
if (count === 0 && Tracing._activeTransaction) {
663745
const timeout = Tracing.options && Tracing.options.idleTimeout;
664-
logger.log(`[Tracing] Flushing Transaction in ${timeout}ms`);
746+
Tracing._log(`[Tracing] Flushing Transaction in ${timeout}ms`);
665747
Tracing._debounce = (setTimeout(() => {
666748
Tracing.finishIdleTransaction();
667749
}, timeout) as any) as number;

0 commit comments

Comments
 (0)