Skip to content

Commit 727da28

Browse files
rhcarvalhoHazAT
andauthored
ref: Add hub.startTransaction extension (getsentry#2626)
* ref: Check for missing name in startTransaction Moving the check to the func where it matters eliminates the need for the internal field _isTransaction and the downstream logic in startSpan. * ref: Shorten log message Shorter message equals smaller bundle size. Limit ourselves to a single warning line. The fix to eliminate the warning is to call startTransaction({name: "some name"}) so the setName advice is misplaced. * ref: Add hub.startTransaction extension Extract code that starts transactions from startSpan and deprecate startSpan. Move check of empty transaction name to right before sending the transaction, because it is valid to start the transaction without a name and set the name later with Transaction.setName(). * misc: Disable tslint deprecation check * ref: Changes * ref: Update docs * fix: Typo * ref: Small refactor Co-authored-by: Daniel Griesser <daniel.griesser.86@gmail.com>
1 parent 8184a54 commit 727da28

File tree

7 files changed

+84
-56
lines changed

7 files changed

+84
-56
lines changed

packages/apm/src/hubextensions.ts

+41-33
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { getMainCarrier, Hub } from '@sentry/hub';
1+
import { getCurrentHub, getMainCarrier, Hub } from '@sentry/hub';
22
import { SpanContext, TransactionContext } from '@sentry/types';
33
import { logger } from '@sentry/utils';
44

@@ -20,44 +20,49 @@ function traceHeaders(this: Hub): { [key: string]: string } {
2020
}
2121

2222
/**
23-
* This functions starts a span. If there is already a `Span` on the Scope,
24-
* the created Span with the SpanContext will have a reference to it and become it's child.
25-
* Otherwise it'll crete a new `Span`.
26-
*
27-
* @param context Properties with which the span should be created
23+
* {@see Hub.startTransaction}
2824
*/
29-
function startSpan(this: Hub, context: SpanContext | TransactionContext): Transaction | Span {
30-
// This is our safeguard so people always get a Transaction in return.
31-
// We set `_isTransaction: true` in {@link Sentry.startTransaction} to have a runtime check
32-
// if the user really wanted to create a Transaction.
33-
if ((context as TransactionContext)._isTransaction && !(context as TransactionContext).name) {
34-
logger.warn('You are trying to start a Transaction but forgot to provide a `name` property.');
35-
logger.warn('Will fall back to <unlabeled transaction>, use `transaction.setName()` to change it.');
36-
(context as TransactionContext).name = '<unlabeled transaction>';
25+
function startTransaction(this: Hub, context: TransactionContext): Transaction {
26+
const transaction = new Transaction(context, this);
27+
28+
const client = this.getClient();
29+
// Roll the dice for sampling transaction, all child spans inherit the sampling decision.
30+
if (transaction.sampled === undefined) {
31+
const sampleRate = (client && client.getOptions().tracesSampleRate) || 0;
32+
// if true = we want to have the transaction
33+
// if false = we don't want to have it
34+
// Math.random (inclusive of 0, but not 1)
35+
transaction.sampled = Math.random() < sampleRate;
3736
}
3837

39-
if ((context as TransactionContext).name) {
40-
// We are dealing with a Transaction
41-
const transaction = new Transaction(context as TransactionContext, this);
38+
// We only want to create a span list if we sampled the transaction
39+
// If sampled == false, we will discard the span anyway, so we can save memory by not storing child spans
40+
if (transaction.sampled) {
41+
const experimentsOptions = (client && client.getOptions()._experiments) || {};
42+
transaction.initSpanRecorder(experimentsOptions.maxSpans as number);
43+
}
4244

43-
const client = this.getClient();
44-
// We only roll the dice on sampling for root spans of transactions because all child spans inherit this state
45-
if (transaction.sampled === undefined) {
46-
const sampleRate = (client && client.getOptions().tracesSampleRate) || 0;
47-
// if true = we want to have the transaction
48-
// if false = we don't want to have it
49-
// Math.random (inclusive of 0, but not 1)
50-
transaction.sampled = Math.random() < sampleRate;
51-
}
45+
return transaction;
46+
}
5247

53-
// We only want to create a span list if we sampled the transaction
54-
// If sampled == false, we will discard the span anyway, so we can save memory by not storing child spans
55-
if (transaction.sampled) {
56-
const experimentsOptions = (client && client.getOptions()._experiments) || {};
57-
transaction.initSpanRecorder(experimentsOptions.maxSpans as number);
58-
}
48+
/**
49+
* {@see Hub.startSpan}
50+
*/
51+
function startSpan(this: Hub, context: SpanContext): Transaction | Span {
52+
/**
53+
* @deprecated
54+
* This is here to make sure we don't break users that relied on calling startSpan to create a transaction
55+
* with the transaction poperty set.
56+
*/
57+
if ((context as any).transaction !== undefined) {
58+
logger.warn(`Use \`Sentry.startTransaction({name: ${(context as any).transaction}})\` to start a Transaction.`);
59+
(context as TransactionContext).name = (context as any).transaction as string;
60+
}
5961

60-
return transaction;
62+
// We have the check of not undefined since we defined it's ok to start a transaction with an empty name
63+
// tslint:disable-next-line: strict-type-predicates
64+
if ((context as TransactionContext).name !== undefined) {
65+
return getCurrentHub().startTransaction(context as TransactionContext);
6166
}
6267

6368
const scope = this.getScope();
@@ -80,6 +85,9 @@ export function addExtensionMethods(): void {
8085
const carrier = getMainCarrier();
8186
if (carrier.__SENTRY__) {
8287
carrier.__SENTRY__.extensions = carrier.__SENTRY__.extensions || {};
88+
if (!carrier.__SENTRY__.extensions.startTransaction) {
89+
carrier.__SENTRY__.extensions.startTransaction = startTransaction;
90+
}
8391
if (!carrier.__SENTRY__.extensions.startSpan) {
8492
carrier.__SENTRY__.extensions.startSpan = startSpan;
8593
}

packages/apm/src/span.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,7 @@ export class Span implements SpanInterface, SpanContext {
7777
public spanRecorder?: SpanRecorder;
7878

7979
/**
80-
* You should never call the custructor manually, always use `hub.startSpan()`.
80+
* You should never call the constructor manually, always use `hub.startSpan()`.
8181
* @internal
8282
* @hideconstructor
8383
* @hidden

packages/apm/src/transaction.ts

+7-1
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,8 @@ export class Transaction extends SpanClass {
4646
private readonly _trimEnd?: boolean;
4747

4848
/**
49-
* This constructor should never be called manually. Those instrumenting tracing should use `Stentry.startTransaction()`, and internal methods should use `hub.startSpan()`.
49+
* This constructor should never be called manually. Those instrumenting tracing should use
50+
* `Sentry.startTransaction()`, and internal methods should use `hub.startTransaction()`.
5051
* @internal
5152
* @hideconstructor
5253
* @hidden
@@ -92,6 +93,11 @@ export class Transaction extends SpanClass {
9293
return undefined;
9394
}
9495

96+
if (!this.name) {
97+
logger.warn('Transaction has no name, falling back to `<unlabeled transaction>`.');
98+
this.name = '<unlabeled transaction>';
99+
}
100+
95101
super.finish(endTimestamp);
96102

97103
if (this.sampled !== true) {

packages/hub/src/hub.ts

+8-1
Original file line numberDiff line numberDiff line change
@@ -368,10 +368,17 @@ export class Hub implements HubInterface {
368368
/**
369369
* @inheritDoc
370370
*/
371-
public startSpan(context: SpanContext | TransactionContext): Transaction | Span {
371+
public startSpan(context: SpanContext): Span {
372372
return this._callExtensionMethod('startSpan', context);
373373
}
374374

375+
/**
376+
* @inheritDoc
377+
*/
378+
public startTransaction(context: TransactionContext): Transaction {
379+
return this._callExtensionMethod('startTransaction', context);
380+
}
381+
375382
/**
376383
* @inheritDoc
377384
*/

packages/minimal/src/index.ts

+7-9
Original file line numberDiff line numberDiff line change
@@ -177,14 +177,12 @@ export function _callOnClient(method: string, ...args: any[]): void {
177177
}
178178

179179
/**
180-
* This starts a Transaction and is considered the entry point to do manual tracing. You can add child spans
181-
* to a transactions. After that more children can be added to created spans to buld a tree structure.
182-
* This function returns a Transaction and you need to keep track of the instance yourself. When you call `.finsh()` on
183-
* a transaction it will be sent to Sentry.
180+
* Starts a Transaction. This is the entry point to do manual tracing. You can
181+
* add child spans to transactions. Spans themselves can have children, building
182+
* a tree structure. This function returns a Transaction and you need to keep
183+
* track of the instance yourself. When you call `.finish()` on the transaction
184+
* it will be sent to Sentry.
184185
*/
185-
export function startTransaction(transactionContext: TransactionContext): Transaction {
186-
return callOnHub<Transaction>('startSpan', {
187-
...transactionContext,
188-
_isTransaction: true,
189-
});
186+
export function startTransaction(context: TransactionContext): Transaction {
187+
return callOnHub('startTransaction', { ...context });
190188
}

packages/types/src/hub.ts

+20-4
Original file line numberDiff line numberDiff line change
@@ -174,10 +174,26 @@ export interface Hub {
174174
traceHeaders(): { [key: string]: string };
175175

176176
/**
177-
* This functions starts either a Span or a Transaction (depending on the argument passed).
178-
* If there is a Span on the Scope we use the `trace_id` for all other created Transactions / Spans as a reference.
177+
* This function starts a span. If there is already a `Span` on the Scope,
178+
* the created Span with the SpanContext will have a reference to it and become it's child.
179+
* Otherwise it'll create a new `Span`.
180+
*/
181+
startSpan(context: SpanContext): Span;
182+
183+
/**
184+
* Starts a new transaction and returns it. This is the entry point to manual
185+
* tracing instrumentation.
186+
*
187+
* A tree structure can be built by adding child spans to the transaction, and
188+
* child spans to other spans. To start a new child span within the transaction
189+
* or any span, call the respective `.startChild()` method.
190+
*
191+
* Every child span must be finished before the transaction is finished,
192+
* otherwise the unfinished spans are discarded.
179193
*
180-
* @param context Properties with which the Transaction/Span should be created
194+
* The transaction must be finished with a call to its `.finish()` method, at
195+
* which point the transaction with all its finished child spans will be sent to
196+
* Sentry.
181197
*/
182-
startSpan(context: SpanContext | TransactionContext): Transaction | Span;
198+
startTransaction(context: TransactionContext): Transaction;
183199
}

packages/types/src/transaction.ts

-7
Original file line numberDiff line numberDiff line change
@@ -12,13 +12,6 @@ export interface TransactionContext extends SpanContext {
1212
* transaction after a given "idle time" and we don't want this "idle time" to be part of the transaction.
1313
*/
1414
trimEnd?: boolean;
15-
16-
/**
17-
* This flag is internally used by {@link Sentry.startTransaction} and set there to determine this is really a
18-
* Transaction. Since there is no type safety in JS we set it in the top level function to true to check later
19-
* if the user really wanted to create a Transaction and we can log a warning if they forgot to set the name property.
20-
*/
21-
_isTransaction?: boolean;
2215
}
2316

2417
/**

0 commit comments

Comments
 (0)