Correct approach to global logging in Golang

Carson picture Carson · Aug 21, 2013 · Viewed 57.4k times · Source

What's the pattern for application logging in Go? If I've got, say, 5 goroutines I need to log from, should I...

  • Create a single log.Logger and pass it around?
  • Pass around a pointer to that log.Logger?
  • Should each goroutine or function create a logger?
  • Should I create the logger as a global variable?

Answer

tux21b picture tux21b · Aug 21, 2013
  • Create a single log.Logger and pass it around?

That is possible. A log.Logger can be used concurrently from multiple goroutines.

  • Pass around a pointer to that log.Logger?

log.New returns a *Logger which is usually an indication that you should pass the object around as a pointer. Passing it as value would create a copy of the struct (i.e. a copy of the Logger) and then multiple goroutines might write to the same io.Writer concurrently. That might be a serious problem, depending on the implementation of the writer.

  • Should each goroutine or function create a logger?

I wouldn't create a separate logger for each function or goroutine. Goroutines (and functions) are used for very lightweight tasks that will not justify the maintenance of a separate logger. It's probably a good idea to create a logger for each bigger component of your project. For example, if your project uses a SMTP service for sending mails, creating a separate logger for the mail service sounds like a good idea so that you can filter and turn off the output separately.

  • Should I create the logger as a global variable?

That depends on your package. In the previous mail service example, it would be probably a good idea to have one logger for each instance of your service, so that users can log failures while using the gmail mail service differently than failures that occured while using the local MTA (e.g. sendmail).