Skip to content

Audience configurable logger for JavaScript/TypeScript libraries

License

Notifications You must be signed in to change notification settings

colelawrence/librarylog

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

7 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

librarylog

A logging library for libraries.

Features

âś” Multiple levels based on audience. Public, Developers, Internal

âś” Colorful browser logs

âś” CommonJS

âś” ES Modules

âś” TypeScript

Usage

We can create loggers which are essentially nested from their parent.

import { createLibraryLoggerProvider } from "librarylog";

// create logger provider
const provider = createLibraryLoggerProvider();

// root logger
const logger = provider.getLogger()

// create nested loggers
const appLogger = logger.named("App")

// create nested loggers with a name and a key
const pageLogger = appLogger.named("Page", page.id)

We can log for a variety of audiences.

import { createLibraryLoggerProvider } from "librarylog";

// create logger provider
const provider = createLibraryLoggerProvider();

// root logger
const logger = provider.getLogger()

// create nested loggers
const appLogger = logger.named("App")

// create nested loggers with a name and a key
const pageLogger = appLogger.named("Page", page.id)

See the breadth of logger functions with example messages. All log functions accept one message and one optional arguments object.

// internal log functions
appLogger._error("We've experienced a general problem")
appLogger._hmm("This doesn't look right")
appLogger._todo("I'm not finished")
appLogger._kapow("Lookie here! I guess we do execute this code")
appLogger._warn("I'm not finished")
appLogger._debug("Opening page", { pageId: "..." })
appLogger._trace("User mouse clicked", { mouseEvent: "..." })

// developer log functions
appLogger.errorDev("Data passed in was malformed")
appLogger.warnDev("Challenge with loading exports sourcemaps. Ensure you're compiling with esm: true")
appLogger.debugDev("Page loaded", { pageId: "...", duration: "...", objects: 120 })
appLogger.traceDev("Loading page's external object", { pageId: "...", objectId: "..." })

// public log functions
appLogger.errorPublic("Something that just cannot go unnoticed!")
appLogger.warnPublic("Something so so important!")

Lazy logging

All log functions also come with a .lazy.<logfn>(message, () => args) version.

// execute the inner function only if the log is included in logging
appLogger.lazy.debugDev("Page loaded", () => ({ pageId: "...", pageMeta: calculatePageMeta() }))

Downgrading

In many places in your code such as in utility functions, you don't know which audience the logs are for. So, in this case, you can use .downgrade.<audience>() to produce a IUtilLogger (which is also nameable).

It looks like the following:

export interface IUtilLogger {
  /** Usually equivalent to `console.error`. */
  error(message: string, args?: LibraryLoggable): void;
  /** Usually equivalent to `console.warn`. */
  warn(message: string, args?: LibraryLoggable): void;
  /** Usually equivalent to `console.info`. */
  debug(message: string, args?: LibraryLoggable): void;
  /** Usually equivalent to `console.debug`. */
  trace(message: string, args?: LibraryLoggable): void;
  named(name: string, key?: string): IUtilLogger;
}

For example,

// now, any logs that `cssRenderHelpers` wants to surface, will go through
// the `internal` audience.
const cssLogger = appLogger.downgrade.internal()
cssRenderHelpers.convertBezier(cssLogger, "...")

Configurable with a TypeScript API

Configure what gets logged

import { createLibraryLoggerProvider } from "librarylog";

// create logger provider
const provider = createLibraryLoggerProvider();

// set custom logging behaviors (filtering and such)
provider.configureFiltering({
  // disable style to the console (if the logger does not support style, this won't have an effect)
  consoleStyle: false,
  // include logs made for the dev audience
  dev: true,
  // include logs made for the internal audience
  internal: true,

  // configure the behavior of inclusion based on source of the logs
  include(source) {
    if (source.names.find(n => n.name === "XYZSystem")) {
      // include internal logs for XYZSystem children
      return {
        internal: true
      }
    }

    if (source.names.find(n => n.name === "Rendering")) {
      // suppress all logs under the "Rendering" tree
      return {
        internal: false,
        dev: false,
        min: Infinity,
      }
    }

    if (source.names.find(n => n.name === "Page" && n.key === "page_ajkwhloieuw8990se")) {
      // enable all logs for page "page_ajkwhloieuw8990se"
      // this source would have been constructed via something like `parentLogger.named("Page", page.id)`
      return {
        internal: true,
        min: 0,
      }
    }
  },
});

Configure how it gets logged

import { createLibraryLoggerProvider, LibraryLoggerLevel } from "librarylog";

// create logger provider
const logger = createLibraryLoggerProvider();

// set a custom console
logger.configureConsole({
  type: "console",
  console: console,
  // disable colorful styling
  style: false,
});

// disable console styling, and set default console
logger.configureConsole({
  type: "console",
  style: false,
});

// set your own keyed logger
logger.configureConsole({
  type: "keyed",
  keyed(nameAndKeys) {
    const prefix = nameAndKeys
      .map((a) => (a.key ? `${a.name}#${a.key}` : a.name))
      .join(" ");
    return {
      error(meta, message, args) {
        console.error(
          meta.audience,
          meta.category,
          LibraryLoggerLevel[meta.level],
          prefix,
          message,
          ...(args ? [args] : [])
        );
      },
      warn(meta, message, args) {
        console.warn(
          meta.audience,
          meta.category,
          LibraryLoggerLevel[meta.level],
          prefix,
          message,
          ...(args ? [args] : [])
        );
      },
      debug(meta, message, args) {
        console.info(
          meta.audience,
          meta.category,
          LibraryLoggerLevel[meta.level],
          prefix,
          message,
          ...(args ? [args] : [])
        );
      },
      trace(meta, message, args) {
        console.debug(
          meta.audience,
          meta.category,
          LibraryLoggerLevel[meta.level],
          prefix,
          message,
          ...(args ? [args] : [])
        );
      },
    };
  },
});

License

This project is licensed under the terms of the MIT license.

About

Audience configurable logger for JavaScript/TypeScript libraries

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published