scribbly v1.0.0
scribbly

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 --saveSimple 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 browserimport 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 n1Adjusting 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 loggerimport 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 logmessage- main message, can be a string or any other typeextras- 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 clientconst log = scribbly.use(namespace('n1')).use(consoleStreamer)
log.info('test')Output:
[n1] testTo 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 logmessage- Any type, main content of the logextras- 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
}9 years ago
9 years ago
9 years ago
9 years ago
9 years ago