simple-node-logger
simple-node-logger copied to clipboard
Example of how to override/extend FileAppender
I lack documentation on how (or maybe even a possibility) to override/extend concrete appenders. This is my workaround for creating a logger with FileAppender
that knows how to handle cause
property of an Error
. Code is in TypeScript. Maybe this will help someone or can be added as a part of documentation.
import OS from "os";
import util from "util";
import SimpleNodeLogger from "simple-node-logger";
private createLogger(logFilePath: string, level: SimpleNodeLogger.STANDARD_LEVELS, category: string): SimpleNodeLogger.Logger {
const manager = new SimpleNodeLogger();
const fileAppenderOptions: SimpleNodeLogger.IFileAppenderOptions = { logFilePath, level };
const fileAppender = new SimpleNodeLogger.appenders.FileAppender(fileAppenderOptions);
this.overrideObjectFormatter(fileAppender, fileAppenderOptions);
manager.addAppender(fileAppender);
return manager.createLogger(category, level);
}
private overrideObjectFormatter(fileAppender: SimpleNodeLogger.appenders.FileAppender, options: SimpleNodeLogger.IFileAppenderOptions) {
// These are mostly original SimpleNodeLogger implementations with enhanced error formatting
Object.defineProperty(fileAppender, `formatEntry`, {
value(this: SimpleNodeLogger.AbstractAppender, entry: SimpleNodeLogger.IEntry): string[] {
const fields: string[] = [];
if (entry.domain)
fields.push(entry.domain);
fields.push(fileAppender.formatTimestamp(entry.ts));
fields.push(fileAppender.formatLevel(entry.level));
if (entry.category)
fields.push(entry.category);
fields.push(fileAppender.formatMessage(entry.msg, fileAppender));
return fields;
},
writable: true,
configurable: true,
});
const getErrorParts = (error: Error, prettyPrint?: boolean) => {
const values: string[] = [];
values.push(error.message);
values.push((prettyPrint) ? JSON.stringify(error, null, 2) : JSON.stringify(error));
if (error.stack)
values.push(error.stack);
if (error.cause) {
values.push(`--- Caused by: ---`);
values.push(...getErrorParts(error.cause));
}
return values;
};
Object.defineProperty(fileAppender, `formatObject`, {
value(this: SimpleNodeLogger.appenders.FileAppender, value: any): string {
if (!value)
return ``;
if (typeof value === `object`) {
try {
if (value instanceof Error)
return getErrorParts(value).join(OS.EOL);
return (options.prettyPrint) ? JSON.stringify(value, null, 2) : JSON.stringify(value);
}
catch (ignore) {
return `json error: ${value.toString()}`;
}
}
else {
const s = value.toString();
if (s === `[object Object]`)
return util.inspect(value);
return s;
}
},
writable: true,
configurable: true,
});
}