123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336 |
- import { dropUndefinedKeys, logger } from '@sentry/utils';
- import { DEBUG_BUILD } from '../debug-build.js';
- import { getCurrentHub } from '../hub.js';
- import { getMetricSummaryJsonForSpan } from '../metrics/metric-summary.js';
- import { SEMANTIC_ATTRIBUTE_SENTRY_SOURCE, SEMANTIC_ATTRIBUTE_SENTRY_SAMPLE_RATE } from '../semanticAttributes.js';
- import { spanTimeInputToSeconds, spanToJSON, spanToTraceContext } from '../utils/spanUtils.js';
- import { getDynamicSamplingContextFromSpan } from './dynamicSamplingContext.js';
- import { Span, SpanRecorder } from './span.js';
- import { getCapturedScopesOnSpan } from './trace.js';
- class Transaction extends Span {
-
-
-
- constructor(transactionContext, hub) {
- super(transactionContext);
- this._measurements = {};
- this._contexts = {};
-
- this._hub = hub || getCurrentHub();
- this._name = transactionContext.name || '';
- this._metadata = {
-
- ...transactionContext.metadata,
- };
- this._trimEnd = transactionContext.trimEnd;
-
-
-
- this.transaction = this;
-
-
- const incomingDynamicSamplingContext = this._metadata.dynamicSamplingContext;
- if (incomingDynamicSamplingContext) {
-
- this._frozenDynamicSamplingContext = { ...incomingDynamicSamplingContext };
- }
- }
-
-
-
- get name() {
- return this._name;
- }
-
- set name(newName) {
-
- this.setName(newName);
- }
-
- get metadata() {
-
- return {
-
-
- source: 'custom',
- spanMetadata: {},
-
- ...this._metadata,
-
- ...(this._attributes[SEMANTIC_ATTRIBUTE_SENTRY_SOURCE] && {
- source: this._attributes[SEMANTIC_ATTRIBUTE_SENTRY_SOURCE] ,
- }),
- ...(this._attributes[SEMANTIC_ATTRIBUTE_SENTRY_SAMPLE_RATE] && {
- sampleRate: this._attributes[SEMANTIC_ATTRIBUTE_SENTRY_SAMPLE_RATE] ,
- }),
- };
- }
-
- set metadata(metadata) {
- this._metadata = metadata;
- }
-
-
- setName(name, source = 'custom') {
- this._name = name;
- this.setAttribute(SEMANTIC_ATTRIBUTE_SENTRY_SOURCE, source);
- }
-
- updateName(name) {
- this._name = name;
- return this;
- }
-
- initSpanRecorder(maxlen = 1000) {
-
- if (!this.spanRecorder) {
-
- this.spanRecorder = new SpanRecorder(maxlen);
- }
-
- this.spanRecorder.add(this);
- }
-
- setContext(key, context) {
- if (context === null) {
-
- delete this._contexts[key];
- } else {
- this._contexts[key] = context;
- }
- }
-
- setMeasurement(name, value, unit = '') {
- this._measurements[name] = { value, unit };
- }
-
- setMetadata(newMetadata) {
- this._metadata = { ...this._metadata, ...newMetadata };
- }
-
- end(endTimestamp) {
- const timestampInS = spanTimeInputToSeconds(endTimestamp);
- const transaction = this._finishTransaction(timestampInS);
- if (!transaction) {
- return undefined;
- }
-
- return this._hub.captureEvent(transaction);
- }
-
- toContext() {
-
- const spanContext = super.toContext();
- return dropUndefinedKeys({
- ...spanContext,
- name: this._name,
- trimEnd: this._trimEnd,
- });
- }
-
- updateWithContext(transactionContext) {
-
- super.updateWithContext(transactionContext);
- this._name = transactionContext.name || '';
- this._trimEnd = transactionContext.trimEnd;
- return this;
- }
-
- getDynamicSamplingContext() {
- return getDynamicSamplingContextFromSpan(this);
- }
-
- setHub(hub) {
- this._hub = hub;
- }
-
- _finishTransaction(endTimestamp) {
-
- if (this._endTime !== undefined) {
- return undefined;
- }
- if (!this._name) {
- DEBUG_BUILD && logger.warn('Transaction has no name, falling back to `<unlabeled transaction>`.');
- this._name = '<unlabeled transaction>';
- }
-
- super.end(endTimestamp);
-
- const client = this._hub.getClient();
- if (client && client.emit) {
- client.emit('finishTransaction', this);
- }
- if (this._sampled !== true) {
-
- DEBUG_BUILD && logger.log('[Tracing] Discarding transaction because its trace was not chosen to be sampled.');
- if (client) {
- client.recordDroppedEvent('sample_rate', 'transaction');
- }
- return undefined;
- }
-
- const finishedSpans = this.spanRecorder
- ?
- this.spanRecorder.spans.filter(span => span !== this && spanToJSON(span).timestamp)
- : [];
- if (this._trimEnd && finishedSpans.length > 0) {
- const endTimes = finishedSpans.map(span => spanToJSON(span).timestamp).filter(Boolean) ;
- this._endTime = endTimes.reduce((prev, current) => {
- return prev > current ? prev : current;
- });
- }
- const { scope: capturedSpanScope, isolationScope: capturedSpanIsolationScope } = getCapturedScopesOnSpan(this);
-
- const { metadata } = this;
-
- const { source } = metadata;
- const transaction = {
- contexts: {
- ...this._contexts,
-
- trace: spanToTraceContext(this),
- },
-
- spans: finishedSpans,
- start_timestamp: this._startTime,
-
- tags: this.tags,
- timestamp: this._endTime,
- transaction: this._name,
- type: 'transaction',
- sdkProcessingMetadata: {
- ...metadata,
- capturedSpanScope,
- capturedSpanIsolationScope,
- dynamicSamplingContext: getDynamicSamplingContextFromSpan(this),
- },
- _metrics_summary: getMetricSummaryJsonForSpan(this),
- ...(source && {
- transaction_info: {
- source,
- },
- }),
- };
- const hasMeasurements = Object.keys(this._measurements).length > 0;
- if (hasMeasurements) {
- DEBUG_BUILD &&
- logger.log(
- '[Measurements] Adding measurements to transaction',
- JSON.stringify(this._measurements, undefined, 2),
- );
- transaction.measurements = this._measurements;
- }
-
- DEBUG_BUILD && logger.log(`[Tracing] Finishing ${this.op} transaction: ${this._name}.`);
- return transaction;
- }
- }
- export { Transaction };
|