I'm using Google Wire for dependency injection and I want 2 loggers (error and info). So I created the following provider:
type errorLogger *log.Logger
type infoLogger *log.Logger
type Logger struct {
Error errorLogger
Info infoLogger
}
func ProvideLogger() *Logger {
return &Logger{
Error: log.New(os.Stderr, "ERROR\t", log.Ldate|log.Ltime|log.Lshortfile),
Info: log.New(os.Stdout, "INFO\t", log.Ldate|log.Ltime),
}
}
In my code I am referencing the loggers as so
h.Logger.Error
However, this doesn't give me access to the logger
methods as I would assume it would (such as Println
, Fatalf
etc)
I assume I am referencing something incorrectly, just not sure what.
The new types defined as type errorLogger *log.Logger
don't inherit the methods of the underlying type.
See the Go specs, Type Declarations > Type Definitions:
A defined type may have methods associated with it. It does not inherit any methods bound to the given type, but the method set of an interface type or of elements of a composite type remains unchanged
type Mutex struct { /* Mutex fields */ } func (m *Mutex) Lock() { /* Lock implementation */ } func (m *Mutex) Unlock() { /* Unlock implementation */ } // NewMutex has the same composition as Mutex but its method set is empty. type NewMutex Mutex // The method set of PtrMutex's underlying type *Mutex remains unchanged, // but the method set of PtrMutex is empty. type PtrMutex *Mutex
It follows that Printf
and other *log.Logger
methods are not in the method set of errorLogger
and infoLogger
.
You can use composition:
type errorLogger struct {
*log.Logger
}
and then you can initialize it with:
&Logger{
Error: errorLogger{
Logger: log.New(os.Stderr, "ERROR\t", log.Ldate|log.Ltime|log.Lshortfile),
},
}