1 | Object.defineProperty(exports, '__esModule', { value: true });
|
2 |
|
3 | const utils = require('@sentry/utils');
|
4 | const constants = require('../constants.js');
|
5 | const hub = require('../hub.js');
|
6 | const span = require('./span.js');
|
7 |
|
8 |
|
9 | class Transaction extends span.Span {
|
10 |
|
11 | |
12 |
|
13 |
|
14 |
|
15 | __init() {this._measurements = {};}
|
16 |
|
17 | __init2() {this._contexts = {};}
|
18 |
|
19 | __init3() {this._frozenDynamicSamplingContext = undefined;}
|
20 |
|
21 | |
22 |
|
23 |
|
24 |
|
25 |
|
26 |
|
27 |
|
28 | constructor(transactionContext, hub$1) {
|
29 | super(transactionContext);Transaction.prototype.__init.call(this);Transaction.prototype.__init2.call(this);Transaction.prototype.__init3.call(this);
|
30 | this._hub = hub$1 || hub.getCurrentHub();
|
31 |
|
32 | this._name = transactionContext.name || '';
|
33 |
|
34 | this.metadata = {
|
35 | source: 'custom',
|
36 | ...transactionContext.metadata,
|
37 | spanMetadata: {},
|
38 | };
|
39 |
|
40 | this._trimEnd = transactionContext.trimEnd;
|
41 |
|
42 |
|
43 | this.transaction = this;
|
44 |
|
45 |
|
46 |
|
47 | const incomingDynamicSamplingContext = this.metadata.dynamicSamplingContext;
|
48 | if (incomingDynamicSamplingContext) {
|
49 |
|
50 | this._frozenDynamicSamplingContext = { ...incomingDynamicSamplingContext };
|
51 | }
|
52 | }
|
53 |
|
54 |
|
55 | get name() {
|
56 | return this._name;
|
57 | }
|
58 |
|
59 |
|
60 | set name(newName) {
|
61 | this.setName(newName);
|
62 | }
|
63 |
|
64 | |
65 |
|
66 |
|
67 | setName(name, source = 'custom') {
|
68 | this._name = name;
|
69 | this.metadata.source = source;
|
70 | }
|
71 |
|
72 | |
73 |
|
74 |
|
75 |
|
76 | initSpanRecorder(maxlen = 1000) {
|
77 | if (!this.spanRecorder) {
|
78 | this.spanRecorder = new span.SpanRecorder(maxlen);
|
79 | }
|
80 | this.spanRecorder.add(this);
|
81 | }
|
82 |
|
83 | |
84 |
|
85 |
|
86 | setContext(key, context) {
|
87 | if (context === null) {
|
88 |
|
89 | delete this._contexts[key];
|
90 | } else {
|
91 | this._contexts[key] = context;
|
92 | }
|
93 | }
|
94 |
|
95 | |
96 |
|
97 |
|
98 | setMeasurement(name, value, unit = '') {
|
99 | this._measurements[name] = { value, unit };
|
100 | }
|
101 |
|
102 | |
103 |
|
104 |
|
105 | setMetadata(newMetadata) {
|
106 | this.metadata = { ...this.metadata, ...newMetadata };
|
107 | }
|
108 |
|
109 | |
110 |
|
111 |
|
112 | finish(endTimestamp) {
|
113 |
|
114 | if (this.endTimestamp !== undefined) {
|
115 | return undefined;
|
116 | }
|
117 |
|
118 | if (!this.name) {
|
119 | (typeof __SENTRY_DEBUG__ === 'undefined' || __SENTRY_DEBUG__) && utils.logger.warn('Transaction has no name, falling back to `<unlabeled transaction>`.');
|
120 | this.name = '<unlabeled transaction>';
|
121 | }
|
122 |
|
123 |
|
124 | super.finish(endTimestamp);
|
125 |
|
126 | const client = this._hub.getClient();
|
127 | if (client && client.emit) {
|
128 | client.emit('finishTransaction', this);
|
129 | }
|
130 |
|
131 | if (this.sampled !== true) {
|
132 |
|
133 | (typeof __SENTRY_DEBUG__ === 'undefined' || __SENTRY_DEBUG__) && utils.logger.log('[Tracing] Discarding transaction because its trace was not chosen to be sampled.');
|
134 |
|
135 | if (client) {
|
136 | client.recordDroppedEvent('sample_rate', 'transaction');
|
137 | }
|
138 |
|
139 | return undefined;
|
140 | }
|
141 |
|
142 | const finishedSpans = this.spanRecorder ? this.spanRecorder.spans.filter(s => s !== this && s.endTimestamp) : [];
|
143 |
|
144 | if (this._trimEnd && finishedSpans.length > 0) {
|
145 | this.endTimestamp = finishedSpans.reduce((prev, current) => {
|
146 | if (prev.endTimestamp && current.endTimestamp) {
|
147 | return prev.endTimestamp > current.endTimestamp ? prev : current;
|
148 | }
|
149 | return prev;
|
150 | }).endTimestamp;
|
151 | }
|
152 |
|
153 | const metadata = this.metadata;
|
154 |
|
155 | const transaction = {
|
156 | contexts: {
|
157 | ...this._contexts,
|
158 |
|
159 | trace: this.getTraceContext(),
|
160 | },
|
161 | spans: finishedSpans,
|
162 | start_timestamp: this.startTimestamp,
|
163 | tags: this.tags,
|
164 | timestamp: this.endTimestamp,
|
165 | transaction: this.name,
|
166 | type: 'transaction',
|
167 | sdkProcessingMetadata: {
|
168 | ...metadata,
|
169 | dynamicSamplingContext: this.getDynamicSamplingContext(),
|
170 | },
|
171 | ...(metadata.source && {
|
172 | transaction_info: {
|
173 | source: metadata.source,
|
174 | },
|
175 | }),
|
176 | };
|
177 |
|
178 | const hasMeasurements = Object.keys(this._measurements).length > 0;
|
179 |
|
180 | if (hasMeasurements) {
|
181 | (typeof __SENTRY_DEBUG__ === 'undefined' || __SENTRY_DEBUG__) &&
|
182 | utils.logger.log(
|
183 | '[Measurements] Adding measurements to transaction',
|
184 | JSON.stringify(this._measurements, undefined, 2),
|
185 | );
|
186 | transaction.measurements = this._measurements;
|
187 | }
|
188 |
|
189 | (typeof __SENTRY_DEBUG__ === 'undefined' || __SENTRY_DEBUG__) && utils.logger.log(`[Tracing] Finishing ${this.op} transaction: ${this.name}.`);
|
190 |
|
191 | return this._hub.captureEvent(transaction);
|
192 | }
|
193 |
|
194 | |
195 |
|
196 |
|
197 | toContext() {
|
198 | const spanContext = super.toContext();
|
199 |
|
200 | return utils.dropUndefinedKeys({
|
201 | ...spanContext,
|
202 | name: this.name,
|
203 | trimEnd: this._trimEnd,
|
204 | });
|
205 | }
|
206 |
|
207 | |
208 |
|
209 |
|
210 | updateWithContext(transactionContext) {
|
211 | super.updateWithContext(transactionContext);
|
212 |
|
213 | this.name = transactionContext.name || '';
|
214 |
|
215 | this._trimEnd = transactionContext.trimEnd;
|
216 |
|
217 | return this;
|
218 | }
|
219 |
|
220 | |
221 |
|
222 |
|
223 |
|
224 |
|
225 | getDynamicSamplingContext() {
|
226 | if (this._frozenDynamicSamplingContext) {
|
227 | return this._frozenDynamicSamplingContext;
|
228 | }
|
229 |
|
230 | const hub$1 = this._hub || hub.getCurrentHub();
|
231 | const client = hub$1 && hub$1.getClient();
|
232 |
|
233 | if (!client) return {};
|
234 |
|
235 | const { environment, release } = client.getOptions() || {};
|
236 | const { publicKey: public_key } = client.getDsn() || {};
|
237 |
|
238 | const maybeSampleRate = this.metadata.sampleRate;
|
239 | const sample_rate = maybeSampleRate !== undefined ? maybeSampleRate.toString() : undefined;
|
240 |
|
241 | const scope = hub$1.getScope();
|
242 | const { segment: user_segment } = (scope && scope.getUser()) || {};
|
243 |
|
244 | const source = this.metadata.source;
|
245 |
|
246 |
|
247 | const transaction = source && source !== 'url' ? this.name : undefined;
|
248 |
|
249 | const dsc = utils.dropUndefinedKeys({
|
250 | environment: environment || constants.DEFAULT_ENVIRONMENT,
|
251 | release,
|
252 | transaction,
|
253 | user_segment,
|
254 | public_key,
|
255 | trace_id: this.traceId,
|
256 | sample_rate,
|
257 | });
|
258 |
|
259 |
|
260 |
|
261 |
|
262 | return dsc;
|
263 | }
|
264 | }
|
265 |
|
266 | exports.Transaction = Transaction;
|
267 |
|