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

@paperdave/logger

v3.0.1

Published

Versitle logging with spinners and progress bars.

Downloads

282

Readme

@paperdave/logger

This is the logger I use in my programs. It unifies ideas from many other console io packages into one coherent interface.

  • Customizable log levels
    • Built in: info, warn, debug, error, success, trace
    • Custom log names with the same automatic color system the debug package uses.
  • Injecting the global console object to force all logs to be formatted consistantly.
  • Widgets: dynamic, animatable, and interactive things that stick to the bottom of your log:
    • Spinners (replaces ora)
    • Progress Bars (replaces cli-progress)
    • Text/Selector Input (replaces prompt)
  • Pretty error formatting, just pass an error object to any log function.
    • Colorized and simplified stack traces.
    • Easy interface to add long descriptions onto errors the end user may see.
  • Rexports chalk and ansi-escapes for easy usage in commonjs modules.
  • Bun and Node.js support. Technically works in browser, but limited features and it's a huge bundle (13kb node, 51kb browser).

Basic Examples

import Logger from '@paperdave/logger';

Logger.info('Hello World');
Logger.warn('This is a warning');
Logger.debug('This is a debug message'); // Hidden by default

Logger.error('Program did not succeed!');
Logger.success('Program Succeeded!');

Logger.trace('This will print the current stack');
import { info, warn } from '@paperdave/logger';

info('Built-in log presets are exposed as separate functions too.');
warn('This is a warning');

Custom Log Levels

import Logger from '@paperdave/logger';

const http = new Logger('http');
const db = new Logger('db');

http('Request incoming');
db('Dropping all tables');
http('Request complete');

These function similar to the debug package, but are visible by default. Visibility can be customized with the DEBUG environment variable, or by passing the debug: true in the second argument.

The rest of the Logger options are as follows:

const debug = new Logger(name, {
  id: name, // Used for `DEBUG` environment variable filtering
  color: undefined, // Custom color, see jsdoc for how this works.
  coloredText: false,
  boldText: false,
  error: false, // Print to STDERR
  debug: false, // If true, will be hidden by default
});

Injecting console.log and other functions.

In Purplet, we inject @paperdave/logger into the console object. This allows the users' logs to appear nicely formatted. By default this also listens for uncaught errors and will close the program if an error is thrown; this is default behavior in modern Node.

import { injectLogger } from '@paperdave/logger';
injectLogger();

console.log('This will be formatted!');
console.error('This will be formatted too!');

You can pass parameters to the injector to customize how it behaves.

Surprisingly, you may find that @paperdave/logger runs faster than Node.js's console.log function in some cases ;)

Spinners and Progress Bars

The Spinner and ProgressBar bar classes instantly start rendering when constructed, and have various methods to update their state and resolve them.

import { Spinner } from '@paperdave/logger';
import { delay } from '@paperdave/utils';

const spinner = new Spinner('Loading...');
await delay(1000);
spinner.update('Still Loading...');
await delay(1000);
spinner.success('Done!');

It may be more useful to put your logic in an async function and use the withSpinner helper:

import { withSpinner } from '@paperdave/logger';

await withSpinner({
  text: 'Doing this very cool operation.',
  successText: 'Operation done.',
}, async(spinner) => {
  await doSomething();
  spinner.update('part one done');
  await doSomethingElse();
});

Progress bars have the same general API as spinners, but some other properties.

Custom errors with PrintableError and CLIError

A PrintableError is an error that defines some extra fields. @paperdave/logger handles these objects within logs which allows customizing their appearance. It can be useful when building CLIs to throw formatted error objects that instruct the user what they did wrong, without printing a huge piece of text with a useless stack trace.

// as defined in @paperdave/logger
export interface PrintableError extends Error {
  description: string;
  hideStack?: boolean;
  hideName?: boolean;
}

For ease of use, we provide the simple CLIError class which implements this interface. A real world example taken from Purplet is how we handle a missing Discord Token:

throw new CLIError(
  'Missing DISCORD_BOT_TOKEN environment variable!',
  dedent`
    Please create an ${chalk.cyan('.env')} file with the following contents:

    ${chalk.cyanBright('DISCORD_BOT_TOKEN')}=${chalk.grey('<your bot token>')}

    You can create or reset your bot token at ${devPortalLink}
  `
);

In combination with injectLogger, throwing a CLI error is all that is needed to print a pretty error message to the user and exit the program.

Custom Widgets

LogWidget is a base class for widgets. A widget is responsible for providing a format(now) -> string function, where now is the value of performance.now(), and then an fps constant which is set to 15 by default.

In addition to that, the (protected) api contains

  • remove - remove the widget from the log
  • redraw - forces a redraw
  • LogWidget.batchRedraw(fn) - pass a fn and perform multiple log operations in a single batch, useful to optimize log + remove() calls.