memoir v2.0.6
Memoir
Memoir is a type-checked asynchronous logging facility with a simple and familiar interface.
Memoir provides a framework for building custom Logger, Handler, and Formatter implementations. Memoir also provides prebuilt implementations that can be used for everyday logging, such as Memoir's performance oriented LevelLogger.
Table of Contents
Install
npm install memoirConcepts
Memoir implements concepts that are familiar in the logging domain i.e., Levels, Loggers, Handlers, and Formatters. In addition to these familiar concepts, Memoir features a Metadata object that contains relevant information about the logged message (e.g., the log Level, originating function name, etc.). It may be passed to Formatters that support it.
The following concepts are a subset of Memoir classes that are of practical use. These concepts are used in the provided Examples.
memoir.Levellevel
- level
<string>BASE<string>DEBUG<string>INFO<string>WARN<string>ERROR<string>
memoir.Metadata
name<string>The name of theLogger.level<string>The level of the log message represented as a string.func<string>The name of the function where theLoggermethod was called.url<string>The file URL for the module where theLoggermethod was called.line<string>The line number where theLoggermethod was called.col<string>The column number where theLoggermethod was called.
The Metadata object may be passed to a Formatter that supports it.
memoir.LevelLogger<MessageT, FormatT>(options)
- Extends:
<memoir.MetadataLogger> - options
<LoggerOptions & LevelLoggerOptions>name<string>Optional string that names the Logger.level<memoir.Level>OptionalLevelthat indicates which methods theLoggerwill implement for logging. Default:Level.BASE
levelLogger.setLevel(level)
level<memoir.Level>ALevelthat indicates which methods theLoggerwill implement for logging.
levelLogger.addHandler(handler)
handler<memoir.MetadataHandler>A MemoirHandlerthat supports aMetadataargument.
The LevelLogger implementation is unique in that it may be assigned a
Levelin its constructor or aLevelmay be set using itssetLevelmethod. TheLevelLoggerwill configure its interface according to the logLevel. JavaScript's optional chaining operator can be used in order to only log messages that meet the specifiedLevelconstraint. This strategy is aimed at improving performance.
memoir.MetadataHandler<MessageT, FormatT>()
- Extends:
<memoir.Handler>handler.setFormatter(formatter: Formatter) formatter<memoir.formatter>A memoirFormatter.
memoir.MetadataFormatter<MessageT, FormatT>(formatter)
- Extends:
<memoir.Formatter> formatter<(message: MessageT, meta: Metadata) => FormatT>A function that will return the formatted message of typeFormatT.
memoir.RotatingFileHandler(options)
- options
<FileHandlerOptions>path<string>rotations<0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10>Optional number of rotations.bytes<number>The size of the log file in MB. Default:1e6encoding<BufferEncoding>Default:utf8mode<number>Default:0o666
Performant Logging
Memoir provides a performant Logger class named LevelLogger that implements a dynamic logging interface. LevelLogger may implement any of the common logging methods: base, debug, info, warn, and error. The LevelLogger dynamically configures its interface to only implement the methods that are relevant for the specified logging Level that is passed to its constructor or set using its setLevel method. This approach allows the programmer to take advantage of JavaScript's optional chaining operator in order to eliminate unnecessary calls to the Logger and its Handlers.
Practically, this strategy ensures that frequent calls to LevelLogger.debug are not evaluated unless the LevelLogger has been expressly configured to the DEBUG Level.
TypeScript will enforce the usage of the optional chaining operator when calling LevelLogger's methods. Please see the examples for how to use the LevelLogger interface.
Examples
ConsoleHandler Logger
In this simple example you will create a LevelLogger. The LevelLogger's Handler will be set to log at the DEBUG Level; however, the LevelLogger level will be set to INFO, which will log INFO, WARN, and ERROR messages. This ensures that frequent calls throughout the codebase to log.debug will never be evaluated. This is achieved by using JavaScript's optional chaining operator.
Code
const formatter = (message: string, { name, level, func, url, line, col }: Metadata): string =>
`${name}:${level}:${new Date().toISOString()}:${func}:${line}:${col}:${message}`;
const log = new LevelLogger<string, string>({ name: 'Console Handler Example 1', level: Level.INFO }); // Create an instance of a Logger.
const consoleHandler = new ConsoleHandler<string, string>(); // Create an instance of a Handler.
const metadataFormatter = new MetadataFormatter<string, string>({ formatter }); // Create an instance of a Formatter.
consoleHandler.setLevel(Level.DEBUG); // Set the Level of the Handler.
consoleHandler.setFormatter(metadataFormatter); // Set the Formatter on the Handler.
log.addHandler(consoleHandler); // Add the Handler to the Logger.
log.debug?.("Because the LevelLogger's `level` property is set to Level.INFO, this method is never called.");
log.info?.('Hello World.'); // Log a Hello World to the console.
(function test() { log.info?.('Hello World.'); }());
log.setLevel(Level.DEBUG);
log.debug?.("The LevelLogger's `level` property has been set to Level.DEBUG; hence, the method is called.");Output
Console Handler Example 1:INFO:2023-09-15T20:05:10.621Z:undefined:11:11:Hello World.
Console Handler Example 1:INFO:2023-09-15T20:05:10.631Z:test:12:30:Hello World.
Console Handler Example 1:DEBUG:2023-09-15T20:05:10.632Z:undefined:14:12:The LevelLogger's `level` property has been set to Level.DEBUG; hence, the method is called.RotatingFileHandler Logger
Code
const formatter = (message: string, { name, level, func, url, line, col }: Metadata): string =>
`${name}:${level}:${new Date().toISOString()}:${func}:${line}:${col}:${message}`;
const log = new LevelLogger<string, string>({ name: 'Rotating File Handler Example' }); // Create an instance of a Logger.
const fileHandler = new RotatingFileHandler({ path: './test.log', rotations: 5 }); // Create an instance of a Handler.
const metadataFormatter = new MetadataFormatter<string, string>({ formatter }); // Create an instance of a Formatter.
fileHandler.setLevel(Level.DEBUG); // Set the Level of the Handler.
fileHandler.setFormatter(metadataFormatter); // Set the Formatter on the Handler.
log.addHandler(fileHandler); // Add the Handler to the Logger.
log.info?.('Hello World.'); // Log a Hello World to the console.
(function test() { log.info?.('Hello World.'); }());Output
Rotating File Handler Example:INFO:2023-09-15T20:03:45.657Z:undefined:10:11:Hello World.
Rotating File Handler Example:INFO:2023-09-15T20:03:45.657Z:test:11:30:Hello World.How To
How to build a type-checked custom Memoir Handler.
Please see the examples in ./src/console_handler.ts and ./src/rotating_file_handler.ts for practical examples that demonstrate how to subclass the base classes in order to build a custom Memoir Handler.
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
11 years ago
11 years ago
11 years ago
12 years ago
12 years ago