Skip to content

Commit

Permalink
0.1.0. Initial working commit.
Browse files Browse the repository at this point in the history
  • Loading branch information
balupton committed Sep 6, 2011
0 parents commit f9f9bcc
Show file tree
Hide file tree
Showing 4 changed files with 394 additions and 0 deletions.
73 changes: 73 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
# Caterpillar

Caterpillar is an awesome, simple console logging framework for [Node.js](http://nodejs.org/). It supports grouping of messages, filtering log levels, colors, times, modules, custom formatters and custom transports.


## Example

<img src=""/>

``` coffeescript
# Requires
catepillar = require "#{__dirname}/../lib/caterpillar.coffee"

# Create
logger = new catepillar.Logger
transports:
level: 7
formatter:
module: module

# Logs
for own name,code of logger.config.levels
logger.log name, "this is #{name}"

# Standard
logger.log 'this is awesome'

# Grouping
logger.config.autoFlush = false
logger.log ''
logger.log 'one'
logger.log 'two'
logger.log 'three'
setTimeout(
-> logger.flush()
3000
)
```


# Install

1. [Install Node.js](https://github.com/balupton/node/wiki/Installing-Node.js)

1. Install [CoffeeScript](http://jashkenas.github.com/coffee-script/)

npm -g install coffee-script

1. Install DocPad

npm install caterpillar



## Thanks

Uses the following:

- [RFC3164](http://www.faqs.org/rfcs/rfc3164.html) for the level codes and names
- [Mariusz Nowak](https://github.com/medikoo)'s [CLI-Color](https://github.com/medikoo/cli-color)

Inspired by the following:

- [Alexander Dorofeev](https://github.com/akaspin)'s [AIN](https://github.com/akaspin/ain)
- [TJ Holowaychuk](https://github.com/visionmedia)'s [Log.js](https://github.com/visionmedia/log.js)
- [Igor Urminček](https://github.com/igo)'s [NLogger](https://github.com/igo/nlogger)
- [SchizoDuckie](https://github.com/SchizoDuckie)'s [Node-CLI](https://github.com/SchizoDuckie/Node-CLI/)


## License

Licensed under the [MIT License](http://creativecommons.org/licenses/MIT/)
Copyright 2011 [Benjamin Arthur Lupton](http://balupton.com)
27 changes: 27 additions & 0 deletions examples/console.coffee
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
# Requires
catepillar = require "#{__dirname}/../lib/caterpillar.coffee"

# Create
logger = new catepillar.Logger
transports:
level: 7
formatter:
module: module

# Logs
for own name,code of logger.config.levels
logger.log name, "this is #{name}"

# Standard
logger.log 'this is awesome'

# Grouping
logger.config.autoFlush = false
logger.log ''
logger.log 'one'
logger.log 'two'
logger.log 'three'
setTimeout(
-> logger.flush()
3000
)
236 changes: 236 additions & 0 deletions lib/caterpillar.coffee
Original file line number Diff line number Diff line change
@@ -0,0 +1,236 @@
# Requires
colors = require 'cli-color'
util = require 'util'

# Formatter
Formatter = class
config:
module: null # (object or null) the node.js global `module`
colors:
0: 'red'
1: 'red'
2: 'red'
3: 'red'
4: 'yellow'
5: 'yellow'
6: 'green'
7: 'green'

constructor: (config) ->
# Apply config
config or= {}
config[key] ?= value for own key,value of @config
@config = config

padLeft: (padding,size,msg) ->
padding = String(padding)
msg = String(msg)
if msg.length < size
for i in [0...size-msg.length]
msg = padding+msg
msg

padRight: (padding,size,msg) ->
padding = String(padding)
msg = String(msg)
if msg.length < size
for i in [0...size-msg.length]
msg += padding
msg

details: (levelCode, levelName, args) ->
date = @getDate()
className = @getClassName()
line = @getLine()
color = @getColor(levelCode)

parts = []
for value, index in args
parts[index] =
if typeof value is 'string'
value
else
util.inspect value, false, 10
message = parts.join ' '

{date,className,line,color,levelName,message}

format: (levelCode,levelName,args) ->
{date,className,line,levelName,message} = @details levelCode, levelName, args
message = "[#{date}] [#{className}: #{line}] "+@padLeft(' ', 10, "#{levelName}:")+" #{message}"

getColor: (levelCode) ->
color =
if @config.colors
@config.colors[levelCode]
else
false

getDate: ->
now = new Date()
year = now.getFullYear()
month = @padLeft '0', 2, now.getMonth() + 1
date = @padLeft '0', 2, now.getDate()
hours = @padLeft '0', 2, now.getHours()
minutes = @padLeft '0', 2, now.getMinutes()
seconds = @padLeft '0', 2, now.getSeconds()
ms = @padLeft '0', 3, now.getMilliseconds()
"#{year}-#{month}-#{date} #{hours}:#{minutes}:#{seconds}.#{ms}"

getLine: ->
try
throw new Error()
catch e
line = e.stack.split('\n')[3].split(':')[1]
return line

getClassName: (module) ->
module or= @config.module
if module
if module.id
if module.id == '.'
'main'
else
module.id
else
module
else
'unknown'

# Console Formatter
ConsoleFormatter = class extends Formatter
format: (levelCode,levelName,args) ->
{date,className,line,color,levelName,message} = @details levelCode, levelName, args
if !message
message
else
color = color and colors[color] or (str) -> str
message = "[#{date}] [#{className}: #{line}] "+color(@padLeft ' ', 10, "#{levelName}:")+" #{message}"

# Logger
Logger = class

config:
autoFlush: true # (true or false) whether or not to auto flush after each message
transports: null # (Transport, object, array or false)
levels:
emergency: 0
alert: 1
critical: 2
error: 3
warning: 4
notice: 5
info: 6
debug: 7

emerg: 0
crit: 2
err: 3
warn: 4
note: 5

default: 6

messages: []
formatter: null
transports: []

constructor: (config) ->
# Apply config
config or= {}
config[key] ?= value for own key,value of @config

# Apply levels
levels = {}
levels[key] ?= value for own key,value of config.levels
config.levels = levels

# Apply transports
unless config.transports
config.transports = new ConsoleTransport
unless config.transports instanceof Array
config.transports = [config.transports]
for transport in config.transports
if transport instanceof Transport
@transports.push transport
else if transport
@transports.push new ConsoleTransport transport
delete config.transports

# Apply config
@config = config

getLevelCode: (name) ->
@config.levels[name] ? null

getLevelName: (code) ->
for own key,value of @config.levels
if value is code
return key
null

log: (level, args...) ->
if typeof level is 'number'
levelCode = level
levelName = @getLevelName levelCode
else
levelName = level
levelCode = @getLevelCode levelName
levelName = @getLevelName levelCode
unless levelCode?
levelCode = @getLevelCode 'default'
levelName = @getLevelName levelCode
args.unshift(level)

if @config.autoFlush
@write levelCode,levelName,args
else
@messages.push {levelCode,levelName,args}

flush: ->
for {levelCode,levelName,args} in @messages
@write levelCode,levelName,args

write: (levelCode,levelName,args) ->
for transport in @transports
transport.write levelCode,levelName,args

# Transport
Transport = class
config:
level: 7
formatter: null # (Formatter, object or false)

constructor: (config) ->
# Apply config
config or= {}
config[key] ?= value for own key,value of @config

# Apply formater
if config.formatter instanceof Formatter
@formatter = config.formatter
else
@formatter = new ConsoleFormatter config.formatter
delete config.formatter

# Apply config
@config = config

care: (levelCode) ->
levelCode <= @config.level

write: (levelCode,levelName,message) ->
if @care levelCode
message = @formatter.format levelCode,levelName,message
else
null

# Console Transport
ConsoleTransport = class extends Transport
write: (levelCode,levelName,message) ->
message = super levelCode,levelName,message
if message?
console.log message

# Export
module.exports = {colors,Formatter,Logger,Transport,ConsoleTransport}
Loading

0 comments on commit f9f9bcc

Please sign in to comment.