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)
Thanks, all. Events are okay I guess. I still want a one-line well-known "trick" to come about which becomes idiomatic. There is massive power to tell downstream users:
Firstly, it's one line of code and it's mnemonic. Also, seriously: I refuse to depend on a log framework anymore. I hate them! I hate them! I hate them! When people invite me to a dinner party I do not insist on bringing my friend Joe, even though Joe is a great guy.
@balupton, thank you very much for your feedback. Your sidenotes are great and I bookmarked the RFC but they aren't directly related to my logging problem. The problem is bloat! The problem is XKCD standards! There is a power vacuum.
That is why I want to tell my users, "Look, I am basically doing
console.log()
. Do you knowconsole.log()
? Great. Myconsole
object is all noops by default. You can swap it out out forglobal.console
or whatever else you want. Just stick to the API that Netscape invented in the 90s and we'll be okay."@isaacs Emitting events is okay, but what if my package does
module.exports = function() { /* whatever */ }
? I fear each developer will invent their own technique, for no net gain. Some packages export an EventEmitter so they are fine. Others export an object full of functions. Others have aconfig()
ordefaults()
function (request and nano do this). Some packages are object factories, with each new object emitting its own log events. Maybe I am just despairing too quickly.