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

log-n-roll

v0.2.0

Published

Tiny 1kb logger with slim api and ability of limitless extension

Downloads

4

Readme

log-n-roll

Tiny 1kb logger with slim api and ability of limitless extension.

NPM versionBuild Status

  • Tiny: weighs less than kilobyte gzipped
  • Pluggable: one built-in plugin for pretty formatting and limitless possibilities for extension

Note

This packege is Proof-of-Concept and should be considered as an unstable. Nevertheless, the basic idea has already been proved. Release coming soon.

Install

This project uses node and npm. Go check them out if you don't have them locally installed.

$ npm install log-n-roll

Then with a module bundler like rollup or webpack, use as you would anything else:

// using ES6 modules
import log from 'log-n-roll';

// using CommonJS modules
var log = require('log-n-roll');

The UMD build is also available on unpkg:

<script src="https://unpkg.com/log-n-roll/dist/log-n-roll.umd.js"></script>

You can find the library on window.log.

Usage

const log = require('log-n-roll');

log.trace('Trace shows stacktrace');

// Using the built-in plugin
log.use(log.prefixer);
log.trace('Using any number of plugins adds to the stacktrace only one extra line');

log.info("By default, the level of the default logger is 'trace'. All messages are displayed");

// Loading the processor
let two = 2;
for (let i = 0; i < 1000000; i++) {
  two *= two;
  two = Math.sqrt(two);
}

log.debug('Debug shows the time difference from the last call of any logger method');
log.info('Placeholders are supported. Two = %s', two);
log.warn('Warn message');
log.error('Error message');

// Getting the named logger and setting its level to 'warn'
const child = log('child', 'warn');
child.info('Messages below the level of the logger are ignored');

child.level = 'info';
child.info('The level of the logger can be changed at any time');

child().info(
  'Root logger can be obtained from any logger: child() %s== log() %s== log',
  child() === log() ? '=' : '!',
  log() === log ? '=' : '!',
);

child('any').info(
  'Any logger can be obtained from any logger: child("any") %s== log("any")',
  child('any') === log('any') ? '=' : '!',
);

log('any').debug('Any logger has extended the level from the default logger');
child('any').info('Any logger has extended the plugins props from the default logger');

Output:

Trace: Trace shows stacktrace
    at Object.<anonymous> (C:\Users\u36\Dropbox\kutuluk\log-n-roll\examples\basic.js:3:5)
    ...
Trace: 17:08:01 [TRACE] default : Using any number of plugins adds to the stacktrace only one extra line
    at Function.trace (C:\Users\u36\Dropbox\kutuluk\log-n-roll\dist\log-n-roll.js:1:730)
    at Object.<anonymous> (C:\Users\u36\Dropbox\kutuluk\log-n-roll\examples\basic.js:7:5)
    ...
17:08:01 [ INFO] default : By default, the level of the default logger is 'trace'. All messages are displayed
   +44ms [DEBUG] default : Debug shows the time difference from the last call of any logger method
17:08:01 [ INFO] default : Placeholders are supported. Two = 2
17:08:01 [ WARN] default : Warn message
17:08:01 [ERROR] default : Error message
17:08:01 [ INFO]   child : The level of the logger can be changed at any time
17:08:01 [ INFO] default : Root logger can be obtained from any logger: child() === log() === log
17:08:01 [ INFO]     any : Any logger can be obtained from any logger: child("any") === log("any")
    +0ms [DEBUG]     any : Any logger has extended the level from the default logger
17:08:01 [ INFO]     any : Any logger has extended the plugins props from the default logger

Plugins

The resulted examples of plugins are simplified. Despite the fact that they are workable, it is not recommended to use in production.

log-stacktrace.js

function getStackTrace() {
  try {
    throw new Error();
  } catch (trace) {
    return trace.stack;
  }
}

