I have the following setup
type Foo struct {
a int
}
func NewFoo(a int) *Foo {
return &Foo{a: a}
}
type Bar struct {
foo *Foo
b bool
}
func NewBar(a int, b bool) *Bar {
return &Bar{foo: NewFoo(a), b: b}
}
Basically, Foo
is the low-level interface to a service and Bar
provides a high-level interface on top of it.
Currently, both Foo
and Bar
are logging using a global logger, which makes it easy to configure it for both of them. However, I want to give users the option to specify their own logger. In any case, it should be the same logger for both types.
I’ve tried a couple of things, but most of them did not feel right. My best solution is the following:
var globalLogger := Logger{}
type Foo struct {
a int
logger Logger
}
func NewFoo(a int) *Foo {
return NewFooWithLogger(a, globalLogger)
}
func NewFooWithLogger(a int, logger Logger) *Foo {
return &Foo{a: a, logger: logger}
}
type Bar struct {
foo *Foo
b bool
logger Logger
}
func NewBar(a int, b bool) *Bar {
return NewBarWithLogger(a, b, globalLogger)
}
func NewBarWithLogger(a int, b bool, logger Logger) *Bar {
return &Bar{foo: NewFooWithLogger(a, logger), b, logger: logger}
}
The reason for the two extra functions is that setting the logger is not the regular use case, hence I don’t want to force regular users to do anything about it.
I’m relatively new to go. Does my approach pass the smell test for more experienced people?