-
Notifications
You must be signed in to change notification settings - Fork 0
/
logfactory.go
155 lines (142 loc) · 4.3 KB
/
logfactory.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
// Copyright (c) 2016 Ventu.io, Oleg Sklyar, contributors
// The use of this source code is governed by a MIT style license found in the LICENSE file
package slog
import (
"github.com/KristinaEtc/slf"
"strings"
"sync"
)
const (
// ContextField defines the field name to store context.
ContextField = "context"
rootLevelKey = "root"
)
// LogFactory extends the SLF LogFactory interface with a series of methods specific to the slog
// implementation.
type LogFactory interface {
slf.LogFactory
SetLevel(level slf.Level, contexts ...string)
SetCallerInfo(callerInfo slf.CallerInfo, contexts ...string)
AddEntryHandler(handler EntryHandler)
SetEntryHandlers(handlers ...EntryHandler)
Contexts() map[string]slf.StructuredLogger
SetConcurrent(conc bool)
}
// New constructs a new logger conforming with SLF.
func New() LogFactory {
res := &logFactory{
root: rootLogger{
minlevel: slf.LevelInfo,
// essentially undefined: every logger that does not have it set (even to None)
// should consult the root logger
caller: slf.CallerInfo(-1),
},
contexts: make(map[string]*logger),
concurrent: false,
}
res.root.factory = res
return res
}
// factory implements the slog.Logger interface.
type logFactory struct {
sync.RWMutex
root rootLogger
contexts map[string]*logger
handlers []EntryHandler
concurrent bool
}
// WithContext delivers a logger for the given context (reusing loggers for the same context).
func (lf *logFactory) WithContext(context string) slf.StructuredLogger {
lf.RLock()
ctx, ok := lf.contexts[context]
lf.RUnlock()
if ok {
return ctx
}
fields := make(map[string]interface{})
fields[ContextField] = context
ctx = &logger{
rootLogger: &rootLogger{minlevel: lf.root.minlevel, factory: lf.root.factory, caller: lf.root.caller},
fields: fields,
caller: lf.root.caller,
}
lf.Lock()
lf.contexts[context] = ctx
lf.Unlock()
return ctx
}
// SetLevel sets the logging slf.Level to given contexts, all loggers if no context given, or the root
// logger when context defined as "root".
func (lf *logFactory) SetLevel(level slf.Level, contexts ...string) {
// set on all current and root
if len(contexts) == 0 {
lf.root.minlevel = level
lf.Lock()
for _, logger := range lf.contexts {
logger.rootLogger.minlevel = level
}
lf.Unlock()
return
}
// setting on given only
for _, context := range contexts {
if strings.ToLower(context) != rootLevelKey {
logger, _ := lf.WithContext(context).(*logger) // locks internally
logger.rootLogger.minlevel = level
} else {
lf.root.minlevel = level
}
}
}
// SetCallerInfo sets the logging slf.CallerInfo to given contexts, all loggers if no context given,
// or the root logger when context defined as "root".
func (lf *logFactory) SetCallerInfo(callerInfo slf.CallerInfo, contexts ...string) {
// set on all current and root
if len(contexts) == 0 {
lf.root.caller = callerInfo
lf.Lock()
for _, logger := range lf.contexts {
logger.rootLogger.caller = callerInfo
}
lf.Unlock()
return
}
// setting on given only
for _, context := range contexts {
if strings.ToLower(context) != rootLevelKey {
logger, _ := lf.WithContext(context).(*logger) // locks internally
logger.rootLogger.caller = callerInfo
} else {
lf.root.caller = callerInfo
}
}
}
// AddEntryHandler adds a handler for log entries that are logged at or above the set
// log slf.Level.
func (lf *logFactory) AddEntryHandler(handler EntryHandler) {
lf.Lock()
lf.handlers = append(lf.handlers, handler)
lf.Unlock()
}
// SetEntryHandlers overwrites existing entry handlers with a new set.
func (lf *logFactory) SetEntryHandlers(handlers ...EntryHandler) {
lf.Lock()
lf.handlers = append([]EntryHandler{}, handlers...)
lf.Unlock()
}
// Contexts returns all defined root logging contexts.
func (lf *logFactory) Contexts() map[string]slf.StructuredLogger {
res := make(map[string]slf.StructuredLogger)
lf.RLock()
for key, val := range lf.contexts {
res[key] = val
}
lf.RUnlock()
return res
}
// SetConcurrent toggles concurrency in handling log messages. If concurrent, the output sequence
// of entries is not guaranteed to be the same as log entries input sequence, although the
// timestamp will correspond the time of logging, not handling. Default: not concurrent.
func (lf *logFactory) SetConcurrent(conc bool) {
lf.concurrent = conc
}