From e2640f234b94a7bbb6dde11a25317afd1b8a2f59 Mon Sep 17 00:00:00 2001 From: Zachary Haber Date: Thu, 9 Jun 2022 11:21:17 -0500 Subject: [PATCH 1/3] feat(types): Make Appender type extensible via Appenders --- types/log4js.d.ts | 122 ++++++++++++++++++++++++++++++++-------------- types/test.ts | 109 ++++++++++++++++++++++++++--------------- 2 files changed, 154 insertions(+), 77 deletions(-) diff --git a/types/log4js.d.ts b/types/log4js.d.ts index a0a8b6f6..5f4f76f5 100644 --- a/types/log4js.d.ts +++ b/types/log4js.d.ts @@ -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 connectLogger(logger: Logger, options: { format?: Format; level?: string; nolog?: any; statusRules?: any[], context?: boolean }): any; // express.Handler; +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 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 { diff --git a/types/test.ts b/types/test.ts index b7bb8f3e..ad6ae4af 100644 --- a/types/test.ts +++ b/types/test.ts @@ -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: ',' } } + out: { type: 'stdout', layout: { type: 'json', separator: ',' } }, }, categories: { - default: { appenders: ['out'], level: 'info' } - } + default: { appenders: ['out'], level: 'info' }, + }, }); log4js.configure({ appenders: { - file: { type: 'dateFile', filename: 'thing.log', pattern: '.mm' } + file: { type: 'dateFile', filename: 'thing.log', pattern: '.mm' }, }, categories: { - default: { appenders: ['file'], level: 'debug' } - } + 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}` + ); } From 3eee2e1280b20a23564c49f7f4af8fa28251c35a Mon Sep 17 00:00:00 2001 From: Zachary Haber Date: Thu, 9 Jun 2022 11:22:21 -0500 Subject: [PATCH 2/3] chore(format): make all js/ts files and variants prettier properly --- .editorconfig | 2 +- .gitattributes | 5 +++++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/.editorconfig b/.editorconfig index 3361fd10..0835e8ee 100644 --- a/.editorconfig +++ b/.editorconfig @@ -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 diff --git a/.gitattributes b/.gitattributes index 70d5e00f..5322b173 100644 --- a/.gitattributes +++ b/.gitattributes @@ -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 From 6ba2b0c6cc77a2a0f7780461b6f55ccda5b7c9be Mon Sep 17 00:00:00 2001 From: Zachary Haber Date: Thu, 9 Jun 2022 11:30:40 -0500 Subject: [PATCH 3/3] chore: don't publish the test.ts file --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 294477d2..89a96960 100644 --- a/package.json +++ b/package.json @@ -5,7 +5,7 @@ "homepage": "https://log4js-node.github.io/log4js-node/", "files": [ "lib", - "types", + "types/*.d.ts", "CHANGELOG.md", "SECURITY.md" ],