module.exports = (logger, props) => {
  // Return noop plugin if stacktrace support is absent
  if (!getStackTrace()) {
    return () => {};
  }

  props = Object.assign(
    {
      levels: ['trace', 'warn', 'error'],
      depth: 3,
    },
    props,
  );

  return (state) => {
    if (!props.levels.some(level => level === state.label)) {
      return;
    }

    let stacktrace = getStackTrace();

    const lines = stacktrace.split('\n');
    lines.splice(0, 4);
    const { depth } = props;
    if (depth && lines.length !== depth + 1) {
      const shrink = lines.splice(0, depth);
      stacktrace = shrink.join('\n');
      if (lines.length) stacktrace += `\n    and ${lines.length} more`;
    } else {
      stacktrace = lines.join('\n');
    }

    state.stacktrace = stacktrace;
  };
};

log-meta.js

module.exports = (logger, props) => (state) => {
  const meta = Object.assign({}, props);

  const { args } = state;

  if (args.length && typeof args[0] === 'object') {
    Object.assign(meta, args.shift());
  }

  state.meta = meta;
};

log-message.js

const { format } = require('util');

module.exports = () => (state) => {
  state.message = format(...state.args);
};

log-json.js

module.exports = (logger, props) => (state) => {
  const json = {};

  const fields = Object.keys(props);
  fields.forEach((name) => {
    json[name] = typeof props[name] === 'function'
      ? props[name](state)
      : state[props[name]] || state[name];
  });

  state.json = JSON.stringify(json, null, '\t');
};

to-file.js

const fs = require('fs');

module.exports = (logger, props) => {
  props = Object.assign(
    {
      file: 'app.log',
      fields: ['message', 'stacktrace'],
      separator: '\n',
      eol: '\n',
      roll: true,
    },
    props,
  );

  return (state) => {
    const fields = props.fields.map(field => state[field]).filter(field => field);

    fs.appendFileSync(props.file, fields.join(props.separator) + props.eol);

    state.roll = props.roll;
  };
};

###An example of using these plugins

plugins.js

const log = require('../dist/log-n-roll');

const stacktrace = require('../examples/plugins/log-stacktrace');
const meta = require('../examples/plugins/log-meta');
const message = require('../examples/plugins/log-message');
const json = require('../examples/plugins/log-json');

const toFile = require('../examples/plugins/to-file');

log.use(stacktrace).use(meta, { source: 'plagins.js' }).use(log.prefixer).use(message)
  .use(json, {
    message: 'message',
    timestamp: state => new Date(state.timestamp).toISOString(),
    level: 'label',
    logger: 'logger',
    meta: 'meta',
    stacktrace: state => (state.stacktrace ? state.stacktrace.split('\n') : []),
  });

log.info({ tag: 'message1' }, 'Hello, %s', 'console!');

log.use(toFile, { file: 'my.log' });

log.info({ tag: 'message2' }, 'Hello, %s', 'file!');

const child = log('child')
  .use(toFile, {
    fields: ['json'],
    eol: ',\n',
    roll: false,
  })
  .use(meta, { format: 'json' })
  .unuse(log.prefixer);

child.trace({ tag: 'message3' }, 'Goodbye, %s', 'console!');

Console output:

17:06:19 [ INFO] default : Hello, console!
17:06:19 [ INFO] default : Hello, file!

my.log:

17:06:19 [ INFO] default : Hello, file!
{
	"message": "Goodbye, console!",
	"timestamp": "2018-02-07T13:06:19.333Z",
	"level": "trace",
	"logger": "child",
	"meta": {
		"source": "plagins.js",
		"format": "json",
		"tag": "message3"
	},
	"stacktrace": [
		"    at Object.<anonymous> (C:\\Users\\u36\\Dropbox\\kutuluk\\log-n-roll\\examples\\plugins.js:35:7)",
		"    at Module._compile (module.js:635:30)",
		"    at Object.Module._extensions..js (module.js:646:10)",
		"    and 4 more"
	]
},