-
Notifications
You must be signed in to change notification settings - Fork 47
/
setup.go
201 lines (168 loc) · 4.63 KB
/
setup.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
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
package log
import (
"errors"
"fmt"
"net/url"
"os"
"regexp"
"sync"
"go.uber.org/zap"
"go.uber.org/zap/zapcore"
)
func init() {
// register the global pipes sink to allow us to specify it as an output
zap.RegisterSink("pipes", func(*url.URL) (zap.Sink, error) {
return pipes, nil
})
SetupLogging()
}
// Logging environment variables
const (
// IPFS_* prefixed env vars kept for backwards compatibility
// for this release. They will not be available in the next
// release.
//
// GOLOG_* env vars take precedences over IPFS_* env vars.
envIPFSLogging = "IPFS_LOGGING"
envIPFSLoggingFmt = "IPFS_LOGGING_FMT"
envLogging = "GOLOG_LOG_LEVEL"
envLoggingFmt = "GOLOG_LOG_FMT"
envLoggingFile = "GOLOG_FILE" // /path/to/file
)
// ErrNoSuchLogger is returned when the util pkg is asked for a non existant logger
var ErrNoSuchLogger = errors.New("Error: No such logger")
// loggers is the set of loggers in the system
var loggerMutex sync.RWMutex
var loggers = make(map[string]*zap.SugaredLogger)
var levels = make(map[string]zap.AtomicLevel)
// SetupLogging will initialize the logger backend and set the flags.
// TODO calling this in `init` pushes all configuration to env variables
// - move it out of `init`? then we need to change all the code (js-ipfs, go-ipfs) to call this explicitly
// - have it look for a config file? need to define what that is
var zapCfg = zap.NewProductionConfig()
func SetupLogging() {
loggingFmt := os.Getenv(envLoggingFmt)
if loggingFmt == "" {
loggingFmt = os.Getenv(envIPFSLoggingFmt)
}
// colorful or plain
switch loggingFmt {
case "nocolor":
zapCfg.Encoding = "console"
zapCfg.EncoderConfig.EncodeLevel = zapcore.CapitalLevelEncoder
case "json":
zapCfg.Encoding = "json"
default:
zapCfg.Encoding = "console"
zapCfg.EncoderConfig.EncodeLevel = zapcore.CapitalColorLevelEncoder
}
zapCfg.Sampling = nil
zapCfg.EncoderConfig.EncodeTime = zapcore.ISO8601TimeEncoder
zapCfg.DisableStacktrace = true
zapCfg.OutputPaths = []string{"stderr", "pipes://"}
// check if we log to a file
if logfp := os.Getenv(envLoggingFile); len(logfp) > 0 {
if path, err := normalizePath(logfp); err != nil {
fmt.Fprintf(os.Stderr, "failed to resolve log path '%q', logging to stderr only: %s\n", logfp, err)
} else {
// If file is specified, we will only log to the file
zapCfg.OutputPaths = []string{path}
}
}
// set the backend(s)
lvl := LevelError
logenv := os.Getenv(envLogging)
if logenv == "" {
logenv = os.Getenv(envIPFSLogging)
}
if logenv != "" {
var err error
lvl, err = LevelFromString(logenv)
if err != nil {
fmt.Fprintf(os.Stderr, "error setting log levels: %s\n", err)
}
}
zapCfg.Level.SetLevel(zapcore.Level(lvl))
SetAllLoggers(lvl)
}
// SetDebugLogging calls SetAllLoggers with logging.DEBUG
func SetDebugLogging() {
SetAllLoggers(LevelDebug)
}
// SetAllLoggers changes the logging level of all loggers to lvl
func SetAllLoggers(lvl LogLevel) {
loggerMutex.RLock()
defer loggerMutex.RUnlock()
for _, l := range levels {
l.SetLevel(zapcore.Level(lvl))
}
}
// SetLogLevel changes the log level of a specific subsystem
// name=="*" changes all subsystems
func SetLogLevel(name, level string) error {
lvl, err := LevelFromString(level)
if err != nil {
return err
}
// wildcard, change all
if name == "*" {
SetAllLoggers(lvl)
return nil
}
loggerMutex.RLock()
defer loggerMutex.RUnlock()
// Check if we have a logger by that name
if _, ok := levels[name]; !ok {
return ErrNoSuchLogger
}
levels[name].SetLevel(zapcore.Level(lvl))
return nil
}
// SetLogLevelRegex sets all loggers to level `l` that match expression `e`.
// An error is returned if `e` fails to compile.
func SetLogLevelRegex(e, l string) error {
lvl, err := LevelFromString(l)
if err != nil {
return err
}
rem, err := regexp.Compile(e)
if err != nil {
return err
}
loggerMutex.Lock()
defer loggerMutex.Unlock()
for name := range loggers {
if rem.MatchString(name) {
levels[name].SetLevel(zapcore.Level(lvl))
}
}
return nil
}
// GetSubsystems returns a slice containing the
// names of the current loggers
func GetSubsystems() []string {
loggerMutex.RLock()
defer loggerMutex.RUnlock()
subs := make([]string, 0, len(loggers))
for k := range loggers {
subs = append(subs, k)
}
return subs
}
func getLogger(name string) *zap.SugaredLogger {
loggerMutex.Lock()
defer loggerMutex.Unlock()
log, ok := loggers[name]
if !ok {
levels[name] = zap.NewAtomicLevelAt(zapCfg.Level.Level())
cfg := zap.Config(zapCfg)
cfg.Level = levels[name]
newlog, err := cfg.Build()
if err != nil {
panic(err)
}
log = newlog.Named(name).Sugar()
loggers[name] = log
}
return log
}