Skip to content

Commit e5ce2b0

Browse files
committed
Introduce event categories for every outcome
1 parent 32a3a57 commit e5ce2b0

File tree

9 files changed

+59
-23
lines changed

9 files changed

+59
-23
lines changed

packages/browser/src/transports/base.ts

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ export abstract class BaseTransport implements Transport {
3535
/** Locks transport after receiving rate limits in a response */
3636
protected readonly _rateLimits: Record<string, Date> = {};
3737

38-
protected _outcomes: { [key in Outcome]?: number } = {};
38+
protected _outcomes: { [key: string]: number } = {};
3939

4040
public constructor(public options: TransportOptions) {
4141
this._api = new API(options.dsn, options._metadata, options.tunnel);
@@ -68,13 +68,13 @@ export abstract class BaseTransport implements Transport {
6868
/**
6969
* @inheritDoc
7070
*/
71-
public recordLostEvent(type: Outcome): void {
71+
public recordLostEvent(type: Outcome, category: SentryRequestType): void {
7272
if (!this.options.sendClientReport) {
7373
return;
7474
}
75-
76-
logger.log(`Adding ${type} outcome`);
77-
this._outcomes[type] = (this._outcomes[type] ?? 0) + 1;
75+
const key = `${type}:${CATEGORY_MAPPING[category]}`;
76+
logger.log(`Adding ${key} outcome`);
77+
this._outcomes[key] = (this._outcomes[key] ?? 0) + 1;
7878
}
7979

8080
/**
@@ -106,7 +106,14 @@ export abstract class BaseTransport implements Transport {
106106
});
107107
const item = JSON.stringify({
108108
timestamp: Date.now(),
109-
discarded_events: this._outcomes,
109+
discarded_events: Object.keys(outcomes).map(key => {
110+
const [category, reason] = key.split(':');
111+
return {
112+
reason,
113+
category,
114+
quantity: outcomes[key],
115+
};
116+
}),
110117
});
111118
const envelope = `${itemHeaders}\n${item}`;
112119

packages/browser/src/transports/fetch.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -113,7 +113,7 @@ export class FetchTransport extends BaseTransport {
113113
*/
114114
private _sendRequest(sentryRequest: SentryRequest, originalPayload: Event | Session): PromiseLike<Response> {
115115
if (this._isRateLimited(sentryRequest.type)) {
116-
this.recordLostEvent(Outcome.RateLimit);
116+
this.recordLostEvent(Outcome.RateLimit, sentryRequest.type);
117117

118118
return Promise.reject({
119119
event: originalPayload,
@@ -164,9 +164,9 @@ export class FetchTransport extends BaseTransport {
164164
)
165165
.then(undefined, reason => {
166166
if (reason instanceof SentryError) {
167-
this.recordLostEvent(Outcome.QueueSize);
167+
this.recordLostEvent(Outcome.QueueSize, sentryRequest.type);
168168
} else {
169-
this.recordLostEvent(Outcome.NetworkError);
169+
this.recordLostEvent(Outcome.NetworkError, sentryRequest.type);
170170
}
171171
throw reason;
172172
});

packages/browser/src/transports/xhr.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ export class XHRTransport extends BaseTransport {
2626
*/
2727
private _sendRequest(sentryRequest: SentryRequest, originalPayload: Event | Session): PromiseLike<Response> {
2828
if (this._isRateLimited(sentryRequest.type)) {
29-
this.recordLostEvent(Outcome.RateLimit);
29+
this.recordLostEvent(Outcome.RateLimit, sentryRequest.type);
3030

3131
return Promise.reject({
3232
event: originalPayload,
@@ -65,9 +65,9 @@ export class XHRTransport extends BaseTransport {
6565
)
6666
.then(undefined, reason => {
6767
if (reason instanceof SentryError) {
68-
this.recordLostEvent(Outcome.QueueSize);
68+
this.recordLostEvent(Outcome.QueueSize, sentryRequest.type);
6969
} else {
70-
this.recordLostEvent(Outcome.NetworkError);
70+
this.recordLostEvent(Outcome.NetworkError, sentryRequest.type);
7171
}
7272
throw reason;
7373
});

packages/core/src/baseclient.ts

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import {
1010
Outcome,
1111
SessionStatus,
1212
Severity,
13+
Transport,
1314
} from '@sentry/types';
1415
import {
1516
dateTimestampInSeconds,
@@ -182,13 +183,19 @@ export abstract class BaseClient<B extends Backend, O extends Options> implement
182183
return this._options;
183184
}
184185

186+
/**
187+
* @inheritDoc
188+
*/
189+
public getTransport(): Transport {
190+
return this.getTransport();
191+
}
192+
185193
/**
186194
* @inheritDoc
187195
*/
188196
public flush(timeout?: number): PromiseLike<boolean> {
189197
return this._isClientDoneProcessing(timeout).then(clientFinished => {
190-
return this._getBackend()
191-
.getTransport()
198+
return this.getTransport()
192199
.close(timeout)
193200
.then(transportFlushed => clientFinished && transportFlushed);
194201
});
@@ -499,7 +506,7 @@ export abstract class BaseClient<B extends Backend, O extends Options> implement
499506
protected _processEvent(event: Event, hint?: EventHint, scope?: Scope): PromiseLike<Event> {
500507
// eslint-disable-next-line @typescript-eslint/unbound-method
501508
const { beforeSend, sampleRate } = this.getOptions();
502-
const transport = this._getBackend().getTransport();
509+
const transport = this.getTransport();
503510

504511
if (!this._isEnabled()) {
505512
return SyncPromise.reject(new SentryError('SDK not enabled, will not capture event.'));
@@ -510,7 +517,7 @@ export abstract class BaseClient<B extends Backend, O extends Options> implement
510517
// 0.0 === 0% events are sent
511518
// Sampling for transaction happens somewhere else
512519
if (!isTransaction && typeof sampleRate === 'number' && Math.random() > sampleRate) {
513-
transport.recordLostEvent?.(Outcome.SampleRate);
520+
transport.recordLostEvent?.(Outcome.SampleRate, 'event');
514521
return SyncPromise.reject(
515522
new SentryError(
516523
`Discarding event because it's not included in the random sample (sampling rate = ${sampleRate})`,
@@ -521,7 +528,7 @@ export abstract class BaseClient<B extends Backend, O extends Options> implement
521528
return this._prepareEvent(event, scope, hint)
522529
.then(prepared => {
523530
if (prepared === null) {
524-
transport.recordLostEvent?.(Outcome.EventProcessor);
531+
transport.recordLostEvent?.(Outcome.EventProcessor, event.type || 'event');
525532
throw new SentryError('An event processor returned null, will not send event.');
526533
}
527534

@@ -535,7 +542,7 @@ export abstract class BaseClient<B extends Backend, O extends Options> implement
535542
})
536543
.then(processedEvent => {
537544
if (processedEvent === null) {
538-
transport.recordLostEvent?.(Outcome.BeforeSend);
545+
transport.recordLostEvent?.(Outcome.BeforeSend, event.type || 'event');
539546
throw new SentryError('`beforeSend` returned `null`, will not send event.');
540547
}
541548

packages/core/test/lib/base.test.ts

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,16 @@ describe('BaseClient', () => {
8888
});
8989
});
9090

91+
describe('getTransport()', () => {
92+
test('returns the transport from backend', () => {
93+
expect.assertions(1);
94+
const options = { dsn: PUBLIC_DSN, transport: FakeTransport };
95+
const client = new TestClient(options);
96+
expect(client.getTransport()).toBeInstanceOf(FakeTransport);
97+
expect(TestBackend.instance!.getTransport()).toBe(client.getTransport());
98+
});
99+
});
100+
91101
describe('getBreadcrumbs() / addBreadcrumb()', () => {
92102
test('adds a breadcrumb', () => {
93103
expect.assertions(1);
@@ -906,7 +916,7 @@ describe('BaseClient', () => {
906916
});
907917

908918
const delay = 1;
909-
const transportInstance = (client as any)._getBackend().getTransport() as FakeTransport;
919+
const transportInstance = client.getTransport() as FakeTransport;
910920
transportInstance.delay = delay;
911921

912922
client.captureMessage('test');
@@ -935,7 +945,7 @@ describe('BaseClient', () => {
935945
setTimeout(() => resolve({ message, level }), 150);
936946
}),
937947
);
938-
const transportInstance = (client as any)._getBackend().getTransport() as FakeTransport;
948+
const transportInstance = client.getTransport() as FakeTransport;
939949
transportInstance.delay = delay;
940950

941951
client.captureMessage('test async');
@@ -959,7 +969,7 @@ describe('BaseClient', () => {
959969
});
960970

961971
const delay = 1;
962-
const transportInstance = (client as any)._getBackend().getTransport() as FakeTransport;
972+
const transportInstance = client.getTransport() as FakeTransport;
963973
transportInstance.delay = delay;
964974

965975
expect(client.captureMessage('test')).toBeTruthy();

packages/node/src/client.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -98,7 +98,7 @@ export class NodeClient extends BaseClient<NodeBackend, NodeOptions> {
9898
if (!release) {
9999
logger.warn('Cannot initialise an instance of SessionFlusher if no release is provided!');
100100
} else {
101-
this._sessionFlusher = new SessionFlusher(this._backend.getTransport(), {
101+
this._sessionFlusher = new SessionFlusher(this.getTransport(), {
102102
release,
103103
environment,
104104
});

packages/tracing/src/transaction.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import { getCurrentHub, Hub } from '@sentry/hub';
22
import {
33
Event,
44
Measurements,
5+
Outcome,
56
Transaction as TransactionInterface,
67
TransactionContext,
78
TransactionMetadata,
@@ -102,6 +103,12 @@ export class Transaction extends SpanClass implements TransactionInterface {
102103
if (this.sampled !== true) {
103104
// At this point if `sampled !== true` we want to discard the transaction.
104105
logger.log('[Tracing] Discarding transaction because its trace was not chosen to be sampled.');
106+
107+
this._hub
108+
.getClient()
109+
?.getTransport()
110+
.recordLostEvent?.(Outcome.SampleRate, 'transaction');
111+
105112
return undefined;
106113
}
107114

packages/types/src/client.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import { Options } from './options';
55
import { Scope } from './scope';
66
import { Session } from './session';
77
import { Severity } from './severity';
8+
import { Transport } from './transport';
89

910
/**
1011
* User-Facing Sentry SDK Client.
@@ -59,6 +60,9 @@ export interface Client<O extends Options = Options> {
5960
/** Returns the current options. */
6061
getOptions(): O;
6162

63+
/** Returns clients transport. */
64+
getTransport(): Transport;
65+
6266
/**
6367
* Flush the event queue and set the client to `enabled = false`. See {@link Client.flush}.
6468
*

packages/types/src/transport.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import { DsnLike } from './dsn';
22
import { Event } from './event';
3+
import { SentryRequestType } from './request';
34
import { Response } from './response';
45
import { SdkMetadata } from './sdkmetadata';
56
import { Session, SessionAggregates } from './session';
@@ -42,7 +43,7 @@ export interface Transport {
4243
/**
4344
* Increment the counter for the specific client outcome
4445
*/
45-
recordLostEvent?(type: Outcome): void;
46+
recordLostEvent?(type: Outcome, category: SentryRequestType): void;
4647
}
4748

4849
/** JSDoc */

0 commit comments

Comments
 (0)