123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392 |
- Object.defineProperty(exports, '__esModule', { value: true });
- const utils = require('@sentry/utils');
- const constants = require('../constants.js');
- const eventProcessors = require('../eventProcessors.js');
- const scope = require('../scope.js');
- const applyScopeDataToEvent = require('./applyScopeDataToEvent.js');
- const spanUtils = require('./spanUtils.js');
- /**
- * This type makes sure that we get either a CaptureContext, OR an EventHint.
- * It does not allow mixing them, which could lead to unexpected outcomes, e.g. this is disallowed:
- * { user: { id: '123' }, mechanism: { handled: false } }
- */
- /**
- * Adds common information to events.
- *
- * The information includes release and environment from `options`,
- * breadcrumbs and context (extra, tags and user) from the scope.
- *
- * Information that is already present in the event is never overwritten. For
- * nested objects, such as the context, keys are merged.
- *
- * Note: This also triggers callbacks for `addGlobalEventProcessor`, but not `beforeSend`.
- *
- * @param event The original event.
- * @param hint May contain additional information about the original exception.
- * @param scope A scope containing event metadata.
- * @returns A new event with more information.
- * @hidden
- */
- function prepareEvent(
- options,
- event,
- hint,
- scope$1,
- client,
- isolationScope,
- ) {
- const { normalizeDepth = 3, normalizeMaxBreadth = 1000 } = options;
- const prepared = {
- ...event,
- event_id: event.event_id || hint.event_id || utils.uuid4(),
- timestamp: event.timestamp || utils.dateTimestampInSeconds(),
- };
- const integrations = hint.integrations || options.integrations.map(i => i.name);
- applyClientOptions(prepared, options);
- applyIntegrationsMetadata(prepared, integrations);
- // Only put debug IDs onto frames for error events.
- if (event.type === undefined) {
- applyDebugIds(prepared, options.stackParser);
- }
- // If we have scope given to us, use it as the base for further modifications.
- // This allows us to prevent unnecessary copying of data if `captureContext` is not provided.
- const finalScope = getFinalScope(scope$1, hint.captureContext);
- if (hint.mechanism) {
- utils.addExceptionMechanism(prepared, hint.mechanism);
- }
- const clientEventProcessors = client && client.getEventProcessors ? client.getEventProcessors() : [];
- // This should be the last thing called, since we want that
- // {@link Hub.addEventProcessor} gets the finished prepared event.
- // Merge scope data together
- const data = scope.getGlobalScope().getScopeData();
- if (isolationScope) {
- const isolationData = isolationScope.getScopeData();
- applyScopeDataToEvent.mergeScopeData(data, isolationData);
- }
- if (finalScope) {
- const finalScopeData = finalScope.getScopeData();
- applyScopeDataToEvent.mergeScopeData(data, finalScopeData);
- }
- const attachments = [...(hint.attachments || []), ...data.attachments];
- if (attachments.length) {
- hint.attachments = attachments;
- }
- applyScopeDataToEvent.applyScopeDataToEvent(prepared, data);
- // TODO (v8): Update this order to be: Global > Client > Scope
- const eventProcessors$1 = [
- ...clientEventProcessors,
- // eslint-disable-next-line deprecation/deprecation
- ...eventProcessors.getGlobalEventProcessors(),
- // Run scope event processors _after_ all other processors
- ...data.eventProcessors,
- ];
- const result = eventProcessors.notifyEventProcessors(eventProcessors$1, prepared, hint);
- return result.then(evt => {
- if (evt) {
- // We apply the debug_meta field only after all event processors have ran, so that if any event processors modified
- // file names (e.g.the RewriteFrames integration) the filename -> debug ID relationship isn't destroyed.
- // This should not cause any PII issues, since we're only moving data that is already on the event and not adding
- // any new data
- applyDebugMeta(evt);
- }
- if (typeof normalizeDepth === 'number' && normalizeDepth > 0) {
- return normalizeEvent(evt, normalizeDepth, normalizeMaxBreadth);
- }
- return evt;
- });
- }
- /**
- * Enhances event using the client configuration.
- * It takes care of all "static" values like environment, release and `dist`,
- * as well as truncating overly long values.
- * @param event event instance to be enhanced
- */
- function applyClientOptions(event, options) {
- const { environment, release, dist, maxValueLength = 250 } = options;
- if (!('environment' in event)) {
- event.environment = 'environment' in options ? environment : constants.DEFAULT_ENVIRONMENT;
- }
- if (event.release === undefined && release !== undefined) {
- event.release = release;
- }
- if (event.dist === undefined && dist !== undefined) {
- event.dist = dist;
- }
- if (event.message) {
- event.message = utils.truncate(event.message, maxValueLength);
- }
- const exception = event.exception && event.exception.values && event.exception.values[0];
- if (exception && exception.value) {
- exception.value = utils.truncate(exception.value, maxValueLength);
- }
- const request = event.request;
- if (request && request.url) {
- request.url = utils.truncate(request.url, maxValueLength);
- }
- }
- const debugIdStackParserCache = new WeakMap();
- /**
- * Puts debug IDs into the stack frames of an error event.
- */
- function applyDebugIds(event, stackParser) {
- const debugIdMap = utils.GLOBAL_OBJ._sentryDebugIds;
- if (!debugIdMap) {
- return;
- }
- let debugIdStackFramesCache;
- const cachedDebugIdStackFrameCache = debugIdStackParserCache.get(stackParser);
- if (cachedDebugIdStackFrameCache) {
- debugIdStackFramesCache = cachedDebugIdStackFrameCache;
- } else {
- debugIdStackFramesCache = new Map();
- debugIdStackParserCache.set(stackParser, debugIdStackFramesCache);
- }
- // Build a map of filename -> debug_id
- const filenameDebugIdMap = Object.keys(debugIdMap).reduce((acc, debugIdStackTrace) => {
- let parsedStack;
- const cachedParsedStack = debugIdStackFramesCache.get(debugIdStackTrace);
- if (cachedParsedStack) {
- parsedStack = cachedParsedStack;
- } else {
- parsedStack = stackParser(debugIdStackTrace);
- debugIdStackFramesCache.set(debugIdStackTrace, parsedStack);
- }
- for (let i = parsedStack.length - 1; i >= 0; i--) {
- const stackFrame = parsedStack[i];
- if (stackFrame.filename) {
- acc[stackFrame.filename] = debugIdMap[debugIdStackTrace];
- break;
- }
- }
- return acc;
- }, {});
- try {
- // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
- event.exception.values.forEach(exception => {
- // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
- exception.stacktrace.frames.forEach(frame => {
- if (frame.filename) {
- frame.debug_id = filenameDebugIdMap[frame.filename];
- }
- });
- });
- } catch (e) {
- // To save bundle size we're just try catching here instead of checking for the existence of all the different objects.
- }
- }
- /**
- * Moves debug IDs from the stack frames of an error event into the debug_meta field.
- */
- function applyDebugMeta(event) {
- // Extract debug IDs and filenames from the stack frames on the event.
- const filenameDebugIdMap = {};
- try {
- // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
- event.exception.values.forEach(exception => {
- // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
- exception.stacktrace.frames.forEach(frame => {
- if (frame.debug_id) {
- if (frame.abs_path) {
- filenameDebugIdMap[frame.abs_path] = frame.debug_id;
- } else if (frame.filename) {
- filenameDebugIdMap[frame.filename] = frame.debug_id;
- }
- delete frame.debug_id;
- }
- });
- });
- } catch (e) {
- // To save bundle size we're just try catching here instead of checking for the existence of all the different objects.
- }
- if (Object.keys(filenameDebugIdMap).length === 0) {
- return;
- }
- // Fill debug_meta information
- event.debug_meta = event.debug_meta || {};
- event.debug_meta.images = event.debug_meta.images || [];
- const images = event.debug_meta.images;
- Object.keys(filenameDebugIdMap).forEach(filename => {
- images.push({
- type: 'sourcemap',
- code_file: filename,
- debug_id: filenameDebugIdMap[filename],
- });
- });
- }
- /**
- * This function adds all used integrations to the SDK info in the event.
- * @param event The event that will be filled with all integrations.
- */
- function applyIntegrationsMetadata(event, integrationNames) {
- if (integrationNames.length > 0) {
- event.sdk = event.sdk || {};
- event.sdk.integrations = [...(event.sdk.integrations || []), ...integrationNames];
- }
- }
- /**
- * Applies `normalize` function on necessary `Event` attributes to make them safe for serialization.
- * Normalized keys:
- * - `breadcrumbs.data`
- * - `user`
- * - `contexts`
- * - `extra`
- * @param event Event
- * @returns Normalized event
- */
- function normalizeEvent(event, depth, maxBreadth) {
- if (!event) {
- return null;
- }
- const normalized = {
- ...event,
- ...(event.breadcrumbs && {
- breadcrumbs: event.breadcrumbs.map(b => ({
- ...b,
- ...(b.data && {
- data: utils.normalize(b.data, depth, maxBreadth),
- }),
- })),
- }),
- ...(event.user && {
- user: utils.normalize(event.user, depth, maxBreadth),
- }),
- ...(event.contexts && {
- contexts: utils.normalize(event.contexts, depth, maxBreadth),
- }),
- ...(event.extra && {
- extra: utils.normalize(event.extra, depth, maxBreadth),
- }),
- };
- // event.contexts.trace stores information about a Transaction. Similarly,
- // event.spans[] stores information about child Spans. Given that a
- // Transaction is conceptually a Span, normalization should apply to both
- // Transactions and Spans consistently.
- // For now the decision is to skip normalization of Transactions and Spans,
- // so this block overwrites the normalized event to add back the original
- // Transaction information prior to normalization.
- if (event.contexts && event.contexts.trace && normalized.contexts) {
- normalized.contexts.trace = event.contexts.trace;
- // event.contexts.trace.data may contain circular/dangerous data so we need to normalize it
- if (event.contexts.trace.data) {
- normalized.contexts.trace.data = utils.normalize(event.contexts.trace.data, depth, maxBreadth);
- }
- }
- // event.spans[].data may contain circular/dangerous data so we need to normalize it
- if (event.spans) {
- normalized.spans = event.spans.map(span => {
- const data = spanUtils.spanToJSON(span).data;
- if (data) {
- // This is a bit weird, as we generally have `Span` instances here, but to be safe we do not assume so
- // eslint-disable-next-line deprecation/deprecation
- span.data = utils.normalize(data, depth, maxBreadth);
- }
- return span;
- });
- }
- return normalized;
- }
- function getFinalScope(scope$1, captureContext) {
- if (!captureContext) {
- return scope$1;
- }
- const finalScope = scope$1 ? scope$1.clone() : new scope.Scope();
- finalScope.update(captureContext);
- return finalScope;
- }
- /**
- * Parse either an `EventHint` directly, or convert a `CaptureContext` to an `EventHint`.
- * This is used to allow to update method signatures that used to accept a `CaptureContext` but should now accept an `EventHint`.
- */
- function parseEventHintOrCaptureContext(
- hint,
- ) {
- if (!hint) {
- return undefined;
- }
- // If you pass a Scope or `() => Scope` as CaptureContext, we just return this as captureContext
- if (hintIsScopeOrFunction(hint)) {
- return { captureContext: hint };
- }
- if (hintIsScopeContext(hint)) {
- return {
- captureContext: hint,
- };
- }
- return hint;
- }
- function hintIsScopeOrFunction(
- hint,
- ) {
- return hint instanceof scope.Scope || typeof hint === 'function';
- }
- const captureContextKeys = [
- 'user',
- 'level',
- 'extra',
- 'contexts',
- 'tags',
- 'fingerprint',
- 'requestSession',
- 'propagationContext',
- ] ;
- function hintIsScopeContext(hint) {
- return Object.keys(hint).some(key => captureContextKeys.includes(key ));
- }
- exports.applyDebugIds = applyDebugIds;
- exports.applyDebugMeta = applyDebugMeta;
- exports.parseEventHintOrCaptureContext = parseEventHintOrCaptureContext;
- exports.prepareEvent = prepareEvent;
- //# sourceMappingURL=prepareEvent.js.map
|