From 7795e220556fda703fdd1d9d78aec4b23b0d7b17 Mon Sep 17 00:00:00 2001 From: David Muir Sharnoff Date: Sat, 9 Jul 2022 13:14:13 -0700 Subject: [PATCH] refactor: combining base loggers is now outside Logger --- base.go | 31 ++++--- internal/multibase/group.go | 173 ++++++++++++++++++++++++++++++++++++ logger.go | 76 ++++++++-------- seed.go | 3 +- xopbase/group.go | 118 ------------------------ xopbase/things.go | 33 +++++++ 6 files changed, 259 insertions(+), 175 deletions(-) create mode 100644 internal/multibase/group.go delete mode 100644 xopbase/group.go create mode 100644 xopbase/things.go diff --git a/base.go b/base.go index 3da53798..e0266ca4 100644 --- a/base.go +++ b/base.go @@ -1,12 +1,13 @@ package xoplog import ( - "github.com/muir/xoplog/trace" + "github.com/muir/xoplog/internal/multibase" "github.com/muir/xoplog/xopbase" "github.com/muir/xoplog/xopconst" ) type baseLoggers struct { + AsOne xopbase.Logger List []baseLogger Removed []baseLogger } @@ -17,19 +18,7 @@ type baseLogger struct { MinLevel xopconst.Level } -func (s baseLoggers) requests(bundle trace.Bundle) (xopbase.Requests, bool) { - baseRequests := make(xopbase.Requests, len(s.List)) - var referencesKept bool - for i, baseLogger := range s.List { - baseRequests[i] = baseLogger.Base.Request(bundle) - if baseLogger.Base.ReferencesKept() { - referencesKept = true - } - } - return baseRequests, referencesKept -} - -func (s baseLoggers) copyWithoutTrace() baseLoggers { +func (s baseLoggers) Copy() baseLoggers { n := make([]baseLogger, len(s.List)) for i, bl := range s.List { n[i] = baseLogger{ @@ -38,7 +27,8 @@ func (s baseLoggers) copyWithoutTrace() baseLoggers { } } return baseLoggers{ - List: n, + AsOne: s.AsOne, + List: n, } } @@ -52,17 +42,26 @@ func WithoutBaseLogger(name string) SeedModifier { s.baseLoggers.List[len(s.baseLoggers.List)-1], s.baseLoggers.List[i] } s.baseLoggers.List = s.baseLoggers.List[:len(s.baseLoggers.List)-1] - break + s.rebuildAsOne() } } } } +func (s *Seed) rebuildAsOne() { + loggers := make([]xopbase.Logger, len(s.baseLoggers.List)) + for i, baseLogger := range s.baseLoggers.List { + loggers[i] = baseLogger.Base + } + s.baseLoggers.AsOne = multibase.CombineLoggers(loggers) +} + func WithBaseLogger(name string, logger xopbase.Logger) SeedModifier { return func(s *Seed) { s.baseLoggers.List = append(s.baseLoggers.List, baseLogger{ Name: name, Base: logger, }) + s.rebuildAsOne() } } diff --git a/internal/multibase/group.go b/internal/multibase/group.go new file mode 100644 index 00000000..f77f7b28 --- /dev/null +++ b/internal/multibase/group.go @@ -0,0 +1,173 @@ +package multibase + +import ( + "sync" + "time" + + "github.com/muir/xoplog/trace" + "github.com/muir/xoplog/xop" + "github.com/muir/xoplog/xopbase" + "github.com/muir/xoplog/xopconst" +) + +type Loggers []xopbase.Logger +type Requests []xopbase.Request +type Spans []xopbase.Span +type Lines []xopbase.Line + +var _ xopbase.Logger = Loggers{} +var _ xopbase.Request = Requests{} +var _ xopbase.Span = Spans{} +var _ xopbase.Line = Lines{} + +func CombineLoggers(loggers []xopbase.Logger) xopbase.Logger { + if len(loggers) == 1 { + return loggers[0] + } + return Loggers(loggers) +} + +func (l Loggers) Request(span trace.Bundle) xopbase.Request { + r := make(Requests, len(l)) + for i, logger := range l { + r[i] = logger.Request(span) + } + return r +} + +func (l Loggers) ReferencesKept() bool { + for _, logger := range l { + if logger.ReferencesKept() { + return true + } + } + return false +} + +func (l Loggers) Close() { + for _, logger := range l { + logger.Close() + } +} + +func (s Requests) Flush() { + var wg sync.WaitGroup + wg.Add(len(s)) + for _, request := range s { + go func() { + defer wg.Done() + request.Flush() + }() + } + wg.Wait() +} + +func (s Requests) Span(span trace.Bundle) xopbase.Span { + spans := make(Spans, len(s)) + for i, ele := range s { + spans[i] = ele.Span(span) + } + return spans +} +func (s Spans) Span(span trace.Bundle) xopbase.Span { + spans := make(Spans, len(s)) + for i, ele := range s { + spans[i] = ele.Span(span) + } + return spans +} + +func (s Requests) SpanInfo(st xopconst.SpanType, things []xop.Thing) { + for _, span := range s { + span.SpanInfo(st, things) + } +} +func (s Spans) SpanInfo(st xopconst.SpanType, things []xop.Thing) { + for _, span := range s { + span.SpanInfo(st, things) + } +} + +func (s Requests) AddPrefill(things []xop.Thing) { + for _, span := range s { + span.AddPrefill(things) + } +} +func (s Spans) AddPrefill(things []xop.Thing) { + for _, span := range s { + span.AddPrefill(things) + } +} + +func (s Requests) ResetLinePrefill() { + for _, span := range s { + span.ResetLinePrefill() + } +} +func (s Spans) ResetLinePrefill() { + for _, span := range s { + span.ResetLinePrefill() + } +} + +func (s Requests) Line(level xopconst.Level, t time.Time) xopbase.Line { + lines := make(Lines, len(s)) + for i, span := range s { + lines[i] = span.Line(level, t) + } + return lines +} +func (s Spans) Line(level xopconst.Level, t time.Time) xopbase.Line { + lines := make(Lines, len(s)) + for i, span := range s { + lines[i] = span.Line(level, t) + } + return lines +} + +func (l Lines) Int(k string, v int64) { + for _, line := range l { + line.Int(k, v) + } +} +func (l Lines) Str(k string, v string) { + for _, line := range l { + line.Str(k, v) + } +} +func (l Lines) Bool(k string, v bool) { + for _, line := range l { + line.Bool(k, v) + } +} +func (l Lines) Uint(k string, v uint64) { + for _, line := range l { + line.Uint(k, v) + } +} +func (l Lines) Time(k string, v time.Time) { + for _, line := range l { + line.Time(k, v) + } +} +func (l Lines) Any(k string, v interface{}) { + for _, line := range l { + line.Any(k, v) + } +} +func (l Lines) Error(k string, v error) { + for _, line := range l { + line.Error(k, v) + } +} +func (l Lines) Msg(m string) { + for _, line := range l { + line.Msg(m) + } +} + +func (l Lines) Things(things []xop.Thing) { + for _, line := range l { + xopbase.LineThings(line, things) + } +} diff --git a/logger.go b/logger.go index 542e05ec..be2b18cb 100644 --- a/logger.go +++ b/logger.go @@ -23,12 +23,12 @@ type Log struct { } type Span struct { - seed Seed - dataLock sync.Mutex // protects Data & SpanType (can only be held for short periods) - data []xop.Thing - spanType xopconst.SpanType - log *Log // back to self - baseSpans xopbase.Spans + seed Seed + dataLock sync.Mutex // protects Data & SpanType (can only be held for short periods) + data []xop.Thing + spanType xopconst.SpanType + log *Log // back to self + base xopbase.Span } type local struct { @@ -47,7 +47,7 @@ type shared struct { FlushTimer *time.Timer FlushDelay time.Duration FlushActive int32 // 1 == timer is running, 0 = timer is not running - BaseRequests xopbase.Requests + BaseRequest xopbase.Request ReferencesKept bool // Dirty holds spans that have modified data and need to be @@ -79,8 +79,9 @@ func (s Seed) Request(description string) *Log { log.request = &log.span log.shared.Dirty = append(log.shared.Dirty, &log) log.shared.FlushTimer = time.AfterFunc(DefaultFlushDelay, log.timerFlush) - log.shared.BaseRequests, log.shared.ReferencesKept = log.span.seed.baseLoggers.requests(log.span.seed.traceBundle) - log.span.baseSpans = log.shared.BaseRequests.Spans() + log.shared.BaseRequest = log.span.seed.baseLoggers.AsOne.Request(log.span.seed.traceBundle) + log.shared.ReferencesKept = log.span.seed.baseLoggers.AsOne.ReferencesKept() + log.span.base = log.shared.BaseRequest.(xopbase.Span) return &log } @@ -150,20 +151,15 @@ func (l *Log) Flush() { l.shared.FlushLock.Lock() defer l.shared.FlushLock.Unlock() for _, log := range dirty { - for _, baseSpan := range log.span.baseSpans { - baseSpan.SpanInfo(log.span.spanType, log.span.data) - } + log.span.base.SpanInfo(log.span.spanType, log.span.data) } - l.shared.BaseRequests.Flush() + l.shared.BaseRequest.Flush() } func (l *Log) log(level xopconst.Level, msg string, values []xop.Thing) { - t := time.Now() - for _, baseSpan := range l.span.baseSpans { - line := baseSpan.Line(level, t) - xopbase.LineThings(line, values) - line.Msg(msg) - } + line := l.span.base.Line(level, time.Now()) + xopbase.LineThings(line, values) + line.Msg(msg) l.enableFlushTimer() } @@ -247,15 +243,15 @@ func (l *Log) LogThings(level xopconst.Level, msg string, values ...xop.Thing) { } type LogLine struct { - log *Log - lines xopbase.Lines + log *Log + line xopbase.Line } func (l *Log) LogLine(level xopconst.Level) LogLine { // TODO PERFORMANCE: have a sync.Pool of LogLines return LogLine{ - log: l, - lines: l.span.baseSpans.Line(level, time.Now()), + log: l, + line: l.span.base.Line(level, time.Now()), } } @@ -268,27 +264,27 @@ func (l *Log) Alert() LogLine { return l.LogLine(xopconst.AlertLevel) } // TODO: generate these // TODO: the rest of the set -func (ll LogLine) Msg(msg string) { ll.lines.Msg(msg); ll.log.enableFlushTimer() } +func (ll LogLine) Msg(msg string) { ll.line.Msg(msg); ll.log.enableFlushTimer() } func (ll LogLine) Msgf(msg string, v ...interface{}) { ll.Msg(fmt.Sprintf(msg, v...)) } func (ll LogLine) Msgs(v ...interface{}) { ll.Msg(fmt.Sprint(v...)) } -func (ll LogLine) Int(k string, v int) LogLine { ll.lines.Int(k, int64(v)); return ll } -func (ll LogLine) Int8(k string, v int8) LogLine { ll.lines.Int(k, int64(v)); return ll } -func (ll LogLine) Int16(k string, v int16) LogLine { ll.lines.Int(k, int64(v)); return ll } -func (ll LogLine) Int32(k string, v int32) LogLine { ll.lines.Int(k, int64(v)); return ll } -func (ll LogLine) Int64(k string, v int64) LogLine { ll.lines.Int(k, v); return ll } -func (ll LogLine) Uint(k string, v uint) LogLine { ll.lines.Uint(k, uint64(v)); return ll } -func (ll LogLine) Uint8(k string, v uint8) LogLine { ll.lines.Uint(k, uint64(v)); return ll } -func (ll LogLine) Uint16(k string, v uint16) LogLine { ll.lines.Uint(k, uint64(v)); return ll } -func (ll LogLine) Uint32(k string, v uint32) LogLine { ll.lines.Uint(k, uint64(v)); return ll } -func (ll LogLine) Uint64(k string, v uint64) LogLine { ll.lines.Uint(k, v); return ll } -func (ll LogLine) Str(k string, v string) LogLine { ll.lines.Str(k, v); return ll } -func (ll LogLine) Bool(k string, v bool) LogLine { ll.lines.Bool(k, v); return ll } -func (ll LogLine) Time(k string, v time.Time) LogLine { ll.lines.Time(k, v); return ll } -func (ll LogLine) Error(k string, v error) LogLine { ll.lines.Error(k, v); return ll } +func (ll LogLine) Int(k string, v int) LogLine { ll.line.Int(k, int64(v)); return ll } +func (ll LogLine) Int8(k string, v int8) LogLine { ll.line.Int(k, int64(v)); return ll } +func (ll LogLine) Int16(k string, v int16) LogLine { ll.line.Int(k, int64(v)); return ll } +func (ll LogLine) Int32(k string, v int32) LogLine { ll.line.Int(k, int64(v)); return ll } +func (ll LogLine) Int64(k string, v int64) LogLine { ll.line.Int(k, v); return ll } +func (ll LogLine) Uint(k string, v uint) LogLine { ll.line.Uint(k, uint64(v)); return ll } +func (ll LogLine) Uint8(k string, v uint8) LogLine { ll.line.Uint(k, uint64(v)); return ll } +func (ll LogLine) Uint16(k string, v uint16) LogLine { ll.line.Uint(k, uint64(v)); return ll } +func (ll LogLine) Uint32(k string, v uint32) LogLine { ll.line.Uint(k, uint64(v)); return ll } +func (ll LogLine) Uint64(k string, v uint64) LogLine { ll.line.Uint(k, v); return ll } +func (ll LogLine) Str(k string, v string) LogLine { ll.line.Str(k, v); return ll } +func (ll LogLine) Bool(k string, v bool) LogLine { ll.line.Bool(k, v); return ll } +func (ll LogLine) Time(k string, v time.Time) LogLine { ll.line.Time(k, v); return ll } +func (ll LogLine) Error(k string, v error) LogLine { ll.line.Error(k, v); return ll } // AnyImmutable can be used to log something that is not going to be further modified // after this call. -func (ll LogLine) AnyImmutable(k string, v interface{}) LogLine { ll.lines.Any(k, v); return ll } +func (ll LogLine) AnyImmutable(k string, v interface{}) LogLine { ll.line.Any(k, v); return ll } // Any can be used to log something that might be modified after this call. If any base // logger does not immediately serialize, then the object will be copied using @@ -298,7 +294,7 @@ func (ll LogLine) Any(k string, v interface{}) LogLine { // TODO: make copy function configurable v = deepcopy.Copy(v) } - ll.lines.Any(k, v) + ll.line.Any(k, v) return ll } diff --git a/seed.go b/seed.go index 4a6f2a33..ebcd1dd6 100644 --- a/seed.go +++ b/seed.go @@ -23,7 +23,7 @@ type Seed struct { func (s Seed) Copy() Seed { n := s n.prefill = copyFields(s.prefill) - n.baseLoggers = s.baseLoggers.copyWithoutTrace() + n.baseLoggers = s.baseLoggers.Copy() n.data = nil n.traceBundle = s.traceBundle.Copy() return n @@ -44,6 +44,7 @@ func NewSeed(mods ...SeedModifier) Seed { }, traceBundle: trace.NewBundle(), } + seed.rebuildAsOne() return seed.applyMods(mods) } diff --git a/xopbase/group.go b/xopbase/group.go deleted file mode 100644 index f80220ea..00000000 --- a/xopbase/group.go +++ /dev/null @@ -1,118 +0,0 @@ -package xopbase - -import ( - "fmt" - "sync" - "time" - - "github.com/muir/xoplog/xop" - "github.com/muir/xoplog/xopconst" -) - -type Requests []Request -type Spans []Span -type Lines []Line - -func (r Requests) Flush() { - if len(r) == 1 { - r[0].Flush() - return - } - var wg sync.WaitGroup - wg.Add(len(r)) - for _, request := range r { - go func() { - defer wg.Done() - request.Flush() - }() - } - wg.Wait() -} - -func (r Requests) Spans() Spans { - spans := make(Spans, len(r)) - for i, request := range r { - spans[i] = request.(Span) - } - return spans -} - -func (s Spans) Line(level xopconst.Level, t time.Time) Lines { - lines := make(Lines, len(s)) - for i, span := range s { - lines[i] = span.Line(level, t) - } - return lines -} - -func (l Lines) Int(k string, v int64) { - for _, line := range l { - line.Int(k, v) - } -} -func (l Lines) Str(k string, v string) { - for _, line := range l { - line.Str(k, v) - } -} -func (l Lines) Bool(k string, v bool) { - for _, line := range l { - line.Bool(k, v) - } -} -func (l Lines) Uint(k string, v uint64) { - for _, line := range l { - line.Uint(k, v) - } -} -func (l Lines) Time(k string, v time.Time) { - for _, line := range l { - line.Time(k, v) - } -} -func (l Lines) Any(k string, v interface{}) { - for _, line := range l { - line.Any(k, v) - } -} -func (l Lines) Error(k string, v error) { - for _, line := range l { - line.Error(k, v) - } -} -func (l Lines) Msg(m string) { - for _, line := range l { - line.Msg(m) - } -} - -func (l Lines) Things(things []xop.Thing) { - for _, line := range l { - LineThings(line, things) - } -} - -func LineThings(line Line, things []xop.Thing) { - for _, thing := range things { - switch thing.Type { - case xop.IntType: - line.Int(thing.Key, thing.Int) - case xop.UintType: - line.Uint(thing.Key, thing.Any.(uint64)) - case xop.BoolType: - line.Bool(thing.Key, thing.Any.(bool)) - case xop.StringType: - line.Str(thing.Key, thing.String) - case xop.TimeType: - line.Time(thing.Key, thing.Any.(time.Time)) - case xop.AnyType: - line.Any(thing.Key, thing.Any) - case xop.ErrorType: - line.Error(thing.Key, thing.Any.(error)) - case xop.UnsetType: - fallthrough - default: - panic(fmt.Sprintf("malformed xop.Thing, type is %d", thing.Type)) - } - } -} diff --git a/xopbase/things.go b/xopbase/things.go new file mode 100644 index 00000000..c83a2f7f --- /dev/null +++ b/xopbase/things.go @@ -0,0 +1,33 @@ +package xopbase + +import ( + "fmt" + "time" + + "github.com/muir/xoplog/xop" +) + +func LineThings(line Line, things []xop.Thing) { + for _, thing := range things { + switch thing.Type { + case xop.IntType: + line.Int(thing.Key, thing.Int) + case xop.UintType: + line.Uint(thing.Key, thing.Any.(uint64)) + case xop.BoolType: + line.Bool(thing.Key, thing.Any.(bool)) + case xop.StringType: + line.Str(thing.Key, thing.String) + case xop.TimeType: + line.Time(thing.Key, thing.Any.(time.Time)) + case xop.AnyType: + line.Any(thing.Key, thing.Any) + case xop.ErrorType: + line.Error(thing.Key, thing.Any.(error)) + case xop.UnsetType: + fallthrough + default: + panic(fmt.Sprintf("malformed xop.Thing, type is %d", thing.Type)) + } + } +}