I write Node.js libraries, and I want logging. Why is this so problematic?
Note, I am despairing about how library authors log stuff not how application builders decide on a logging framework.
Hopefully this document can become a spec or feature list for code I will write some day.
I maintain package foo
and I depend on log4js. Bob maintains package bar
and depends on winston. Charlie maintains package baz
and depends on minilog.
My downstream user writes an application which depends on foo
, baz
, and bar
plus npmlog.
This is crazy. The result, in the best case is a tedious application. How can the developer activate debug logging across the board? It's bedlam! In practice Bob, Charlie, and I get many bug reports about something which should be invisible yet ubiquitious, like air.
My half feature list / half whining list:
- I must not depend on some package
- The whole anti-pattern is too many logging cooks. I am deeply skeptical that another package will help.
- I want a technique or a custom, not a package. At least not yet.
- I want to document how I work and my user can hook me into their own logger. That's fine for now.
- I want the
console.*
API.info()
,.warn()
and.error()
. That's fine.- This includes
util.format()
support. I love Winston's structured logs bututil.format()
is more compatible with the world.
- I want to be silent by default. Principle of least surprise.
- It should be pretty easy for my user to get at my logs.
- Maybe I emit a
"console"
event and my user can replace my.info()
,.warn()
, etc. functions? - Maybe I have a
.console()
function and my user just runsfoo.console(console);
to get my output on the screen
- Maybe I emit a
Perhaps in the future, but not yet
- Command-line or environment variables to trivially enable/disable my log visibility, severity cut-off, etc.
- The well-known concept of a log "namespace". My user can hook into
"networking"
logs but ignore"caching"
logs. - Optimized execution in the case where a log message will go nowhere
- Some good solution to the missing
console.debug()
. From bitter experience, I now insist on being 100%console.*
compatible. But there is no debugging level! I will probably just use.trace()
and die a little bit inside. - Be easy to hook into me into logging frameworks (Winston, log4js, npmlog, whatever else)
I'm with @isaacs on this one. Having your objects emit log events works real handy, with then the application allowing filtering of the log levels to display.
For instance in DocPad we use Caterpillar for our logging. We utilise several objects and other libraries that emit log events, and DocPad will bubble those events up the chain to the DocPad object. DocPad is configured to tell its caterpillar instance what log levels to show.
Sidenote, there is actually an RFC which standardizes the log levels - http://www.faqs.org/rfcs/rfc3164.html - we use it for caterpillar. If there is to be a standard format for log events, we should follow that RFC.
Sidenote 2, caterpillar expects log events to be in the format of
logLevel?, args...
(that beinglogLevel
is optional, and following args are one or many). This format would also have to be standardized to avoid pain.So the ability to bubble log events up the chain, and tell applications that would normally output log events with a log library to hold off, seems the way to go. However, that doesn't help with avoiding the numerous log libraries being installed in the first place, not sure if that can be fixed... or even if that is a problem...