Skip to content

Instantly share code, notes, and snippets.

@andreyvit
Last active May 24, 2016 14:54
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save andreyvit/00502aaee833ecc3bc49a673967ad589 to your computer and use it in GitHub Desktop.
Save andreyvit/00502aaee833ecc3bc49a673967ad589 to your computer and use it in GitHub Desktop.
Proposal for a Michigan Logging Policy

Logging Policy

What's this, and why is it needed?

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.

Log Levels

  • 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

Logging should always be enabled

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.

Prefixes vs level-based methods

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.

Logging entries need package prefixes

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”).

Logging errors

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)
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment