package.build.npm.cjs.integrations.breadcrumbs.js Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of browser Show documentation
Show all versions of browser Show documentation
Official Sentry SDK for browsers
Object.defineProperty(exports, '__esModule', { value: true });
const browserUtils = require('@sentry-internal/browser-utils');
const core = require('@sentry/core');
const utils = require('@sentry/utils');
const debugBuild = require('../debug-build.js');
const helpers = require('../helpers.js');
/** maxStringLength gets capped to prevent 100 breadcrumbs exceeding 1MB event payload size */
const MAX_ALLOWED_STRING_LENGTH = 1024;
const INTEGRATION_NAME = 'Breadcrumbs';
const _breadcrumbsIntegration = ((options = {}) => {
const _options = {
console: true,
dom: true,
fetch: true,
history: true,
sentry: true,
xhr: true,
...options,
};
return {
name: INTEGRATION_NAME,
setup(client) {
if (_options.console) {
utils.addConsoleInstrumentationHandler(_getConsoleBreadcrumbHandler(client));
}
if (_options.dom) {
browserUtils.addClickKeypressInstrumentationHandler(_getDomBreadcrumbHandler(client, _options.dom));
}
if (_options.xhr) {
browserUtils.addXhrInstrumentationHandler(_getXhrBreadcrumbHandler(client));
}
if (_options.fetch) {
utils.addFetchInstrumentationHandler(_getFetchBreadcrumbHandler(client));
}
if (_options.history) {
browserUtils.addHistoryInstrumentationHandler(_getHistoryBreadcrumbHandler(client));
}
if (_options.sentry) {
client.on('beforeSendEvent', _getSentryBreadcrumbHandler(client));
}
},
};
}) ;
const breadcrumbsIntegration = core.defineIntegration(_breadcrumbsIntegration);
/**
* Adds a breadcrumb for Sentry events or transactions if this option is enabled.
*/
function _getSentryBreadcrumbHandler(client) {
return function addSentryBreadcrumb(event) {
if (core.getClient() !== client) {
return;
}
core.addBreadcrumb(
{
category: `sentry.${event.type === 'transaction' ? 'transaction' : 'event'}`,
event_id: event.event_id,
level: event.level,
message: utils.getEventDescription(event),
},
{
event,
},
);
};
}
/**
* A HOC that creaes a function that creates breadcrumbs from DOM API calls.
* This is a HOC so that we get access to dom options in the closure.
*/
function _getDomBreadcrumbHandler(
client,
dom,
) {
return function _innerDomBreadcrumb(handlerData) {
if (core.getClient() !== client) {
return;
}
let target;
let componentName;
let keyAttrs = typeof dom === 'object' ? dom.serializeAttribute : undefined;
let maxStringLength =
typeof dom === 'object' && typeof dom.maxStringLength === 'number' ? dom.maxStringLength : undefined;
if (maxStringLength && maxStringLength > MAX_ALLOWED_STRING_LENGTH) {
debugBuild.DEBUG_BUILD &&
utils.logger.warn(
`\`dom.maxStringLength\` cannot exceed ${MAX_ALLOWED_STRING_LENGTH}, but a value of ${maxStringLength} was configured. Sentry will use ${MAX_ALLOWED_STRING_LENGTH} instead.`,
);
maxStringLength = MAX_ALLOWED_STRING_LENGTH;
}
if (typeof keyAttrs === 'string') {
keyAttrs = [keyAttrs];
}
// Accessing event.target can throw (see getsentry/raven-js#838, #768)
try {
const event = handlerData.event ;
const element = _isEvent(event) ? event.target : event;
target = utils.htmlTreeAsString(element, { keyAttrs, maxStringLength });
componentName = utils.getComponentName(element);
} catch (e) {
target = '';
}
if (target.length === 0) {
return;
}
const breadcrumb = {
category: `ui.${handlerData.name}`,
message: target,
};
if (componentName) {
breadcrumb.data = { 'ui.component_name': componentName };
}
core.addBreadcrumb(breadcrumb, {
event: handlerData.event,
name: handlerData.name,
global: handlerData.global,
});
};
}
/**
* Creates breadcrumbs from console API calls
*/
function _getConsoleBreadcrumbHandler(client) {
return function _consoleBreadcrumb(handlerData) {
if (core.getClient() !== client) {
return;
}
const breadcrumb = {
category: 'console',
data: {
arguments: handlerData.args,
logger: 'console',
},
level: utils.severityLevelFromString(handlerData.level),
message: utils.safeJoin(handlerData.args, ' '),
};
if (handlerData.level === 'assert') {
if (handlerData.args[0] === false) {
breadcrumb.message = `Assertion failed: ${utils.safeJoin(handlerData.args.slice(1), ' ') || 'console.assert'}`;
breadcrumb.data.arguments = handlerData.args.slice(1);
} else {
// Don't capture a breadcrumb for passed assertions
return;
}
}
core.addBreadcrumb(breadcrumb, {
input: handlerData.args,
level: handlerData.level,
});
};
}
/**
* Creates breadcrumbs from XHR API calls
*/
function _getXhrBreadcrumbHandler(client) {
return function _xhrBreadcrumb(handlerData) {
if (core.getClient() !== client) {
return;
}
const { startTimestamp, endTimestamp } = handlerData;
const sentryXhrData = handlerData.xhr[browserUtils.SENTRY_XHR_DATA_KEY];
// We only capture complete, non-sentry requests
if (!startTimestamp || !endTimestamp || !sentryXhrData) {
return;
}
const { method, url, status_code, body } = sentryXhrData;
const data = {
method,
url,
status_code,
};
const hint = {
xhr: handlerData.xhr,
input: body,
startTimestamp,
endTimestamp,
};
const level = utils.getBreadcrumbLogLevelFromHttpStatusCode(status_code);
core.addBreadcrumb(
{
category: 'xhr',
data,
type: 'http',
level,
},
hint,
);
};
}
/**
* Creates breadcrumbs from fetch API calls
*/
function _getFetchBreadcrumbHandler(client) {
return function _fetchBreadcrumb(handlerData) {
if (core.getClient() !== client) {
return;
}
const { startTimestamp, endTimestamp } = handlerData;
// We only capture complete fetch requests
if (!endTimestamp) {
return;
}
if (handlerData.fetchData.url.match(/sentry_key/) && handlerData.fetchData.method === 'POST') {
// We will not create breadcrumbs for fetch requests that contain `sentry_key` (internal sentry requests)
return;
}
if (handlerData.error) {
const data = handlerData.fetchData;
const hint = {
data: handlerData.error,
input: handlerData.args,
startTimestamp,
endTimestamp,
};
core.addBreadcrumb(
{
category: 'fetch',
data,
level: 'error',
type: 'http',
},
hint,
);
} else {
const response = handlerData.response ;
const data = {
...handlerData.fetchData,
status_code: response && response.status,
};
const hint = {
input: handlerData.args,
response,
startTimestamp,
endTimestamp,
};
const level = utils.getBreadcrumbLogLevelFromHttpStatusCode(data.status_code);
core.addBreadcrumb(
{
category: 'fetch',
data,
type: 'http',
level,
},
hint,
);
}
};
}
/**
* Creates breadcrumbs from history API calls
*/
function _getHistoryBreadcrumbHandler(client) {
return function _historyBreadcrumb(handlerData) {
if (core.getClient() !== client) {
return;
}
let from = handlerData.from;
let to = handlerData.to;
const parsedLoc = utils.parseUrl(helpers.WINDOW.location.href);
let parsedFrom = from ? utils.parseUrl(from) : undefined;
const parsedTo = utils.parseUrl(to);
// Initial pushState doesn't provide `from` information
if (!parsedFrom || !parsedFrom.path) {
parsedFrom = parsedLoc;
}
// Use only the path component of the URL if the URL matches the current
// document (almost all the time when using pushState)
if (parsedLoc.protocol === parsedTo.protocol && parsedLoc.host === parsedTo.host) {
to = parsedTo.relative;
}
if (parsedLoc.protocol === parsedFrom.protocol && parsedLoc.host === parsedFrom.host) {
from = parsedFrom.relative;
}
core.addBreadcrumb({
category: 'navigation',
data: {
from,
to,
},
});
};
}
function _isEvent(event) {
return !!event && !!(event ).target;
}
exports.breadcrumbsIntegration = breadcrumbsIntegration;
//# sourceMappingURL=breadcrumbs.js.map