Merge pull request #1267 from ZachHaber/master

Make Appender Type extensible from other modules and the user
This commit is contained in:
Lam Wei Li 2022-06-10 01:22:40 +08:00 committed by GitHub
commit 6a0e492b43
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 164 additions and 82 deletions

View File

@ -9,7 +9,7 @@ charset = utf-8
trim_trailing_whitespace = true
insert_final_newline = true
[*.js]
[*.{js,ts,[cm]js,[cm]ts}]
quote_type = single
curly_bracket_next_line = true
indent_brace_style = Allman

5
.gitattributes vendored
View File

@ -10,6 +10,11 @@
*.css text eol=lf
*.html text eol=lf
*.js text eol=lf
*.cjs text eol=lf
*.mjs text eol=lf
*.ts text eol=lf
*.cts text eol=lf
*.mts text eol=lf
*.json text eol=lf
*.md text eol=lf
*.sh text eol=lf

View File

@ -5,7 +5,7 @@
"homepage": "https://log4js-node.github.io/log4js-node/",
"files": [
"lib",
"types",
"types/*.d.ts",
"CHANGELOG.md",
"SECURITY.md"
],

120
types/log4js.d.ts vendored
View File

@ -1,13 +1,21 @@
// Type definitions for log4js
type Format = string | ((req: any, res: any, formatter: ((str: string) => string)) => string);
type Format =
| string
| ((req: any, res: any, formatter: (str: string) => string) => string);
export interface Log4js {
getLogger(category?: string): Logger;
configure(filename: string): Log4js;
configure(config: Configuration): Log4js;
addLayout(name: string, config: (a: any) => (logEvent: LoggingEvent) => string): void;
connectLogger(logger: Logger, options: { format?: Format; level?: string; nolog?: any; }): any; // express.Handler;
addLayout(
name: string,
config: (a: any) => (logEvent: LoggingEvent) => string
): void;
connectLogger(
logger: Logger,
options: { format?: Format; level?: string; nolog?: any }
): any; // express.Handler;
levels: Levels;
shutdown(cb: (error: Error) => void): void | null;
}
@ -17,9 +25,21 @@ export function getLogger(category?: string): Logger;
export function configure(filename: string): Log4js;
export function configure(config: Configuration): Log4js;
export function addLayout(name: string, config: (a: any) => (logEvent: LoggingEvent) => any): void;
export function addLayout(
name: string,
config: (a: any) => (logEvent: LoggingEvent) => any
): void;
export function connectLogger(logger: Logger, options: { format?: Format; level?: string; nolog?: any; statusRules?: any[], context?: boolean }): any; // express.Handler;
export function connectLogger(
logger: Logger,
options: {
format?: Format;
level?: string;
nolog?: any;
statusRules?: any[];
context?: boolean;
}
): any; // express.Handler;
export function recording(): Recording;
@ -56,9 +76,9 @@ export interface Level {
}
export interface LoggingEvent {
categoryName: string; // name of category
level: Level; // level of message
data: any[]; // objects to log
categoryName: string; // name of category
level: Level; // level of message
data: any[]; // objects to log
startTime: Date;
pid: number;
context: any;
@ -89,7 +109,13 @@ export interface CustomLayout {
type: string;
}
export type Layout = BasicLayout | ColoredLayout | MessagePassThroughLayout | DummyLayout | PatternLayout | CustomLayout;
export type Layout =
| BasicLayout
| ColoredLayout
| MessagePassThroughLayout
| DummyLayout
| PatternLayout
| CustomLayout;
/**
* Category Filter
@ -97,7 +123,7 @@ export type Layout = BasicLayout | ColoredLayout | MessagePassThroughLayout | Du
* @see https://log4js-node.github.io/log4js-node/categoryFilter.html
*/
export interface CategoryFilterAppender {
type: "categoryFilter";
type: 'categoryFilter';
// the category (or categories if you provide an array of values) that will be excluded from the appender.
exclude?: string | string[];
// the name of the appender to filter. see https://log4js-node.github.io/log4js-node/layouts.html
@ -110,7 +136,7 @@ export interface CategoryFilterAppender {
* @see https://log4js-node.github.io/log4js-node/noLogFilter.html
*/
export interface NoLogFilterAppender {
type: "noLogFilter";
type: 'noLogFilter';
// the regular expression (or the regular expressions if you provide an array of values)
// will be used for evaluating the events to pass to the appender.
// The events, which will match the regular expression, will be excluded and so not logged.
@ -265,11 +291,11 @@ export interface StandardOutputAppender {
export interface TCPAppender {
type: 'tcp';
// (defaults to 5000)
port?: number
port?: number;
// (defaults to localhost)
host?: string
host?: string;
// (defaults to __LOG4JS__)
endMsg?: string
endMsg?: string;
// (defaults to a serialized log event)
layout?: Layout;
}
@ -279,6 +305,35 @@ export interface CustomAppender {
[key: string]: any;
}
/**
* Mapping of all Appenders to allow for declaration merging
* @example
* declare module 'log4js' {
* interface Appenders {
* StorageTestAppender: {
* type: 'storageTest';
* storageMedium: 'dvd' | 'usb' | 'hdd';
* };
* }
* }
*/
export interface Appenders {
CategoryFilterAppender: CategoryFilterAppender;
ConsoleAppender: ConsoleAppender;
FileAppender: FileAppender;
SyncfileAppender: SyncfileAppender;
DateFileAppender: DateFileAppender;
LogLevelFilterAppender: LogLevelFilterAppender;
NoLogFilterAppender: NoLogFilterAppender;
MultiFileAppender: MultiFileAppender;
MultiprocessAppender: MultiprocessAppender;
RecordingAppender: RecordingAppender;
StandardErrorAppender: StandardErrorAppender;
StandardOutputAppender: StandardOutputAppender;
TCPAppender: TCPAppender;
CustomAppender: CustomAppender;
}
export interface AppenderModule {
configure: (config: Config, layouts: LayoutsParam) => AppenderFunction;
}
@ -287,7 +342,7 @@ export type AppenderFunction = (loggingEvent: LoggingEvent) => void;
// TODO: Actually add types here...
// It's supposed to be the full config element
export type Config = any
export type Config = any;
export interface LayoutsParam {
basicLayout: LayoutFunction;
@ -307,20 +362,7 @@ export interface PatternToken {
export type LayoutFunction = (loggingEvent: LoggingEvent) => string;
export type Appender = CategoryFilterAppender
| ConsoleAppender
| FileAppender
| SyncfileAppender
| DateFileAppender
| LogLevelFilterAppender
| NoLogFilterAppender
| MultiFileAppender
| MultiprocessAppender
| RecordingAppender
| StandardErrorAppender
| StandardOutputAppender
| TCPAppender
| CustomAppender;
export type Appender = Appenders[keyof Appenders];
export interface Levels {
ALL: Level;
@ -338,8 +380,14 @@ export interface Levels {
}
export interface Configuration {
appenders: { [name: string]: Appender; };
categories: { [name: string]: { appenders: string[]; level: string; enableCallStack?: boolean; } };
appenders: { [name: string]: Appender };
categories: {
[name: string]: {
appenders: string[];
level: string;
enableCallStack?: boolean;
};
};
pm2?: boolean;
pm2InstanceVar?: string;
levels?: Levels;
@ -347,11 +395,11 @@ export interface Configuration {
}
export interface Recording {
configure(loggingEvent: LoggingEvent): void
replay(): LoggingEvent[]
playback(): LoggingEvent[]
reset(): void
erase(): void
configure(loggingEvent: LoggingEvent): void;
replay(): LoggingEvent[];
playback(): LoggingEvent[];
reset(): void;
erase(): void;
}
export class Logger {

View File

@ -3,10 +3,10 @@ import * as log4js from './log4js';
log4js.configure('./filename');
const logger1 = log4js.getLogger();
logger1.level = 'debug';
logger1.debug("Some debug messages");
logger1.debug('Some debug messages');
logger1.fatal({
whatever: 'foo'
})
whatever: 'foo',
});
const logger3 = log4js.getLogger('cheese');
logger3.trace('Entering cheese testing');
@ -18,40 +18,44 @@ logger3.fatal('Cheese was breeding ground for listeria.');
log4js.configure({
appenders: { cheese: { type: 'console', filename: 'cheese.log' } },
categories: { default: { appenders: ['cheese'], level: 'error' } }
categories: { default: { appenders: ['cheese'], level: 'error' } },
});
log4js.configure({
appenders: {
out: { type: 'file', filename: 'pm2logs.log' }
out: { type: 'file', filename: 'pm2logs.log' },
},
categories: {
default: { appenders: ['out'], level: 'info' }
default: { appenders: ['out'], level: 'info' },
},
pm2: true,
pm2InstanceVar: 'INSTANCE_ID'
pm2InstanceVar: 'INSTANCE_ID',
});
log4js.addLayout('json', config => function (logEvent) {
return JSON.stringify(logEvent) + config.separator;
log4js.addLayout(
'json',
(config) =>
function (logEvent) {
return JSON.stringify(logEvent) + config.separator;
}
);
log4js.configure({
appenders: {
out: { type: 'stdout', layout: { type: 'json', separator: ',' } },
},
categories: {
default: { appenders: ['out'], level: 'info' },
},
});
log4js.configure({
appenders: {
out: { type: 'stdout', layout: { type: 'json', separator: ',' } }
file: { type: 'dateFile', filename: 'thing.log', pattern: '.mm' },
},
categories: {
default: { appenders: ['out'], level: 'info' }
}
});
log4js.configure({
appenders: {
file: { type: 'dateFile', filename: 'thing.log', pattern: '.mm' }
default: { appenders: ['file'], level: 'debug' },
},
categories: {
default: { appenders: ['file'], level: 'debug' }
}
});
const logger4 = log4js.getLogger('thing');
@ -66,13 +70,13 @@ log4js.shutdown();
log4js.configure({
appenders: {
cheeseLogs: { type: 'file', filename: 'cheese.log' },
console: { type: 'console' }
console: { type: 'console' },
},
categories: {
cheese: { appenders: ['cheeseLogs'], level: 'error' },
another: { appenders: ['console'], level: 'trace' },
default: { appenders: ['console', 'cheeseLogs'], level: 'trace' }
}
default: { appenders: ['console', 'cheeseLogs'], level: 'trace' },
},
});
const logger6 = log4js.getLogger('cheese');
@ -80,7 +84,10 @@ const logger6 = log4js.getLogger('cheese');
const otherLogger = log4js.getLogger();
// this will get coloured output on console, and appear in cheese.log
otherLogger.error('AAArgh! Something went wrong', { some: 'otherObject', useful_for: 'debug purposes' });
otherLogger.error('AAArgh! Something went wrong', {
some: 'otherObject',
useful_for: 'debug purposes',
});
otherLogger.log('This should appear as info output');
// these will not appear (logging level beneath error)
@ -101,22 +108,21 @@ anotherLogger.debug('Just checking');
const pantsLog = log4js.getLogger('pants');
pantsLog.debug('Something for pants');
import { configure, getLogger } from './log4js';
configure('./filename');
const logger2 = getLogger();
logger2.level = 'debug';
logger2.debug("Some debug messages");
logger2.debug('Some debug messages');
configure({
appenders: { cheese: { type: 'file', filename: 'cheese.log' } },
categories: { default: { appenders: ['cheese'], level: 'error' } }
categories: { default: { appenders: ['cheese'], level: 'error' } },
});
log4js.configure('./filename').getLogger();
const logger7 = log4js.getLogger();
logger7.level = 'debug';
logger7.debug("Some debug messages");
logger7.debug('Some debug messages');
const levels: log4js.Levels = log4js.levels;
const level: log4js.Level = levels.getLevel('info');
@ -124,40 +130,63 @@ const level: log4js.Level = levels.getLevel('info');
log4js.connectLogger(logger1, {
format: ':x, :y',
level: 'info',
context: true
context: true,
});
log4js.connectLogger(logger2, {
format: (req, _res, format) => format(`:remote-addr - ${req.id} - ":method :url HTTP/:http-version" :status :content-length ":referrer" ":user-agent"`)
format: (req, _res, format) =>
format(
`:remote-addr - ${req.id} - ":method :url HTTP/:http-version" :status :content-length ":referrer" ":user-agent"`
),
});
//support for passing in an appender module
log4js.configure({
appenders: { thing: { type: { configure: () => () => {} }}},
categories: { default: { appenders: ['thing'], level: 'debug'}}
appenders: { thing: { type: { configure: () => () => {} } } },
categories: { default: { appenders: ['thing'], level: 'debug' } },
});
declare module './log4js' {
interface Appenders {
StorageTestAppender: {
type: 'storageTest';
storageMedium: 'dvd' | 'usb' | 'hdd';
};
}
}
log4js.configure({
appenders: { test: { type: 'storageTest', storageMedium: 'dvd' } },
categories: { default: { appenders: ['test'], level: 'debug' } },
});
log4js.configure({
appenders: { rec: { type: 'recording' } },
categories: { default: { appenders: ['rec'], 'level': 'debug' } }
categories: { default: { appenders: ['rec'], level: 'debug' } },
});
const logger8 = log4js.getLogger();
logger8.level = 'debug'
logger8.debug('This will go to the recording!')
logger8.debug('Another one')
const recording = log4js.recording()
const loggingEvents = recording.playback()
logger8.level = 'debug';
logger8.debug('This will go to the recording!');
logger8.debug('Another one');
const recording = log4js.recording();
const loggingEvents = recording.playback();
if (loggingEvents.length !== 2) {
throw new Error(`Expected 2 recorded events, got ${loggingEvents.length}`)
throw new Error(`Expected 2 recorded events, got ${loggingEvents.length}`);
}
if (loggingEvents[0].data[0] !== 'This will go to the recording!') {
throw new Error(`Expected message 'This will go to the recording!', got ${loggingEvents[0].data[0]}`)
throw new Error(
`Expected message 'This will go to the recording!', got ${loggingEvents[0].data[0]}`
);
}
if (loggingEvents[1].data[0] !== 'Another one') {
throw new Error(`Expected message 'Another one', got ${loggingEvents[1].data[0]}`)
throw new Error(
`Expected message 'Another one', got ${loggingEvents[1].data[0]}`
);
}
recording.reset()
const loggingEventsPostReset = recording.playback()
recording.reset();
const loggingEventsPostReset = recording.playback();
if (loggingEventsPostReset.length !== 0) {
throw new Error(`Expected 0 recorded events after reset, got ${loggingEventsPostReset.length}`)
throw new Error(
`Expected 0 recorded events after reset, got ${loggingEventsPostReset.length}`
);
}