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

consolo

v0.1.0

Published

A progressive enhancement of Node's console into a logger that is not at all scruffy-looking.

Downloads

3

Readme

Consolo

A "progressive enhancement" of Node's console into a logger that is not at all scruffy-looking.

Overview

Consolo (pronounced—and this is absolutely critical to note—to rhyme with everyone's favorite carbonite-encased "scoundrel") is a light-weight library that offers "progressive enhancement" atop Node's console object, allowing you to connect it to a more featureful logger solution. Consolo is also, very notably, not at all scruffy-looking.

⚠️ Warning

Look. I'm going to be honest with you: if you keep reading, you're gonna run into a raft of contrived Star Wars references, OK?

For those unfamiliar with "progressive enhancement", it's essentially a technique of implementing functionality in a manner that starts with something very basic and dresses it up when the runtime environment is confirmed to offer some specific capabilities. In the case of Consolo, it simply means that the library overrides the console object's logging methods, allowing calls to those methods to be fulfilled by more robust logging libraries.

The upshot is that calling console.log('debug', 'some text') will send the text some text to the configured logger (which, one imagines, is configured to output at some appropriate level, presumably with a timestamp prefix, and perhaps other formatting options), as a debug level message.

This can be especially useful to library package authors, as it allows them to avoid forcing any particular logging dependencies upon dependent codebases. In fact, thanks to Consolo's "progressive enhancement"-style implementation, your library's logging statements will even work perfectly in apps that use no logging library, at all!

Usage

"OK," I hear you muttering, "show me some code, already." Let's have a look at an example that that routes console messages to the widely-used winston logger.

First, install consolo and the winston adaptor to your project:

npm install --save consolo consolo-adaptor-winston winston

Next, create lib.js, app-no-consolo.js, and app-consolo.js files, as follows:

// lib.js ================================
module.exports = {
  doSomething: () => {
    console.log('warn', 'a warning message');
    console.log('debug', 'some debug message');
    console.error('this works, too!');
  }
};

// app-no-consolo.js =====================
const lib = require('./lib');

lib.doSomething();

// app-consolo.js ========================
const { enhanceConsole } = require('consolo');
const WinstonAdaptor = require('consolo-adaptor-winston');
const winston = require('winston');

const lib = require('./lib');

// configure your logger
winston.configure({
  level: 'warn',
  transports: [
    new winston.transports.File('./my-output.log')
  ]
});

// use an instance of the adaptor to enhance the console object
enhanceConsole(new WinstonAdaptor(winston));

lib.doSomething();

Now, let's execute app-no-consolo.js and app-consolo.js and review their output:

$ node app-no-cosolo.js
warn a warning message
debug some debug message
this works, too!

$ node app-consolo.js
# no output, because of the winston transport config
$ cat my-output.log
warn: a warning message
error: this works, too!

Note first and foremost that the console methods called in lib.js function perfectly from within an app that doesn't use Consolo (in this case, the app-no-consolo.js script. This is where the "progressive enhancement" implementation direction really shines for the library author—code intended for use with a Consolo-capable application works perfectly well with any out-of-the-box Node app.

When apps do elect to use Consolo, however, those console method calls start getting "dressed up". Note, for example, the absence of output from the app-consolo.js script, because we configured winston to log to the my-output.log file. Additionally, note the misisng debug level message, which didn't make it to the logger output because we configured winston to ignore any messages lower that the warn level.

And yes, you may have guessed it: custom adaptors can be written to support additional logging solutions—even proprietary ones. We'll get to that in a bit.

Library Authors

When you're writing a library, you'll want to keep the following things in mind:

  • All calls to console.log() should start with a level string as a first argument.
  • Do not include a level string as a first argument when using console.warn(), console.info(), etc., as the level is automatically implied.
  • If you're using ESLint, make sure the no-console rule is disabled (at least for the server-side code).
  • You may optionally want to consider adding consolo as a peer dependency to indicate to dependent projects that your library supports it, but that's entirely up to you.

Application Authors

It's at the app level that you'll want to add consolo (along with whatever adaptor is needed to support the logging library you intend to use) as a dependency.

To repeat the earlier example demonstrating winston logging, simply install:

npm install --save consolo consolo-adaptor-winston winston

And add the following lines to your application's initialization script:

const { enhanceConsole } = require('consolo');
const WinstonAdaptor = require('consolo-adaptor-winston');
const winston = require('winston');

winston.configure({
  // configure winston
});

enhanceConsole(new WinstonAdaptor(winston));

And Owen's your uncle.

Adaptor Authors

Creating an adaptor is rather straight-forward! Honest. Have a look:

import { BaseAdaptor } from 'consolo';

export default class MyAdaptor extends BaseAdaptor {
  constructor(someLogger) {
    super();
    this.logger = logger;
  }

  isLogLevel(level) {
    // our hypothetical logger conveniently exposes its levels
    return  this.logger
      .getLevelNamesAsArray()
      .includes(level);
  }

  log(level, ...messages) {
    this.logger.log(level, ...messages);
  }
}

JavaScript doesn't support interfaces, which is mildly unfortunate, so I've decided to offer a BaseAdaptor class and made it so that Consolo applies validation to adaptor instances it's asked to use. (Note that the BaseAdaptor is optional, but gives you a basic—and unit-tested—#enhanceConsole() method implementation to work with.)

At the end of the day, an adaptor instance must include the following methods:

  • enhanceConsole([object] target): this method decorates target with the overridden console object methods. I know, you're wondering why its necessary to explicitly pass console as an argument, given it's a global flippin' object. In short, it's got to do with testability.
  • isLogLevel([string] level): answers whether the string in question is one of the configured logging levels.
  • log([string] level, ...): sends a log message with the specified level to an instance of whatever logger it supports.

It should be painless to implement an adaptor for whatever logger you like. And, if you'd like to implement an adaptor for a community-maintained logger that isn't yet available (and you'd like to share your adaptor with the community), please check out the contribution guidelines!

API

Coming soon.

Project Info

This is part of the Consolo monorepo, hosted on Github. Learn all you like aobut the project, its MIT licensing, and more there.