From 261d09510878986482ec9f701ae46538b04ba35e Mon Sep 17 00:00:00 2001 From: Christian Schwarz Date: Sat, 23 Dec 2017 00:55:02 +0100 Subject: [PATCH] logger: support forking of outlets refs #10 --- cmd/config_logging.go | 2 +- logger/datastructures.go | 47 ++++++++++++++++++++++++++++++---------- logger/logger.go | 20 ++++++++++++++--- 3 files changed, 53 insertions(+), 16 deletions(-) diff --git a/cmd/config_logging.go b/cmd/config_logging.go index df6b0b7..6f4a5d3 100644 --- a/cmd/config_logging.go +++ b/cmd/config_logging.go @@ -13,7 +13,7 @@ import ( ) type LoggingConfig struct { - Outlets logger.Outlets + Outlets *logger.Outlets } type MetadataFlags int64 diff --git a/logger/datastructures.go b/logger/datastructures.go index a5c0f23..745582e 100644 --- a/logger/datastructures.go +++ b/logger/datastructures.go @@ -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{} diff --git a/logger/logger.go b/logger/logger.go index 560f117..618c18f 100644 --- a/logger/logger.go +++ b/logger/logger.go @@ -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, }