Skip to content

Commit 4f0dfe8

Browse files
committed
ref(core): Expose prepareEvent util function
1 parent 86d3e06 commit 4f0dfe8

File tree

5 files changed

+210
-165
lines changed

5 files changed

+210
-165
lines changed

packages/browser/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@
6666
"size:check": "run-p size:check:es5 size:check:es6",
6767
"size:check:es5": "cat build/bundles/bundle.min.js | gzip -9 | wc -c | awk '{$1=$1/1024; print \"ES5: \",$1,\"kB\";}'",
6868
"size:check:es6": "cat build/bundles/bundle.es6.min.js | gzip -9 | wc -c | awk '{$1=$1/1024; print \"ES6: \",$1,\"kB\";}'",
69-
"test": "run-s test:unit",
69+
"test": "yarn test:unit",
7070
"test:unit": "jest",
7171
"test:integration": "test/integration/run.js",
7272
"test:integration:checkbrowsers": "node scripts/checkbrowsers.js",

packages/browser/test/unit/index.test.ts

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -180,6 +180,19 @@ describe('SentryBrowser', () => {
180180
captureEvent({ message: 'event' });
181181
});
182182

183+
it('should set `platform` on events', done => {
184+
const options = getDefaultBrowserClientOptions({
185+
beforeSend: (event: Event): Event | null => {
186+
expect(event.platform).toBe('javascript');
187+
done();
188+
return event;
189+
},
190+
dsn,
191+
});
192+
getCurrentHub().bindClient(new BrowserClient(options));
193+
captureEvent({ message: 'event' });
194+
});
195+
183196
it('should not dedupe an event on bound client', async () => {
184197
const localBeforeSend = jest.fn();
185198
const options = getDefaultBrowserClientOptions({

packages/core/src/baseclient.ts

Lines changed: 3 additions & 164 deletions
Original file line numberDiff line numberDiff line change
@@ -23,26 +23,23 @@ import {
2323
addItemToEnvelope,
2424
checkOrSetAlreadyCaught,
2525
createAttachmentEnvelopeItem,
26-
dateTimestampInSeconds,
2726
isPlainObject,
2827
isPrimitive,
2928
isThenable,
3029
logger,
3130
makeDsn,
32-
normalize,
3331
rejectedSyncPromise,
3432
resolvedSyncPromise,
3533
SentryError,
3634
SyncPromise,
37-
truncate,
38-
uuid4,
3935
} from '@sentry/utils';
4036

4137
import { getEnvelopeEndpointWithUrlEncodedAuth } from './api';
4238
import { createEventEnvelope, createSessionEnvelope } from './envelope';
4339
import { IntegrationIndex, setupIntegrations } from './integration';
4440
import { Scope } from './scope';
4541
import { updateSession } from './session';
42+
import { prepareEvent } from './utils/prepareEvent';
4643

4744
const ALREADY_SEEN_ERROR = "Not capturing exception because it's already been captured.";
4845

@@ -322,7 +319,7 @@ export abstract class BaseClient<O extends ClientOptions> implements Client<O> {
322319
// Note: we use `event` in replay, where we overwrite this hook.
323320

324321
if (this._options.sendClientReports) {
325-
// We want to track each category (error, transaction, session) separately
322+
// We want to track each category (error, transaction, session, replay_event) separately
326323
// but still keep the distinction between different type of outcomes.
327324
// We could use nested maps, but it's much easier to read and type this way.
328325
// A correct type for map-based implementation if we want to go that route
@@ -419,166 +416,8 @@ export abstract class BaseClient<O extends ClientOptions> implements Client<O> {
419416
* @returns A new event with more information.
420417
*/
421418
protected _prepareEvent(event: Event, hint: EventHint, scope?: Scope): PromiseLike<Event | null> {
422-
const { normalizeDepth = 3, normalizeMaxBreadth = 1_000 } = this.getOptions();
423-
const prepared: Event = {
424-
...event,
425-
event_id: event.event_id || hint.event_id || uuid4(),
426-
timestamp: event.timestamp || dateTimestampInSeconds(),
427-
};
428-
429-
this._applyClientOptions(prepared);
430-
this._applyIntegrationsMetadata(prepared);
431-
432-
// If we have scope given to us, use it as the base for further modifications.
433-
// This allows us to prevent unnecessary copying of data if `captureContext` is not provided.
434-
let finalScope = scope;
435-
if (hint.captureContext) {
436-
finalScope = Scope.clone(finalScope).update(hint.captureContext);
437-
}
438-
439-
// We prepare the result here with a resolved Event.
440-
let result = resolvedSyncPromise<Event | null>(prepared);
441-
442-
// This should be the last thing called, since we want that
443-
// {@link Hub.addEventProcessor} gets the finished prepared event.
444-
//
445-
// We need to check for the existence of `finalScope.getAttachments`
446-
// because `getAttachments` can be undefined if users are using an older version
447-
// of `@sentry/core` that does not have the `getAttachments` method.
448-
// See: https://github.com/getsentry/sentry-javascript/issues/5229
449-
if (finalScope && finalScope.getAttachments) {
450-
// Collect attachments from the hint and scope
451-
const attachments = [...(hint.attachments || []), ...finalScope.getAttachments()];
452-
453-
if (attachments.length) {
454-
hint.attachments = attachments;
455-
}
456-
457-
// In case we have a hub we reassign it.
458-
result = finalScope.applyToEvent(prepared, hint);
459-
}
460-
461-
return result.then(evt => {
462-
if (typeof normalizeDepth === 'number' && normalizeDepth > 0) {
463-
return this._normalizeEvent(evt, normalizeDepth, normalizeMaxBreadth);
464-
}
465-
return evt;
466-
});
467-
}
468-
469-
/**
470-
* Applies `normalize` function on necessary `Event` attributes to make them safe for serialization.
471-
* Normalized keys:
472-
* - `breadcrumbs.data`
473-
* - `user`
474-
* - `contexts`
475-
* - `extra`
476-
* @param event Event
477-
* @returns Normalized event
478-
*/
479-
protected _normalizeEvent(event: Event | null, depth: number, maxBreadth: number): Event | null {
480-
if (!event) {
481-
return null;
482-
}
483-
484-
const normalized: Event = {
485-
...event,
486-
...(event.breadcrumbs && {
487-
breadcrumbs: event.breadcrumbs.map(b => ({
488-
...b,
489-
...(b.data && {
490-
data: normalize(b.data, depth, maxBreadth),
491-
}),
492-
})),
493-
}),
494-
...(event.user && {
495-
user: normalize(event.user, depth, maxBreadth),
496-
}),
497-
...(event.contexts && {
498-
contexts: normalize(event.contexts, depth, maxBreadth),
499-
}),
500-
...(event.extra && {
501-
extra: normalize(event.extra, depth, maxBreadth),
502-
}),
503-
};
504-
505-
// event.contexts.trace stores information about a Transaction. Similarly,
506-
// event.spans[] stores information about child Spans. Given that a
507-
// Transaction is conceptually a Span, normalization should apply to both
508-
// Transactions and Spans consistently.
509-
// For now the decision is to skip normalization of Transactions and Spans,
510-
// so this block overwrites the normalized event to add back the original
511-
// Transaction information prior to normalization.
512-
if (event.contexts && event.contexts.trace && normalized.contexts) {
513-
normalized.contexts.trace = event.contexts.trace;
514-
515-
// event.contexts.trace.data may contain circular/dangerous data so we need to normalize it
516-
if (event.contexts.trace.data) {
517-
normalized.contexts.trace.data = normalize(event.contexts.trace.data, depth, maxBreadth);
518-
}
519-
}
520-
521-
// event.spans[].data may contain circular/dangerous data so we need to normalize it
522-
if (event.spans) {
523-
normalized.spans = event.spans.map(span => {
524-
// We cannot use the spread operator here because `toJSON` on `span` is non-enumerable
525-
if (span.data) {
526-
span.data = normalize(span.data, depth, maxBreadth);
527-
}
528-
return span;
529-
});
530-
}
531-
532-
return normalized;
533-
}
534-
535-
/**
536-
* Enhances event using the client configuration.
537-
* It takes care of all "static" values like environment, release and `dist`,
538-
* as well as truncating overly long values.
539-
* @param event event instance to be enhanced
540-
*/
541-
protected _applyClientOptions(event: Event): void {
542419
const options = this.getOptions();
543-
const { environment, release, dist, maxValueLength = 250 } = options;
544-
545-
if (!('environment' in event)) {
546-
event.environment = 'environment' in options ? environment : 'production';
547-
}
548-
549-
if (event.release === undefined && release !== undefined) {
550-
event.release = release;
551-
}
552-
553-
if (event.dist === undefined && dist !== undefined) {
554-
event.dist = dist;
555-
}
556-
557-
if (event.message) {
558-
event.message = truncate(event.message, maxValueLength);
559-
}
560-
561-
const exception = event.exception && event.exception.values && event.exception.values[0];
562-
if (exception && exception.value) {
563-
exception.value = truncate(exception.value, maxValueLength);
564-
}
565-
566-
const request = event.request;
567-
if (request && request.url) {
568-
request.url = truncate(request.url, maxValueLength);
569-
}
570-
}
571-
572-
/**
573-
* This function adds all used integrations to the SDK info in the event.
574-
* @param event The event that will be filled with all integrations.
575-
*/
576-
protected _applyIntegrationsMetadata(event: Event): void {
577-
const integrationsArray = Object.keys(this._integrations);
578-
if (integrationsArray.length > 0) {
579-
event.sdk = event.sdk || {};
580-
event.sdk.integrations = [...(event.sdk.integrations || []), ...integrationsArray];
581-
}
420+
return prepareEvent(options, event, hint, scope);
582421
}
583422

584423
/**

packages/core/src/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ export { createTransport } from './transports/base';
2727
export { SDK_VERSION } from './version';
2828
export { getIntegrationsToSetup } from './integration';
2929
export { FunctionToString, InboundFilters } from './integrations';
30+
export { prepareEvent } from './utils/prepareEvent';
3031

3132
import * as Integrations from './integrations';
3233

0 commit comments

Comments
 (0)