@sentry/core
Version:
Base implementation for all Sentry JavaScript SDKs
189 lines (162 loc) • 6.02 kB
JavaScript
Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
const client = require('../client.js');
const currentScopes = require('../currentScopes.js');
const debugBuild = require('../debug-build.js');
const constants = require('./constants.js');
const is = require('../utils-hoist/is.js');
require('../utils-hoist/debug-build.js');
const logger = require('../utils-hoist/logger.js');
require('../utils-hoist/time.js');
require('../utils-hoist/syncpromise.js');
const spanOnScope = require('../utils/spanOnScope.js');
const envelope = require('./envelope.js');
const MAX_LOG_BUFFER_SIZE = 100;
const CLIENT_TO_LOG_BUFFER_MAP = new WeakMap();
/**
* Converts a log attribute to a serialized log attribute.
*
* @param key - The key of the log attribute.
* @param value - The value of the log attribute.
* @returns The serialized log attribute.
*/
function logAttributeToSerializedLogAttribute(key, value) {
switch (typeof value) {
case 'number':
return {
key,
value: { doubleValue: value },
};
case 'boolean':
return {
key,
value: { boolValue: value },
};
case 'string':
return {
key,
value: { stringValue: value },
};
default: {
let stringValue = '';
try {
stringValue = JSON.stringify(value) ?? '';
} catch {
// Do nothing
}
return {
key,
value: { stringValue },
};
}
}
}
/**
* Captures a log event and sends it to Sentry.
*
* @param log - The log event to capture.
* @param scope - A scope. Uses the current scope if not provided.
* @param client - A client. Uses the current client if not provided.
*
* @experimental This method will experience breaking changes. This is not yet part of
* the stable Sentry SDK API and can be changed or removed without warning.
*/
function _INTERNAL_captureLog(
beforeLog,
client$1 = currentScopes.getClient(),
scope = currentScopes.getCurrentScope(),
) {
if (!client$1) {
debugBuild.DEBUG_BUILD && logger.logger.warn('No client available to capture log.');
return;
}
const { _experiments, release, environment } = client$1.getOptions();
const { enableLogs = false, beforeSendLog } = _experiments ?? {};
if (!enableLogs) {
debugBuild.DEBUG_BUILD && logger.logger.warn('logging option not enabled, log will not be captured.');
return;
}
const [, traceContext] = client._getTraceInfoFromScope(client$1, scope);
const processedLogAttributes = {
...beforeLog.attributes,
};
if (release) {
processedLogAttributes['sentry.release'] = release;
}
if (environment) {
processedLogAttributes['sentry.environment'] = environment;
}
const { sdk } = client$1.getSdkMetadata() ?? {};
if (sdk) {
processedLogAttributes['sentry.sdk.name'] = sdk.name;
processedLogAttributes['sentry.sdk.version'] = sdk.version;
}
const beforeLogMessage = beforeLog.message;
if (is.isParameterizedString(beforeLogMessage)) {
const { __sentry_template_string__, __sentry_template_values__ = [] } = beforeLogMessage;
processedLogAttributes['sentry.message.template'] = __sentry_template_string__;
__sentry_template_values__.forEach((param, index) => {
processedLogAttributes[`sentry.message.parameter.${index}`] = param;
});
}
const span = spanOnScope._getSpanForScope(scope);
if (span) {
// Add the parent span ID to the log attributes for trace context
processedLogAttributes['sentry.trace.parent_span_id'] = span.spanContext().spanId;
}
const processedLog = { ...beforeLog, attributes: processedLogAttributes };
client$1.emit('beforeCaptureLog', processedLog);
const log = beforeSendLog ? beforeSendLog(processedLog) : processedLog;
if (!log) {
client$1.recordDroppedEvent('before_send', 'log_item', 1);
debugBuild.DEBUG_BUILD && logger.logger.warn('beforeSendLog returned null, log will not be captured.');
return;
}
const { level, message, attributes = {}, severityNumber } = log;
const serializedLog = {
severityText: level,
body: {
stringValue: message,
},
attributes: Object.entries(attributes).map(([key, value]) => logAttributeToSerializedLogAttribute(key, value)),
timeUnixNano: `${new Date().getTime().toString()}000000`,
traceId: traceContext?.trace_id,
severityNumber: severityNumber ?? constants.SEVERITY_TEXT_TO_SEVERITY_NUMBER[level],
};
const logBuffer = CLIENT_TO_LOG_BUFFER_MAP.get(client$1);
if (logBuffer === undefined) {
CLIENT_TO_LOG_BUFFER_MAP.set(client$1, [serializedLog]);
} else {
logBuffer.push(serializedLog);
if (logBuffer.length > MAX_LOG_BUFFER_SIZE) {
_INTERNAL_flushLogsBuffer(client$1, logBuffer);
}
}
client$1.emit('afterCaptureLog', log);
}
/**
* Flushes the logs buffer to Sentry.
*
* @param client - A client.
* @param maybeLogBuffer - A log buffer. Uses the log buffer for the given client if not provided.
*
* @experimental This method will experience breaking changes. This is not yet part of
* the stable Sentry SDK API and can be changed or removed without warning.
*/
function _INTERNAL_flushLogsBuffer(client, maybeLogBuffer) {
const logBuffer = maybeLogBuffer ?? CLIENT_TO_LOG_BUFFER_MAP.get(client) ?? [];
if (logBuffer.length === 0) {
return;
}
const clientOptions = client.getOptions();
const envelope$1 = envelope.createOtelLogEnvelope(logBuffer, clientOptions._metadata, clientOptions.tunnel, client.getDsn());
// Clear the log buffer after envelopes have been constructed.
logBuffer.length = 0;
client.emit('flushLogs');
// sendEnvelope should not throw
// eslint-disable-next-line @typescript-eslint/no-floating-promises
client.sendEnvelope(envelope$1);
}
exports._INTERNAL_captureLog = _INTERNAL_captureLog;
exports._INTERNAL_flushLogsBuffer = _INTERNAL_flushLogsBuffer;
exports.logAttributeToSerializedLogAttribute = logAttributeToSerializedLogAttribute;
//# sourceMappingURL=exports.js.map