1.0.0 • Published 7 years ago

scribbly v1.0.0

Weekly downloads
5
License
MIT
Repository
github
Last release
7 years ago

scribbly node version Build Status npm version

Scribbly is a simple isomorphic logging tool which is based on the middleware system. Management and construction of middlewares are very similar to the ones in expressjs. This allows broad flexibility and it keeps api simple.

Quick start

Installation:

npm install scribbly --save

Simple logging to the console

import scribbly from 'scribbly'
import { consoleStreamer } from 'scribbly/middlewares'

const log = scribbly.use(consoleStreamer)

log.debug('Hello')
log.info('Hello')
log.warning('Hello')
log.error('Hello')
log.critical('Hello')

Using namespaces

export DEBUG=n1,n3 # or window.DEBUG=n1,n3 in the browser
import scribbly from 'scribbly'
import { consoleStreamer, namespace } from 'scribbly/middlewares'

const n1 = scribbly
  .use(namespace('n1'))
  .use(consoleStreamer)
  
const n2 = scribbly
  .use(namespace('n2'))
  .use(consoleStreamer)

n1.info('Hello from n1')
n2.info('Hello from n2')

Only log from n1 namespace will be emitted because we enabled specific namespaces in DEBUG global which are n1 and n3.

Output:

[n1] Hello from n1

Adjusting logging strategy

It's common to log production errors to error reporting services like Rollbar but for development log them to console. We can easily apply different middlewares on different conditions to make that possible.

logger.js

import scribbly from 'scribbly'
import rollbar from 'rollbar-browser'
import { consoleStreamer, externalLogger } from 'scribbly/middleware'

let logger

if (process.env.NODE_ENV === 'production') {
  let rollbarLogger = rollbar.init(someConfig)
  logger = scribbly.use(externalLogger(rollbarLogger))
} else {
  logger = scribbly.use(consoleStreamer)
}

export default logger
import log from './logger'

log.error('Some error')

Keep in mind that without any middleware scribbly actually won't do anything and without streaming middleware like consoleStreamer logs won't be emitted or written.

Middlewares

For each logging, scribbly goes through a chain of middlewares in the same order how they were defined by use method. Middlewares are just pure functions which can modify the message (formatter), emit it to the console/file (streamer) or prevent it from further emission to the rest of the chain (filter). Having that said they can actually do anything, they are just functions.

Construction

const log = scribbly.use((next, level, message, extras) => {
  
  next(level, message, extras)
})
  • next - {Function} calls the next middleware from the chain. If not called it breaks the chain.
  • level - {Number} level of the log
  • message - main message, can be a string or any other type
  • extras - optional extra data, can be any type

Immutability

Every time when use method is called it returns a new logger object with freshly defined middleware and the middlewares from the previous logger. This have nice implications when in one module you can store the main logger, import it to other modules and add new middlewares there if needed without any modifications to the original logger.

Order

We can distinguish 3 types of middleware: filter, formatter and streamer. Order in which those are applied is very important. If streamer will be added earlier than filter or formatter it means that those 2 will have no effect on the log emission through the streamer. Unless it is intended it is a good practice to add streamers as the last ones to the middlewares chain.

Predefined middlewares

import { ... } from 'scribbly/middlewares'

consoleStreamer

Emit log to the output using console.log, console.warn or console.error depend on log level.

scribbly.use(consoleStreamer)

enableWhen(isOn)

Passes logs only when isOn is true. Useful when we want to disable/enable logs to a certain condition. Should be applied as first.

scribbly.use(enableWhen(process.env.DEBUG))

externalLogger(logger)

Logs to a given logger. It is expected that external logger should provide methods: debug, info, warning, error, critical. If it doesn't it should be wrapped around that kind of interface before.

scribbly.use(externalLogger(rollbarBrowserLogger))

fileStreamer(fs, filePath)

Only for node. Logs to a given file. If file does not exist it creates it.

import fs from 'fs'

scribbly.use(fileStreamer(fs, './logs.txt'))

levelFilter(minLevel)

Passes only logs which are equal or higher than given level.

import scribbly from 'scribbly'
import { levels } from 'scribbly/core'

scribbly.use(levelFilter(levels.ERROR))

namespace(name, format = '{name} ')

Passes logs only if given namespace is found within DEBUG global. DEBUG global should be a string which represents list of namespaces seperated by comma. Wildcards are respected. The middleware also adds namespace name to the log message as a prefix.

It works in a isomorphic nature and it uses different DEBUG global on different environments (browser/node):

export DEBUG=n1,n2:sub:* // in the terminal when node (access through process.env.DEBUG)
window.DEBUG=n1,n2:sub:* // in the browser when client
const log = scribbly.use(namespace('n1')).use(consoleStreamer)
log.info('test')

Output:

[n1] test

To pass logs from all namespaces:

DEBUG=*

timeFormatter

It adds time information to the message.

scribbly.use(timeFormatter)

Api

Logger

import { Logger } from 'scribbly/core'

Main class of the scribbly logger. Instance of it can by imported by import scribbly from 'scribbly'. It's the same as const scribbly = new Logger().

constructor(middlewares = [])

Creates logger and set an Array of middlewares.

middlewares

Property. Array of middlewares. Can't be modified, it's frozen.

use(middleware)

Returns a new logger with combined old middlewares and the new one.

return new Logger(this.middlewares.concat(middleware))

log(level, message, extras)

Emit the message with extras through middlewares, in order.

  • level - {Number} level of the log
  • message - Any type, main content of the log
  • extras - Any type, optional data

debug(message, extras)

Same as log(levels.DEBUG, message, extras).

info(message, extras)

Same as log(levels.INFO, message, extras).

warning(message, extras)

Same as log(levels.WARNING, message, extras).

error(message, extras)

Same as log(levels.ERROR, message, extras).

critical(message, extras)

Same as log(levels.CRITICAL, message, extras).

levels

import { levels } from 'scribbly/core'

Stores a set of constants which stores numerical representation of logging levels.

export const levels = {
  DEBUG: 10,
  INFO: 20,
  WARNING: 30,
  ERROR: 40,
  CRITICAL: 50
}
1.0.0

7 years ago

1.0.0-beta.4

8 years ago

1.0.0-beta.3

8 years ago

1.0.0-beta.2

8 years ago

1.0.0-beta.1

8 years ago