Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Add scope.getTransaction, rename scope.setTransaction -> setTransactionName #2668

Merged
merged 16 commits into from Jun 22, 2020
3 changes: 2 additions & 1 deletion CHANGELOG.md
Expand Up @@ -9,7 +9,8 @@
- [core] feat: Export `makeMain` (#2665)
- [core] fix: Call `bindClient` when creating new `Hub` to make integrations work automatically (#2665)
- [gatsby] feat: Add @sentry/gatsby package (#2652)
- [core] ref: Rename `whitelistUrls/blacklistUrls` to `allowUrls/denyUrls`
- [apm] feat: Add `Sentry.getSpan` to return the Span on the Scope (#2668)
- [core] ref: Rename `whitelistUrls/blacklistUrls` to `allowUrls/denyUrls` (#2671)

## 5.17.0

Expand Down
16 changes: 16 additions & 0 deletions packages/apm/src/hubextensions.ts
Expand Up @@ -19,6 +19,19 @@ function traceHeaders(this: Hub): { [key: string]: string } {
return {};
}

/**
* {@see Hub.getSpan}
*/
function getSpan(this: Hub, callback: (span: Span) => void): void {
const scope = this.getScope();
if (scope) {
const span = scope.getSpan();
if (span) {
callback(span);
}
}
}

/**
* {@see Hub.startTransaction}
*/
Expand Down Expand Up @@ -96,6 +109,9 @@ export function addExtensionMethods(): void {
if (!carrier.__SENTRY__.extensions.startSpan) {
carrier.__SENTRY__.extensions.startSpan = startSpan;
}
if (!carrier.__SENTRY__.extensions.getSpan) {
carrier.__SENTRY__.extensions.getSpan = getSpan;
}
if (!carrier.__SENTRY__.extensions.traceHeaders) {
carrier.__SENTRY__.extensions.traceHeaders = traceHeaders;
}
Expand Down
17 changes: 15 additions & 2 deletions packages/apm/src/span.ts
@@ -1,5 +1,5 @@
import { Span as SpanInterface, SpanContext } from '@sentry/types';
import { dropUndefinedKeys, timestampWithMs, uuid4 } from '@sentry/utils';
import { Span as SpanInterface, SpanContext, Transaction } from '@sentry/types';
import { dropUndefinedKeys, logger, timestampWithMs, uuid4 } from '@sentry/utils';

import { SpanStatus } from './spanstatus';
import { SpanRecorder } from './transaction';
Expand Down Expand Up @@ -153,6 +153,19 @@ export class Span implements SpanInterface, SpanContext {
return span;
}

/**
* @inheritDoc
*/
public getTransaction(): Transaction {
const recorder = this.spanRecorder;
if (!recorder) {
logger.warn('This Span has no reference to a Transaction. Returning an instance to itself.');
HazAT marked this conversation as resolved.
Show resolved Hide resolved
logger.warn('It means that the Transaction has been sampled or the Span did not originate from a Transaction.');
return (this as unknown) as Transaction;
HazAT marked this conversation as resolved.
Show resolved Hide resolved
HazAT marked this conversation as resolved.
Show resolved Hide resolved
}
return recorder.spans[0] as Transaction;
HazAT marked this conversation as resolved.
Show resolved Hide resolved
}

/**
* Continues a trace from a string (usually the header).
* @param traceparent Traceparent string
Expand Down
22 changes: 22 additions & 0 deletions packages/apm/test/hub.test.ts
Expand Up @@ -11,6 +11,28 @@ describe('Hub', () => {
jest.useRealTimers();
});

describe('getSpan', () => {
HazAT marked this conversation as resolved.
Show resolved Hide resolved
HazAT marked this conversation as resolved.
Show resolved Hide resolved
test('simple invoke', () => {
const hub = new Hub(new BrowserClient({ tracesSampleRate: 1 }));
const transaction = hub.startTransaction({ name: 'foo' });
hub.configureScope(scope => {
scope.setSpan(transaction);
});
hub.getSpan(t => {
expect(t).toBe(transaction);
});
});

test('not invoke', () => {
const hub = new Hub(new BrowserClient({ tracesSampleRate: 1 }));
const transaction = hub.startTransaction({ name: 'foo' });
hub.getSpan(_ => {
expect(true).toBe(false);
});
transaction.finish();
});
});

describe('spans', () => {
describe('sampling', () => {
test('set tracesSampleRate 0 on span', () => {
Expand Down
13 changes: 13 additions & 0 deletions packages/apm/test/span.test.ts
Expand Up @@ -366,6 +366,19 @@ describe('Span', () => {
});
});

test('getTransaction on Span from Transaction', () => {
const transaction = hub.startTransaction({ name: 'test' });
const childSpan = transaction.startChild();
childSpan.finish();
transaction.finish();
expect(childSpan.getTransaction()).toBe(transaction);
});

test('getTransaction on new Span()', () => {
const span = new Span({});
expect(span.getTransaction()).toBe(span);
});

describe('getTraceContext', () => {
test('should have status attribute undefined if no status tag is available', () => {
const span = new Span({});
Expand Down
7 changes: 7 additions & 0 deletions packages/hub/src/hub.ts
Expand Up @@ -380,6 +380,13 @@ export class Hub implements HubInterface {
return this._callExtensionMethod('startTransaction', context);
}

/**
* @inheritDoc
*/
public getSpan(callback: (span: Span) => void): void {
this._callExtensionMethod<void>('getSpan', callback);
}

/**
* @inheritDoc
*/
Expand Down
19 changes: 18 additions & 1 deletion packages/minimal/src/index.ts
@@ -1,5 +1,14 @@
import { getCurrentHub, Hub, Scope } from '@sentry/hub';
import { Breadcrumb, CaptureContext, Event, Severity, Transaction, TransactionContext, User } from '@sentry/types';
import {
Breadcrumb,
CaptureContext,
Event,
Severity,
Span,
Transaction,
TransactionContext,
User,
} from '@sentry/types';

/**
* This calls a function on the current hub.
Expand Down Expand Up @@ -196,3 +205,11 @@ export function _callOnClient(method: string, ...args: any[]): void {
export function startTransaction(context: TransactionContext): Transaction {
return callOnHub('startTransaction', { ...context });
}

/**
* Callback that receives a Span if there is one on the Scope.
* @param callback Will only be invoked in case there is a Span on the Scope
*/
export function getSpan(callback: (span: Span) => void): void {
HazAT marked this conversation as resolved.
Show resolved Hide resolved
callOnHub<void>('getSpan', callback);
}
6 changes: 6 additions & 0 deletions packages/types/src/hub.ts
Expand Up @@ -199,4 +199,10 @@ export interface Hub {
* @param context Properties of the new `Transaction`.
*/
startTransaction(context: TransactionContext): Transaction;

/**
* Callback that receives a Span if there is one on the Scope.
* @param callback Will only be invoked in case there is a Span on the Scope
*/
getSpan(callback: (span: Span) => void): void;
}
7 changes: 7 additions & 0 deletions packages/types/src/span.ts
@@ -1,3 +1,5 @@
import { Transaction } from './transaction';

/** Interface holding all properties that can be set on a Span on creation. */
export interface SpanContext {
/**
Expand Down Expand Up @@ -133,6 +135,11 @@ export interface Span extends SpanContext {
spanContext?: Pick<SpanContext, Exclude<keyof SpanContext, 'spanId' | 'sampled' | 'traceId' | 'parentSpanId'>>,
): Span;

/**
* Retruns the reference to the root Span (Transaction).
*/
getTransaction(): Transaction;

/**
* Determines whether span was successful (HTTP200)
*/
Expand Down