Choosing a Log Level
Like all subjective decisions in technology, which log level to use is the cause of much angry debate. Worse, different logging systems use different levels: Log4j has 6 severity levels, and Syslog has 8 severity levels. While both lists of log levels come with guidance as to which level to use when, there's still enough ambiguity to cause confusion.
When choosing a log level, it's important to know how visible you want the message to be, how big of a problem it is, and what you want the user to do about it. With that in mind, this is the decision tree I follow when choosing a log level:
- Can you continue execution after this? If no, use the
error
log level. Log4j uses theFATAL
log level for this, but I find the degree of difference between "fatal" and "error" to be too small to be useful. - Is this a problem the user needs to know about? If yes, use the
warn
log level. It's important to think about what the user needs to know. The more that falls into this category, the less the user will actually see. This is called "alert blindness": The user gets conditioned to ignore output from the machine, which can cause real problems to go unnoticed. - Does this contain technical details or data structures? If no, you
can use the
info
log level. This log level should be written for the non-technical end-user to give high-level descriptions of the current phase of execution (or, it should say, plainly and simply, what's happening right now). Theinfo
log level can provide some extra context to the errors and warnings, but it should not provide technical details only useful to a programmer. - Otherwise, use the
debug
log level. The debug log level should be the information used by the developer to diagnose and fix the problems revealed by the errors and warnings. A non-technical user should find little to no useful information at the debug level.
And that's it! I only use 4 log levels. Of the 2 remaining log4j levels,
fatal
isn't distinct enough from error
to my taste, and trace
is
meant for pedantic messages describing entering/leaving every subroutine
(which I refuse to write myself, and haven't used any tool to
auto-generate).
With these rules for which messages are logged at what level, I can easily decide what logs should be displayed.
- The
debug
level (and all higher levels) are always logged via Syslog (no matter what level is being shown on the terminal) and, from there, propagated to long-term log storage in files or databases. - The terminal gets, by default, the
warn
log level, but a user can pass in flags to change what they see. These command-line flags are easy to achieve with the Getopt::Long Perl module.-q
is "quiet" mode, and shows only theerror
log level-v
is "verbose" mode, and shows theinfo
log level-vv
is "debug" mode, and shows thedebug
log level
These rules result in very sparse program output: If a program is working perfectly, it will output nothing at all, which is a common convention in Unix programs.
What to log to the terminal by default is another point of contention:
A lot of people expect a program to be verbose about what it is doing,
and that if a program doesn't say it did what you asked it to do, you
have to double-check. I disagree, but if it becomes a problem, I just
make info
the default level (never debug
, as debug
is too much).
However your project decides to organize its logs, Log::Any can accommodate. To provide interoperability between Syslog, Log4j (Log4perl), and other logging systems, Log::Any supports all the severity levels from each system.
Remember that logging is meant to serve a variety of users, including the end-user, and you as the developer. It can be difficult to serve both, so some care needs to be taken when choosing what to display, and like all other subjective things, consistency is key.