Skip to content

Commit e7ea403

Browse files
author
Zachary Haber
committed
feat: use data Error for callStack information
use the first data value if an Error to get callstack info. Only 1 line will be stripped from it by default Refs: #1268
1 parent 5e15dca commit e7ea403

1 file changed

Lines changed: 59 additions & 16 deletions

File tree

lib/logger.js

Lines changed: 59 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,39 @@
11
/* eslint no-underscore-dangle: ["error", { "allow": ["_log"] }] */
22

3-
const debug = require("debug")("log4js:logger");
4-
const LoggingEvent = require("./LoggingEvent");
5-
const levels = require("./levels");
6-
const clustering = require("./clustering");
7-
const categories = require("./categories");
8-
const configuration = require("./configuration");
3+
const debug = require('debug')('log4js:logger');
4+
const LoggingEvent = require('./LoggingEvent');
5+
const levels = require('./levels');
6+
const clustering = require('./clustering');
7+
const categories = require('./categories');
8+
const configuration = require('./configuration');
99

1010
const stackReg = /at (?:(.+)\s+\()?(?:(.+?):(\d+)(?::(\d+))?|([^)]+))\)?/;
11+
/**
12+
* The top entry is the Error
13+
*/
14+
const baseCallStackSkip = 1;
15+
/**
16+
* The _log function is 3 levels deep, we need to skip those to make it to the callSite
17+
*/
18+
const defaultErrorCallStackSkip = 3;
1119

12-
function defaultParseCallStack(data, skipIdx = 4) {
20+
/**
21+
*
22+
* @param {Error} data
23+
* @param {number} skipIdx
24+
* @returns {import('../types/log4js').CallStack | null}
25+
*/
26+
function defaultParseCallStack(
27+
data,
28+
skipIdx = defaultErrorCallStackSkip + baseCallStackSkip
29+
) {
1330
try {
14-
const stacklines = data.stack.split("\n").slice(skipIdx);
31+
const stacklines = data.stack.split('\n').slice(skipIdx);
32+
if (!stacklines.length) {
33+
// There's no stack in this stack
34+
// Should we try a previous index if skipIdx was set?
35+
return null;
36+
}
1537
const lineMatch = stackReg.exec(stacklines[0]);
1638
/* istanbul ignore else: failsafe */
1739
if (lineMatch && lineMatch.length === 6) {
@@ -20,14 +42,14 @@ function defaultParseCallStack(data, skipIdx = 4) {
2042
fileName: lineMatch[2],
2143
lineNumber: parseInt(lineMatch[3], 10),
2244
columnNumber: parseInt(lineMatch[4], 10),
23-
callStack: stacklines.join("\n")
45+
callStack: stacklines.join('\n'),
2446
};
25-
} else { // eslint-disable-line no-else-return
47+
// eslint-disable-next-line no-else-return
48+
} else {
2649
// will never get here unless nodejs has changes to Error
2750
console.error('log4js.logger - defaultParseCallStack error'); // eslint-disable-line no-console
2851
}
29-
}
30-
catch (err) {
52+
} catch (err) {
3153
// will never get error unless nodejs has breaking changes to Error
3254
console.error('log4js.logger - defaultParseCallStack error', err); // eslint-disable-line no-console
3355
}
@@ -49,10 +71,11 @@ function defaultParseCallStack(data, skipIdx = 4) {
4971
class Logger {
5072
constructor(name) {
5173
if (!name) {
52-
throw new Error("No category provided.");
74+
throw new Error('No category provided.');
5375
}
5476
this.category = name;
5577
this.context = {};
78+
/** @private */
5679
this.parseCallStack = defaultParseCallStack;
5780
debug(`Logger created (${this.category}, ${this.level})`);
5881
}
@@ -84,7 +107,11 @@ class Logger {
84107
if (!logLevel) {
85108
if (configuration.validIdentifier(level) && args.length > 0) {
86109
// logLevel not found but of valid signature, WARN before fallback to INFO
87-
this.log(levels.WARN, 'log4js:logger.log: valid log-level not found as first parameter given:', level);
110+
this.log(
111+
levels.WARN,
112+
'log4js:logger.log: valid log-level not found as first parameter given:',
113+
level
114+
);
88115
this.log(levels.INFO, `[${level}]`, ...args);
89116
} else {
90117
// apart from fallback, allow .log(...args) to be synonym with .log("INFO", ...args)
@@ -101,12 +128,28 @@ class Logger {
101128

102129
_log(level, data) {
103130
debug(`sending log data (${level}) to appenders`);
131+
let callStack;
132+
if (this.useCallStack) {
133+
try {
134+
if (data[0] instanceof Error) {
135+
callStack = this.parseCallStack(data[0], baseCallStackSkip);
136+
}
137+
} catch (_err) {
138+
// Ignore Error
139+
}
140+
callStack =
141+
callStack ||
142+
this.parseCallStack(
143+
new Error(),
144+
defaultErrorCallStackSkip + baseCallStackSkip
145+
);
146+
}
104147
const loggingEvent = new LoggingEvent(
105148
this.category,
106149
level,
107150
data,
108151
this.context,
109-
this.useCallStack && this.parseCallStack(new Error())
152+
callStack
110153
);
111154
clustering.send(loggingEvent);
112155
}
@@ -132,7 +175,7 @@ function addLevelMethods(target) {
132175
const level = levels.getLevel(target);
133176

134177
const levelStrLower = level.toString().toLowerCase();
135-
const levelMethod = levelStrLower.replace(/_([a-z])/g, g =>
178+
const levelMethod = levelStrLower.replace(/_([a-z])/g, (g) =>
136179
g[1].toUpperCase()
137180
);
138181
const isLevelMethod = levelMethod[0].toUpperCase() + levelMethod.slice(1);

0 commit comments

Comments
 (0)