diff --git a/packages/core/src/baseclient.ts b/packages/core/src/baseclient.ts index c7b3e89032f4..8a801ca79b0e 100644 --- a/packages/core/src/baseclient.ts +++ b/packages/core/src/baseclient.ts @@ -490,7 +490,11 @@ export abstract class BaseClient implement // 0.0 === 0% events are sent // Sampling for transaction happens somewhere else if (!isTransaction && typeof sampleRate === 'number' && Math.random() > sampleRate) { - return SyncPromise.reject(new SentryError('This event has been sampled, will not send event.')); + return SyncPromise.reject( + new SentryError( + `Discarding event because it's not included in the random sample (sampling rate = ${sampleRate})`, + ), + ); } return this._prepareEvent(event, scope, hint) diff --git a/packages/core/test/lib/sdk.test.ts b/packages/core/test/lib/sdk.test.ts index 9910cf1391dd..241994d7584f 100644 --- a/packages/core/test/lib/sdk.test.ts +++ b/packages/core/test/lib/sdk.test.ts @@ -51,7 +51,7 @@ describe('SDK', () => { expect((DEFAULT_INTEGRATIONS[1].setupOnce as jest.Mock).mock.calls.length).toBe(1); }); - test('not installs default integrations', () => { + test("doesn't install default integrations if told not to", () => { const DEFAULT_INTEGRATIONS: Integration[] = [ new MockIntegration('MockIntegration 1'), new MockIntegration('MockIntegration 2'), diff --git a/packages/node/src/handlers.ts b/packages/node/src/handlers.ts index ad353423c022..f03e7aa5c50f 100644 --- a/packages/node/src/handlers.ts +++ b/packages/node/src/handlers.ts @@ -139,10 +139,10 @@ function extractExpressTransactionName( return info; } -type TransactionTypes = 'path' | 'methodPath' | 'handler'; +type TransactionNamingScheme = 'path' | 'methodPath' | 'handler'; /** JSDoc */ -function extractTransaction(req: ExpressRequest, type: boolean | TransactionTypes): string { +function extractTransaction(req: ExpressRequest, type: boolean | TransactionNamingScheme): string { switch (type) { case 'path': { return extractExpressTransactionName(req, { path: true }); @@ -186,7 +186,7 @@ export interface ParseRequestOptions { ip?: boolean; request?: boolean | string[]; serverName?: boolean; - transaction?: boolean | TransactionTypes; + transaction?: boolean | TransactionNamingScheme; user?: boolean | string[]; version?: boolean; } diff --git a/packages/node/test/handlers.test.ts b/packages/node/test/handlers.test.ts index 6f1bdd43ba50..6540a5d765c2 100644 --- a/packages/node/test/handlers.test.ts +++ b/packages/node/test/handlers.test.ts @@ -2,7 +2,7 @@ import * as sentryCore from '@sentry/core'; import { Hub } from '@sentry/hub'; import * as sentryHub from '@sentry/hub'; import { SpanStatus, Transaction } from '@sentry/tracing'; -import { Runtime, Transaction as TransactionType } from '@sentry/types'; +import { Runtime } from '@sentry/types'; import * as http from 'http'; import * as net from 'net'; @@ -255,7 +255,7 @@ describe('tracingHandler', () => { it('pulls status code from the response', done => { const transaction = new Transaction({ name: 'mockTransaction' }); - jest.spyOn(sentryCore, 'startTransaction').mockReturnValue(transaction as TransactionType); + jest.spyOn(sentryCore, 'startTransaction').mockReturnValue(transaction as Transaction); const finishTransaction = jest.spyOn(transaction, 'finish'); sentryTracingMiddleware(req, res, next); @@ -302,7 +302,7 @@ describe('tracingHandler', () => { it('closes the transaction when request processing is done', done => { const transaction = new Transaction({ name: 'mockTransaction' }); - jest.spyOn(sentryCore, 'startTransaction').mockReturnValue(transaction as TransactionType); + jest.spyOn(sentryCore, 'startTransaction').mockReturnValue(transaction as Transaction); const finishTransaction = jest.spyOn(transaction, 'finish'); sentryTracingMiddleware(req, res, next); @@ -321,7 +321,7 @@ describe('tracingHandler', () => { description: 'reallyCoolHandler', op: 'middleware', }); - jest.spyOn(sentryCore, 'startTransaction').mockReturnValue(transaction as TransactionType); + jest.spyOn(sentryCore, 'startTransaction').mockReturnValue(transaction as Transaction); const finishSpan = jest.spyOn(span, 'finish'); const finishTransaction = jest.spyOn(transaction, 'finish'); diff --git a/packages/serverless/package.json b/packages/serverless/package.json index 47fc9a8b6ca3..dd1364ecc56c 100644 --- a/packages/serverless/package.json +++ b/packages/serverless/package.json @@ -60,8 +60,8 @@ "fix": "run-s fix:eslint fix:prettier", "fix:prettier": "prettier --write \"{src,test}/**/*.ts\"", "fix:eslint": "eslint . --format stylish --fix", - "test": "jest --passWithNoTests", - "test:watch": "jest --watch --passWithNoTests", + "test": "jest", + "test:watch": "jest --watch", "pack": "npm pack" }, "volta": { diff --git a/packages/tracing/src/browser/browsertracing.ts b/packages/tracing/src/browser/browsertracing.ts index 0110dcb9cc5a..ee51900df7a5 100644 --- a/packages/tracing/src/browser/browsertracing.ts +++ b/packages/tracing/src/browser/browsertracing.ts @@ -1,5 +1,5 @@ import { Hub } from '@sentry/hub'; -import { EventProcessor, Integration, Transaction as TransactionType, TransactionContext } from '@sentry/types'; +import { EventProcessor, Integration, Transaction, TransactionContext } from '@sentry/types'; import { logger } from '@sentry/utils'; import { startIdleTransaction } from '../hubextensions'; @@ -76,7 +76,7 @@ export interface BrowserTracingOptions extends RequestInstrumentationOptions { * Instrumentation that creates routing change transactions. By default creates * pageload and navigation transactions. */ - routingInstrumentation( + routingInstrumentation( startTransaction: (context: TransactionContext) => T | undefined, startTransactionOnPageLoad?: boolean, startTransactionOnLocationChange?: boolean, @@ -182,7 +182,7 @@ export class BrowserTracing implements Integration { } /** Create routing idle transaction. */ - private _createRouteTransaction(context: TransactionContext): TransactionType | undefined { + private _createRouteTransaction(context: TransactionContext): Transaction | undefined { if (!this._getCurrentHub) { logger.warn(`[Tracing] Did not create ${context.op} transaction because _getCurrentHub is invalid.`); return undefined; @@ -216,7 +216,7 @@ export class BrowserTracing implements Integration { adjustTransactionDuration(secToMs(maxTransactionDuration), transaction, endTimestamp); }); - return idleTransaction as TransactionType; + return idleTransaction as Transaction; } } diff --git a/packages/tracing/src/browser/metrics.ts b/packages/tracing/src/browser/metrics.ts index 27ad7cc1c6c6..d1ca770e0ad1 100644 --- a/packages/tracing/src/browser/metrics.ts +++ b/packages/tracing/src/browser/metrics.ts @@ -321,7 +321,7 @@ export interface ResourceEntry extends Record { decodedBodySize?: number; } -/** Create resource related spans */ +/** Create resource-related spans */ export function addResourceSpans( transaction: Transaction, entry: ResourceEntry, @@ -375,27 +375,27 @@ function addPerformanceNavigationTiming( return; } _startChild(transaction, { - description: event, - endTimestamp: timeOrigin + msToSec(end), op: 'browser', + description: event, startTimestamp: timeOrigin + msToSec(start), + endTimestamp: timeOrigin + msToSec(end), }); } /** Create request and response related spans */ function addRequest(transaction: Transaction, entry: Record, timeOrigin: number): void { _startChild(transaction, { - description: 'request', - endTimestamp: timeOrigin + msToSec(entry.responseEnd as number), op: 'browser', + description: 'request', startTimestamp: timeOrigin + msToSec(entry.requestStart as number), + endTimestamp: timeOrigin + msToSec(entry.responseEnd as number), }); _startChild(transaction, { - description: 'response', - endTimestamp: timeOrigin + msToSec(entry.responseEnd as number), op: 'browser', + description: 'response', startTimestamp: timeOrigin + msToSec(entry.responseStart as number), + endTimestamp: timeOrigin + msToSec(entry.responseEnd as number), }); } diff --git a/packages/tracing/src/browser/router.ts b/packages/tracing/src/browser/router.ts index 2e7e3398bc75..4ed79ffe88c3 100644 --- a/packages/tracing/src/browser/router.ts +++ b/packages/tracing/src/browser/router.ts @@ -1,4 +1,4 @@ -import { Transaction as TransactionType, TransactionContext } from '@sentry/types'; +import { Transaction, TransactionContext } from '@sentry/types'; import { addInstrumentationHandler, getGlobalObject, logger } from '@sentry/utils'; const global = getGlobalObject(); @@ -6,7 +6,7 @@ const global = getGlobalObject(); /** * Default function implementing pageload and navigation transactions */ -export function defaultRoutingInstrumentation( +export function defaultRoutingInstrumentation( startTransaction: (context: TransactionContext) => T | undefined, startTransactionOnPageLoad: boolean = true, startTransactionOnLocationChange: boolean = true, diff --git a/packages/tracing/test/span.test.ts b/packages/tracing/test/span.test.ts index de2ad536d639..9ee079503c82 100644 --- a/packages/tracing/test/span.test.ts +++ b/packages/tracing/test/span.test.ts @@ -127,9 +127,8 @@ describe('Span', () => { traceId: 'c', }); const serialized = spanB.toJSON(); - expect(serialized).toHaveProperty('start_timestamp'); - delete (serialized as { start_timestamp: number }).start_timestamp; expect(serialized).toStrictEqual({ + start_timestamp: expect.any(Number), parent_span_id: 'b', span_id: 'd', trace_id: 'c', diff --git a/packages/utils/src/object.ts b/packages/utils/src/object.ts index 7fe8012ab7da..3a41d71c3107 100644 --- a/packages/utils/src/object.ts +++ b/packages/utils/src/object.ts @@ -12,16 +12,17 @@ import { truncate } from './string'; * * @param source An object that contains a method to be wrapped. * @param name A name of method to be wrapped. - * @param replacement A function that should be used to wrap a given method. + * @param replacementFactory A function that should be used to wrap a given method, returning the wrapped method which + * will be substituted in for `source[name]`. * @returns void */ -export function fill(source: { [key: string]: any }, name: string, replacement: (...args: any[]) => any): void { +export function fill(source: { [key: string]: any }, name: string, replacementFactory: (...args: any[]) => any): void { if (!(name in source)) { return; } const original = source[name] as () => any; - const wrapped = replacement(original) as WrappedFunction; + const wrapped = replacementFactory(original) as WrappedFunction; // Make sure it's a function first, as we need to attach an empty prototype for `defineProperties` to work // otherwise it'll throw "TypeError: Object.defineProperties called on non-object" @@ -56,10 +57,10 @@ export function urlEncode(object: { [key: string]: any }): string { } /** - * Transforms any object into an object literal with all it's attributes + * Transforms any object into an object literal with all its attributes * attached to it. * - * @param value Initial source that we have to transform in order to be usable by the serializer + * @param value Initial source that we have to transform in order for it to be usable by the serializer */ function getWalkSource( value: any, @@ -383,7 +384,7 @@ export function dropUndefinedKeys(val: T): T { } if (Array.isArray(val)) { - return val.map(dropUndefinedKeys) as any; + return (val as any[]).map(dropUndefinedKeys) as any; } return val; diff --git a/packages/utils/src/string.ts b/packages/utils/src/string.ts index 83896358dc4f..4722ad4f172a 100644 --- a/packages/utils/src/string.ts +++ b/packages/utils/src/string.ts @@ -4,7 +4,7 @@ import { isRegExp, isString } from './is'; * Truncates given string to the maximum characters count * * @param str An object that contains serializable values - * @param max Maximum number of characters in truncated string + * @param max Maximum number of characters in truncated string (0 = unlimited) * @returns string Encoded */ export function truncate(str: string, max: number = 0): string { diff --git a/packages/utils/test/string.test.ts b/packages/utils/test/string.test.ts index e1b75aca3f5d..316328d9ee13 100644 --- a/packages/utils/test/string.test.ts +++ b/packages/utils/test/string.test.ts @@ -2,13 +2,19 @@ import { isMatchingPattern, truncate } from '../src/string'; describe('truncate()', () => { test('it works as expected', () => { - expect(truncate(null, 3)).toEqual(null); expect(truncate('lolol', 3)).toEqual('lol...'); expect(truncate('lolol', 10)).toEqual('lolol'); expect(truncate('1'.repeat(1000), 300)).toHaveLength(303); expect(truncate(new Array(1000).join('f'), 0)).toEqual(new Array(1000).join('f')); expect(truncate(new Array(1000).join('f'), 0)).toEqual(new Array(1000).join('f')); }); + + test('should bail out as an identity function when given non-string value', () => { + expect(truncate(null as any, 3)).toEqual(null); + expect(truncate(undefined as any, 3)).toEqual(undefined); + expect(truncate({} as any, 3)).toEqual({}); + expect(truncate([] as any, 3)).toEqual([]); + }); }); describe('isMatchingPattern()', () => { @@ -33,9 +39,9 @@ describe('isMatchingPattern()', () => { }); test('should bail out with false when given non-string value', () => { - expect(isMatchingPattern(null, 'foo')).toEqual(false); - expect(isMatchingPattern(undefined, 'foo')).toEqual(false); - expect(isMatchingPattern({}, 'foo')).toEqual(false); - expect(isMatchingPattern([], 'foo')).toEqual(false); + expect(isMatchingPattern(null as any, 'foo')).toEqual(false); + expect(isMatchingPattern(undefined as any, 'foo')).toEqual(false); + expect(isMatchingPattern({} as any, 'foo')).toEqual(false); + expect(isMatchingPattern([] as any, 'foo')).toEqual(false); }); });