logger: support forking of outlets

refs #10
This commit is contained in:
Christian Schwarz 2017-12-23 00:55:02 +01:00
parent 583a63a68f
commit 261d095108
3 changed files with 53 additions and 16 deletions

View File

@ -13,7 +13,7 @@ import (
)
type LoggingConfig struct {
Outlets logger.Outlets
Outlets *logger.Outlets
}
type MetadataFlags int64

View File

@ -5,6 +5,7 @@ import (
"encoding/json"
"fmt"
"github.com/pkg/errors"
"sync"
"time"
)
@ -78,30 +79,52 @@ type Outlet interface {
WriteEntry(ctx context.Context, entry Entry) error
}
type Outlets map[Level][]Outlet
func NewOutlets() Outlets {
return make(map[Level][]Outlet, len(AllLevels))
type Outlets struct {
mtx sync.RWMutex
outs map[Level][]Outlet
}
func (os Outlets) Add(outlet Outlet, minLevel Level) {
for _, l := range AllLevels[minLevel:] {
os[l] = append(os[l], outlet)
func NewOutlets() *Outlets {
return &Outlets{
mtx: sync.RWMutex{},
outs: make(map[Level][]Outlet, len(AllLevels)),
}
}
func (os Outlets) Get(level Level) []Outlet {
return os[level]
func (os *Outlets) DeepCopy() (copy *Outlets) {
copy = NewOutlets()
for level := range os.outs {
for i := range os.outs[level] {
copy.outs[level] = append(copy.outs[level], os.outs[level][i])
}
}
return copy
}
func (os *Outlets) Add(outlet Outlet, minLevel Level) {
os.mtx.Lock()
defer os.mtx.Unlock()
for _, l := range AllLevels[minLevel:] {
os.outs[l] = append(os.outs[l], outlet)
}
}
func (os *Outlets) Get(level Level) []Outlet {
os.mtx.RLock()
defer os.mtx.RUnlock()
return os.outs[level]
}
// Return the first outlet added to this Outlets list using Add()
// with minLevel <= Error.
// If no such outlet is in this Outlets list, a discarding outlet is returned.
func (os Outlets) GetLoggerErrorOutlet() Outlet {
if len(os[Error]) < 1 {
func (os *Outlets) GetLoggerErrorOutlet() Outlet {
os.mtx.RLock()
defer os.mtx.RUnlock()
if len(os.outs[Error]) < 1 {
return nullOutlet{}
}
return os[Error][0]
return os.outs[Error][0]
}
type nullOutlet struct{}

View File

@ -17,13 +17,13 @@ const DefaultUserFieldCapacity = 5
type Logger struct {
fields Fields
outlets Outlets
outlets *Outlets
outletTimeout time.Duration
mtx *sync.Mutex
}
func NewLogger(outlets Outlets, outletTimeout time.Duration) *Logger {
func NewLogger(outlets *Outlets, outletTimeout time.Duration) *Logger {
return &Logger{
make(Fields, DefaultUserFieldCapacity),
outlets,
@ -89,6 +89,20 @@ func (l *Logger) log(level Level, msg string) {
}
func (l *Logger) WithOutlet(outlet Outlet, level Level) *Logger {
l.mtx.Lock()
defer l.mtx.Unlock()
newOutlets := l.outlets.DeepCopy()
newOutlets.Add(outlet, level)
child := &Logger{
fields: l.fields,
outlets: newOutlets,
outletTimeout: l.outletTimeout,
mtx: l.mtx,
}
return child
}
func (l *Logger) WithField(field string, val interface{}) *Logger {
l.mtx.Lock()
@ -101,7 +115,7 @@ func (l *Logger) WithField(field string, val interface{}) *Logger {
child := &Logger{
fields: make(Fields, len(l.fields)+1),
outlets: l.outlets, // cannot be changed after logger initialized
outlets: l.outlets,
outletTimeout: l.outletTimeout,
mtx: l.mtx,
}