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

async-node-logger

v1.2.0

Published

The Logger Util to log inside of async operations.

Downloads

21

Readme

AsyncNodeLogger

The Logger Util to log inside of async operations.

Why?

Have you ever wished that you can have a logger that is unique inside of a callback or promise chain? Ever wanted to be able segment portions of your logs based on asynchronous operations? Well with this library you can! AsyncNodeLogger allows you to define a logger per async operations and will look up which logger to use based on context. It barely even feels like you are using anything different!

Installation

npm i node-logger-async

Usage

Basic usage

This usage is the most basic of all usages. If you use this library like this, this is equivalent of using console.

import { AsyncLogger } from "async-node-logger";

const logger = new AsyncLogger();
logger.info("This is a message from a test"); // Same as calling console.info.

Slightly more complicated example

This example shows you how to set up a logger to add context inside of a callback chain. This logger will generate a random ID when ever runWithNewContext is called and make the message be formatted with that id in the message.

import { AsyncLogger } from "async-node-logger";

const logger = new AsyncLogger(console, (logger: Console) => {
  const id = Math.floor(Math.random() * 1000); // assume random returns 1
  return {
    info: (...args: any[]) => logger.info(`[ID- ${id}]:`, ...args),
    log: (...args: any[]) => logger.log(`[ID- ${id}]:`, ...args),
    warn: (...args: any[]) => logger.warn(`[ID- ${id}]:`, ...args),
    error: (...args: any[]) => logger.error(`[ID- ${id}]:`, ...args),
    debug: (...args: any[]) => logger.debug(`[ID- ${id}]:`, ...args),
    trace: (...args: any[]) => logger.trace(`[ID- ${id}]:`, ...args),
  }
});
logger.info("This is a message from a test"); // outputs "This is a message from a test"
const callDB = async () => logger.info('calling db'); // outputs "[ID- 1] calling db"
const doSomethingAsync = async () => {
  logger.info('do something async'); // outputs "[ID- 1] do something async"
  await callDB();
}
logger.runWithNewContext(doSomethingAsync);
logger.info("done"); //outputs "Done"; 

Usage with other loggers

You don't have to use console. You can use something like bunyan (my personal favorite logging library), in order to perform logging for you. This allows you to use more rich loggers and really customize what you log.

import { AsyncLogger } from "async-node-logger";
import bunyan from "bunyan";

const bunyanLogger = bunyan.createLogger({
  name: "myapp",
});

const logger = new AsyncLogger(bunyanLogger, (logger: bunyan) => {
  const id = Math.floor(Math.random() * 1000); // assume random returns 1
  return logger.child({
    id,
  });
});
logger.info("This is a message from a test"); // uses main bunyanLogger; 
const callDB = async () => logger.info('calling db'); // uses child bunyan logger
const doSomethingAsync = async () => {
  logger.info('do something async'); // uses child bunyan logger 
  await callDB();
}
logger.runWithNewContext(doSomethingAsync);
logger.info("done"); // uses main bunyanLogger; 

Documentation

Logger

Logger is an interface that defines the methods that loggers use to write to loggers. It defines the info, warn, error, debug, trace, and log methods.

export interface Logger {
 debug(...data: any[]): void;
 debug(message?: any, ...optionalParams: any[]): void;
 debug(message?: any, ...optionalParams: any[]): void;

 error(...data: any[]): void;
 error(message?: any, ...optionalParams: any[]): void;
 error(message?: any, ...optionalParams: any[]): void;

 info(...data: any[]): void;
 info(message?: any, ...optionalParams: any[]): void;
 info(message?: any, ...optionalParams: any[]): void;

 log(...data: any[]): void;
 log(message?: any, ...optionalParams: any[]): void;
 log(message?: any, ...optionalParams: any[]): void;

 trace(...data: any[]): void;
 trace(message?: any, ...optionalParams: any[]): void;
 trace(message?: any, ...optionalParams: any[]): void;


 warn(...data: any[]): void;
 warn(message?: any, ...optionalParams: any[]): void;
 warn(message?: any, ...optionalParams: any[]): void;
}

LoggerMiddleware<LoggerType extends Logger>

This defines a function that takes a logger, and then returns a logger. This logger can either be the same as the logger that was passed in, or a different logger. You can use this to define a way to hydrate context when a new logger is created.

AsyncLogger<LoggerType extends Logger>

The AsyncLogger is a facade that manages the context for async logging. It passes calls to the logging methods to the chosen logger. The LoggerType is any type that satisfies the Logger Interface.

constructor(logger: LoggerType, middleware: LoggerMiddleware<LoggerType>)

Creates the AsyncLogger. The logger is the logger to use for actually performing the logging. The middleware is called right before a new async context is created.

public onSpawn(spawner: LoggerMiddleware<LoggerType>)

Adds a new middleware to the pipeline when a new logger is created for an async context.

runWithNewContext(cb: () => unknown, once?: LoggerMiddleWare<LoggerType>)

Runs the callback with a new context that has a logger bound to it. You can use the once parameter to run this middleware only for this single context.

Express middleware

We have an easy to use middleware for express. You can use this middleware to spawn new contexts for you and to add some identifying information about the request ID. For example a request ID, a user ID, or the request path.

import { AsyncLogger, createMiddleware } from "async-node-logger";
import bunyan from "bunyan";
import express from "express";

const bunyanLogger = bunyan.createLogger({
  name: "myapp",
});

const logger = new AsyncLogger(bunyanLogger);

const app = express();
app.use(createMiddleware(logger, (logger, request: express.Request) => {
  const requestID = generateUniqueID();
  return logger.child({
    requestID,
    path: request.originalUrl,
  });
}));

app.get("/hello-world", (_, resp) => {
  logger.info("I am here") // This will have a unique ID, and the original request path for the request
});

app.listen(3000, () => {
  logger.info("listening on port 3000"); // Will be top level code
})

Type Definition: <LoggerType extends Logger>( logger: AsyncLogger<LoggerType>, requestHydrator?: RequestHydrator<LoggerType> => RequestHandler;