People often pick log levels randomly, making them fairly useless. I've recently seen a very useful definition of log levels, and I liked it very much. So here we go.
-
Notice: notable events that should be aggregated and reviewed by the system administrator or development team regularly. This is a good fit for something that's normal in moderation, but may represent a problem if it starts happening too often.
-
Error: a problem that needs to be investigated and resolved. Log monitoring tools should bring this to the attention of the development team.
-
Critical: like Error, but the team (or on-call engineers) need to be paged for an immediate attention.
-
Warning: like Error, but the code isn't sure if it is a real problem or a normal condition.
-
Debug/Trace: events that may be useful when tracking down problems, but don't qualify for the Notice level, and
Another argument I saw somewhere is that most logging statements should be enabled all the time, because when a problem happens in production, it's too late to enable it.
I propose to only make exceptions for very verbose or expensive logging.
I personally dislike elaborate solutions, so I personally prefer:
log.Printf("ERROR: something failed")
to
log.Errorf("something failed")
I think that prefixes provide a complete solution to the problem, and allow components to accept any logger that implements
interface Logger {
Printf(format string, args ...interface{})
}
This interface can be satisfied even by the standard library logger. I think it's a very useful thing in fighting the logging madness.
Because all logging is always enabled, we want it to be greppable, so let's include package names into logging statements:
q.Logger.Printf("NOTICE mongoqueue recovering job: %v/%v age=%v", request.Op, request.Name, now.Sub(job.LastExecutionTime))
Another great convention to make loggers more greppable is to make sure the logging event name is static, and the dynamic details come after it, like in the example above (“mongoqueue recovering job”).
Only log those errors that are consumed. If you're returning an error, you should NOT log it, but instead make sure to add the relevant context for those who will later log it:
if err != nil {
return fmt.Errorf("mongoqueue failed to add job (%v/%v): %v", request.Op, request.Name, err)
}