-
Notifications
You must be signed in to change notification settings - Fork 444
/
logging.go
146 lines (118 loc) · 4.34 KB
/
logging.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
package services
import (
"fmt"
"os"
"strings"
"sync"
"k8s.io/apimachinery/pkg/util/sets"
"github.com/onsi/gomega"
errors "github.com/rotisserie/eris"
"github.com/solo-io/gloo/test/testutils"
"go.uber.org/zap"
"go.uber.org/zap/zapcore"
)
const (
// _loggingConfigRegex is the format of the string that can be passed to configure the log level of services
// It is currently unused, but is here for reference
// In general, we try to use the name of the deployment, e.g. gateway-proxy, gloo, discovery, etc.
// for the name of the service. To confirm the name of the service that is being used, check the
// invocation for the given service
_loggingConfigRegex = "serviceA:logLevel,serviceB:logLevel"
pairSeparator = ","
nameValueSeparator = ":"
)
var (
logProviderSingleton = &logProvider{
defaultLogLevel: zapcore.InfoLevel,
serviceLogLevel: make(map[string]zapcore.Level, 3),
}
)
func init() {
// Initialize the log provider with the log level provided in the environment variable
LoadUserDefinedLogLevelFromEnv()
}
// LoadUserDefinedLogLevelFromEnv loads the log level from the environment variable
// and resets the entire LogProvider state to the values in that environment variable
func LoadUserDefinedLogLevelFromEnv() {
logProviderSingleton.ReloadFromEnv()
}
// LoadUserDefinedLogLevel loads the log level from the provided string
// and resets the entire LogProvider state to the values in that string
func LoadUserDefinedLogLevel(userDefinedLogLevel string) {
logProviderSingleton.ReloadFromString(userDefinedLogLevel)
}
// GetLogLevel returns the log level for the given service
func GetLogLevel(serviceName string) zapcore.Level {
return logProviderSingleton.GetLogLevel(serviceName)
}
// SetLogLevel sets the log level for the given service
func SetLogLevel(serviceName string, logLevel zapcore.Level) {
logProviderSingleton.SetLogLevel(serviceName, logLevel)
}
// IsDebugLogLevel returns true if the given service is logging at the debug level
func IsDebugLogLevel(serviceName string) bool {
logLevel := GetLogLevel(serviceName)
return logLevel == zapcore.DebugLevel
}
// MustGetSugaredLogger returns a sugared logger for the given service
// This logger is configured with the appropriate log level
func MustGetSugaredLogger(serviceName string) *zap.SugaredLogger {
logLevel := GetLogLevel(serviceName)
config := zap.NewProductionConfig()
config.EncoderConfig.EncodeTime = zapcore.ISO8601TimeEncoder
config.Level.SetLevel(logLevel)
logger, err := config.Build()
gomega.Expect(err).NotTo(gomega.HaveOccurred(), "failed to build logger for: %s", serviceName)
return logger.Sugar()
}
// logProvider is a helper for managing the log level of multiple services
type logProvider struct {
sync.RWMutex
defaultLogLevel zapcore.Level
serviceLogLevel map[string]zapcore.Level
}
func (l *logProvider) GetLogLevel(serviceName string) zapcore.Level {
l.RLock()
defer l.RUnlock()
logLevel, ok := l.serviceLogLevel[serviceName]
if !ok {
return l.defaultLogLevel
}
return logLevel
}
func (l *logProvider) SetLogLevel(serviceName string, logLevel zapcore.Level) {
l.Lock()
defer l.Unlock()
l.serviceLogLevel[serviceName] = logLevel
}
func (l *logProvider) ReloadFromEnv() {
l.ReloadFromString(os.Getenv(testutils.ServiceLogLevel))
}
func (l *logProvider) ReloadFromString(userDefinedLogLevel string) {
l.Lock()
defer l.Unlock()
serviceLogPairs := strings.Split(userDefinedLogLevel, pairSeparator)
serviceNameSet := sets.NewString()
for _, serviceLogPair := range serviceLogPairs {
nameValue := strings.Split(serviceLogPair, nameValueSeparator)
if len(nameValue) != 2 {
continue
}
serviceName := nameValue[0]
logLevelStr := nameValue[1]
if serviceNameSet.Has(serviceName) {
// This isn't an error, but we want to warn the user that with multiple definitions
// there may be unknown behavior
fmt.Printf("WARNING: duplicate service name found in log level string: %s\n", serviceName)
}
logLevel, err := zapcore.ParseLevel(logLevelStr)
// We intentionally error loudly here
// This will occur if the user passes an invalid log level string
if err != nil {
panic(errors.Wrapf(err, "invalid log level string: %s", logLevelStr))
}
// This whole function operates with a lock, so we can modify the map directly
logProviderSingleton.serviceLogLevel[serviceName] = logLevel
serviceNameSet.Insert(serviceName)
}
}