gempir
gempir

Reputation: 1901

Golang packages and using variables across packages

So I'm kinda wondering what the best practice is here.

I have an application with several subpackages, some require access to the logger I have in the main package, because i use a custom logger with colors and timestamps etc.

Is the only way of accomplishing this by injecting it like so? (Assuming Handler is in a subpackage called command)

type Handler struct {
    logger logging.Logger
}

func NewHandler(logger logging.Logger) Handler {
    return Handler{
         logger: logger,
    }
} 

handler := command.NewHandler(logger)

This issue I have with this is that testing becomes annoying since I have to mock the logger for tests. I thought about just returning errors that should be logged and let the main package deal with them, but I'd like to run some function async like so

go handler.HandleMessage(msg)

So idk how to handle errors from asynchronous functions or if its even possible.

So is there a best practice to do what I want?

Upvotes: 0

Views: 815

Answers (1)

Colin Stewart
Colin Stewart

Reputation: 572

A few thoughts on this:

  1. Injecting the resource (logger) is the best way to do this in my opinion. Directly referencing a global variable is certainly possible, but makes your code hard to change.
  2. If you logging.Logger is a concrete type then you can make it work when nil, so allowing you to skip initialisation in your tests.
  3. You absolutely can handle your errors in async calls.

On this last point you can use anonymous functions to add additional error handling at the calling site:

go func() {
        err := handler.HandleMessage(msg)
        // err handling / logging here
}()

If you can pass errors up meaningfully to the calling site that initiated the call then I prefer to do this every time. You do need to bear in mind that you are still running in a separate goroutine when you come back from HandleMessage().

Upvotes: 2

Related Questions