Some checks failed
Build & Deploy / 🔍 Prepare (push) Successful in 20s
Build & Deploy / 🧪 QA (push) Failing after 34s
Build & Deploy / 🏗️ Build (push) Has started running
Build & Deploy / 🚀 Deploy (push) Has been cancelled
Build & Deploy / 🧪 Smoke Test (push) Has been cancelled
Build & Deploy / ⚡ Lighthouse (push) Has been cancelled
Build & Deploy / 🔔 Notify (push) Has been cancelled
159 lines
5.1 KiB
Plaintext
159 lines
5.1 KiB
Plaintext
Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
|
|
|
|
const diagnosticsChannel = require('node:diagnostics_channel');
|
|
const core = require('@sentry/core');
|
|
const injectLoader = require('../sdk/injectLoader.js');
|
|
|
|
const SENTRY_TRACK_SYMBOL = Symbol('sentry-track-pino-logger');
|
|
|
|
/**
|
|
* Gets a custom Pino key from a logger instance by searching for the symbol.
|
|
* Pino uses non-global symbols like Symbol('pino.messageKey'): https://github.com/pinojs/pino/blob/8a816c0b1f72de5ae9181f3bb402109b66f7d812/lib/symbols.js
|
|
*/
|
|
function getPinoKey(logger, symbolName, defaultKey) {
|
|
const symbols = Object.getOwnPropertySymbols(logger);
|
|
const symbolString = `Symbol(${symbolName})`;
|
|
for (const sym of symbols) {
|
|
if (sym.toString() === symbolString) {
|
|
const value = logger[sym];
|
|
return typeof value === 'string' ? value : defaultKey;
|
|
}
|
|
}
|
|
return defaultKey;
|
|
}
|
|
|
|
const DEFAULT_OPTIONS = {
|
|
error: { levels: [], handled: true },
|
|
log: { levels: ['trace', 'debug', 'info', 'warn', 'error', 'fatal'] },
|
|
};
|
|
|
|
function stripIgnoredFields(result) {
|
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
const { level, time, pid, hostname, ...rest } = result;
|
|
return rest;
|
|
}
|
|
|
|
const _pinoIntegration = core.defineIntegration((userOptions = {}) => {
|
|
const options = {
|
|
autoInstrument: userOptions.autoInstrument !== false,
|
|
error: { ...DEFAULT_OPTIONS.error, ...userOptions.error },
|
|
log: { ...DEFAULT_OPTIONS.log, ...userOptions.log },
|
|
};
|
|
|
|
function shouldTrackLogger(logger) {
|
|
const override = logger[SENTRY_TRACK_SYMBOL];
|
|
return override === 'track' || (override !== 'ignore' && options.autoInstrument);
|
|
}
|
|
|
|
return {
|
|
name: 'Pino',
|
|
setup: client => {
|
|
const enableLogs = !!client.getOptions().enableLogs;
|
|
|
|
injectLoader.addInstrumentationConfig({
|
|
channelName: 'pino-log',
|
|
// From Pino v9.10.0 a tracing channel is available directly from Pino:
|
|
// https://github.com/pinojs/pino/pull/2281
|
|
module: { name: 'pino', versionRange: '>=8.0.0 < 9.10.0', filePath: 'lib/tools.js' },
|
|
functionQuery: {
|
|
functionName: 'asJson',
|
|
kind: 'Sync',
|
|
},
|
|
});
|
|
|
|
const injectedChannel = diagnosticsChannel.tracingChannel('orchestrion:pino:pino-log');
|
|
const integratedChannel = diagnosticsChannel.tracingChannel('pino_asJson');
|
|
|
|
function onPinoStart(self, args, result) {
|
|
if (!shouldTrackLogger(self)) {
|
|
return;
|
|
}
|
|
|
|
const resultObj = stripIgnoredFields(result);
|
|
|
|
const [captureObj, message, levelNumber] = args;
|
|
const level = self?.levels?.labels?.[levelNumber] || 'info';
|
|
const messageKey = getPinoKey(self, 'pino.messageKey', 'msg');
|
|
const logMessage = message || (resultObj?.[messageKey] ) || '';
|
|
|
|
if (enableLogs && options.log.levels.includes(level)) {
|
|
const attributes = {
|
|
...resultObj,
|
|
'sentry.origin': 'auto.log.pino',
|
|
'pino.logger.level': levelNumber,
|
|
};
|
|
|
|
core._INTERNAL_captureLog({ level, message: logMessage, attributes });
|
|
}
|
|
|
|
if (options.error.levels.includes(level)) {
|
|
const captureContext = {
|
|
level: core.severityLevelFromString(level),
|
|
};
|
|
|
|
core.withScope(scope => {
|
|
scope.addEventProcessor(event => {
|
|
event.logger = 'pino';
|
|
|
|
core.addExceptionMechanism(event, {
|
|
handled: options.error.handled,
|
|
type: 'pino',
|
|
});
|
|
|
|
return event;
|
|
});
|
|
|
|
const error = captureObj[getPinoKey(self, 'pino.errorKey', 'err')];
|
|
if (error) {
|
|
core.captureException(error, captureContext);
|
|
return;
|
|
}
|
|
|
|
core.captureMessage(logMessage, captureContext);
|
|
});
|
|
}
|
|
}
|
|
|
|
injectedChannel.end.subscribe(data => {
|
|
const { self, arguments: args, result } = data ;
|
|
onPinoStart(self, args, JSON.parse(result));
|
|
});
|
|
|
|
integratedChannel.end.subscribe(data => {
|
|
const {
|
|
instance,
|
|
arguments: args,
|
|
result,
|
|
} = data ;
|
|
onPinoStart(instance, args, JSON.parse(result));
|
|
});
|
|
},
|
|
};
|
|
}) ;
|
|
|
|
/**
|
|
* Integration for Pino logging library.
|
|
* Captures Pino logs as Sentry logs and optionally captures some log levels as events.
|
|
*
|
|
* By default, all Pino loggers will be captured. To ignore a specific logger, use `pinoIntegration.untrackLogger(logger)`.
|
|
*
|
|
* If you disable automatic instrumentation with `autoInstrument: false`, you can mark specific loggers to be tracked with `pinoIntegration.trackLogger(logger)`.
|
|
*
|
|
* Requires Pino >=v8.0.0 and Node >=20.6.0 or >=18.19.0
|
|
*/
|
|
const pinoIntegration = Object.assign(_pinoIntegration, {
|
|
trackLogger(logger) {
|
|
if (logger && typeof logger === 'object' && 'levels' in logger) {
|
|
(logger )[SENTRY_TRACK_SYMBOL] = 'track';
|
|
}
|
|
},
|
|
untrackLogger(logger) {
|
|
if (logger && typeof logger === 'object' && 'levels' in logger) {
|
|
(logger )[SENTRY_TRACK_SYMBOL] = 'ignore';
|
|
}
|
|
},
|
|
}) ;
|
|
|
|
exports.pinoIntegration = pinoIntegration;
|
|
//# sourceMappingURL=pino.js.map
|