-
-
Save alfasin/ddd5b559658751af35f765a7a690f777 to your computer and use it in GitHub Desktop.
const winston = require('winston'); | |
const { format } = winston; | |
const { combine, colorize, timestamp, printf } = format; | |
/** | |
* /** | |
* Use CallSite to extract filename and number, for more info read: https://v8.dev/docs/stack-trace-api#customizing-stack-traces | |
* @param numberOfLinesToFetch - optional, when we want more than one line back from the stacktrace | |
* @returns {string|null} filename and line number separated by a colon, if numberOfLinesToFetch > 1 we'll return a string | |
* that represents multiple CallSites (representing the latest calls in the stacktrace) | |
* | |
*/ | |
const getFileNameAndLineNumber = function getFileNameAndLineNumber (numberOfLinesToFetch = 1) { | |
const oldStackTrace = Error.prepareStackTrace; | |
const boilerplateLines = line => line && | |
line.getFileName() && | |
// in the following line you may want to "play" with adding a '/' as a prefix/postfix to your module name | |
(line.getFileName().indexOf('<The Name of This Module>') && | |
(line.getFileName().indexOf('/node_modules/') < 0)); | |
try { | |
// eslint-disable-next-line handle-callback-err | |
Error.prepareStackTrace = (err, structuredStackTrace) => structuredStackTrace; | |
Error.captureStackTrace(this); | |
// we need to "peel" the first CallSites (frames) in order to get to the caller we're looking for | |
// in our case we're removing frames that come from logger module or from winston | |
const callSites = this.stack.filter(boilerplateLines); | |
if (callSites.length === 0) { | |
// bail gracefully: even though we shouldn't get here, we don't want to crash for a log print! | |
return null; | |
} | |
const results = []; | |
for (let i = 0; i < numberOfLinesToFetch; i++) { | |
const callSite = callSites[i]; | |
let fileName = callSite.getFileName(); | |
// BASE_DIR_NAME is the path to the project root folder | |
const BASE_DIR_NAME = require('path').resolve('.'); | |
fileName = fileName.includes(BASE_DIR_NAME) ? fileName.substring(BASE_DIR_NAME.length + 1) : fileName; | |
results.push(fileName + ':' + callSite.getLineNumber()); | |
} | |
return results.join('\n'); | |
} finally { | |
Error.prepareStackTrace = oldStackTrace; | |
} | |
}; | |
function humanReadableFormatter ({ level, message, ...metadata }) { | |
const filename = getFileNameAndLineNumber(); | |
return `[${level}] [${filename}] ${message} ${JSON.stringify(metadata)}`; | |
} | |
const logger = winston.createLogger({ | |
transports: [ | |
new winston.transports.Console({ | |
level: 'info', | |
handleExceptions: true, | |
humanReadableUnhandledException: true, | |
json: false, | |
colorize: { all: true }, | |
stderrLevels: ['error', 'alert', 'critical', 'bizAlert'], | |
format: combine( | |
colorize(), | |
timestamp(), | |
humanReadableFormatter, | |
), | |
}) | |
] | |
}); | |
logger.info('test print', { a: 1, b: 2 }); | |
What's BASE_DIR_NAME?
it's the root of the project
please change BASE_DIR_NAME to require('path').resolve('.')
Copy and pasted exact code. Got Error:
/usr/src/app/node_modules/logform/combine.js:37
throw new Error([
^
Error: No transform function found on format. Did you create a format instance?
const myFormat = format(formatFn);
const instance = myFormat();
at isValidFormat (/usr/src/app/node_modules/logform/combine.js:37:11)
at Array.every (<anonymous>)
at cascade (/usr/src/app/node_modules/logform/combine.js:13:16)
at module.exports (/usr/src/app/node_modules/logform/combine.js:55:33)
at Object.<anonymous> (/usr/src/app/src/utils/logger.js:58:15)
at Module._compile (node:internal/modules/cjs/loader:1155:14)
at Object.Module._extensions..js (node:internal/modules/cjs/loader:1209:10)
at Module.load (node:internal/modules/cjs/loader:1033:32)
at Function.Module._load (node:internal/modules/cjs/loader:868:12)
at Module.require (node:internal/modules/cjs/loader:1057:19)
@lucasrahn09 this is coming from winston, maybe something changed but according to their documents it looks like this code is still using the correct way to set a format to a transport. See: https://github.com/winstonjs/winston#common-transport-options
@sudhiryadav good idea thanks!
done!
@alfasin Had the same issue as @ljrahn , the following fixed it for me:
- humanReadableFormatter,
+ winston.format.printf(humanReadableFormatter),
but apparently this breaks the stack, maximum that I'm getting (after disabling filtering) is
[�[32minfo�[39m] [logger2.cjs:26
logger2.cjs:50
node_modules/logform/printf.js:11
node_modules/logform/combine.js:20
node_modules/winston-transport/index.js:91
node_modules/winston-transport/node_modules/readable-stream/lib/_stream_writable.js:389
node_modules/winston-transport/node_modules/readable-stream/lib/_stream_writable.js:380
node_modules/winston-transport/node_modules/readable-stream/lib/_stream_writable.js:301
node_modules/readable-stream/lib/_stream_readable.js:619
node:events:513] test print {"a":1,"b":2,"timestamp":"2023-03-06T17:17:45.404Z"}
so the closest line is the callSite is line 50, far from 72
BTW, downgrading to winston 3.0.0 didn't help with the error, so it is probably something with the build system configuration...
What's BASE_DIR_NAME?