npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

memoir

v2.0.6

Published

Memoir is a type-checked asynchronous logging facility with a simple and familiar interface.

Downloads

18

Readme

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 memoir

Concepts

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.Level[level]

  • level <string>
    • BASE <string>
    • DEBUG <string>
    • INFO <string>
    • WARN <string>
    • ERROR <string>

memoir.Metadata

  • name <string> The name of the Logger.
  • level <string> The level of the log message represented as a string.
  • func <string> The name of the function where the Logger method was called.
  • url <string> The file URL for the module where the Logger method was called.
  • line <string> The line number where the Logger method was called.
  • col <string> The column number where the Logger method 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> Optional Level that indicates which methods the Logger will implement for logging. Default: Level.BASE

levelLogger.setLevel(level)

  • level <memoir.Level> A Level that indicates which methods the Logger will implement for logging.

levelLogger.addHandler(handler)

  • handler <memoir.MetadataHandler> A Memoir Handler that supports a Metadata argument.

The LevelLogger implementation is unique in that it may be assigned a Level in its constructor or a Level may be set using its setLevel method. The LevelLogger will configure its interface according to the log Level. JavaScript's optional chaining operator can be used in order to only log messages that meet the specified Level constraint. This strategy is aimed at improving performance.

memoir.MetadataHandler<MessageT, FormatT>()

  • Extends: <memoir.Handler> handler.setFormatter(formatter: Formatter)
  • formatter <memoir.formatter> A memoir Formatter.

memoir.MetadataFormatter<MessageT, FormatT>(formatter)

  • Extends: <memoir.Formatter>
  • formatter <(message: MessageT, meta: Metadata) => FormatT> A function that will return the formatted message of type FormatT.

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: 1e6
    • encoding <BufferEncoding> Default: utf8
    • mode <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.