-
Notifications
You must be signed in to change notification settings - Fork 0
/
log.go
189 lines (165 loc) · 6.15 KB
/
log.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
// SPDX-License-Identifier: Apache-2.0
// Copyright Authors of Cilium
package endpoint
import (
"os"
"path/filepath"
"strconv"
"sync"
"sync/atomic"
"unsafe"
"github.com/cilium/lumberjack/v2"
"github.com/sirupsen/logrus"
"github.com/cilium/cilium/pkg/logging"
"github.com/cilium/cilium/pkg/logging/logfields"
"github.com/cilium/cilium/pkg/option"
)
var (
log = logging.DefaultLogger.WithField(logfields.LogSubsys, subsystem)
policyLog = logrus.New()
policyLogOnce sync.Once
)
const (
subsystem = "endpoint"
fieldRegenLevel = "regeneration-level"
)
// getLogger returns a logrus object with EndpointID, containerID and the Endpoint
// revision fields.
func (e *Endpoint) getLogger() *logrus.Entry {
v := atomic.LoadPointer(&e.logger)
return (*logrus.Entry)(v)
}
// getPolicyLogger returns a logger to be used for policy update debugging, or nil,
// if not configured.
func (e *Endpoint) getPolicyLogger() *logrus.Entry {
v := atomic.LoadPointer(&e.policyLogger)
return (*logrus.Entry)(v)
}
// PolicyDebug logs the 'msg' with 'fields' if policy debug logging is enabled.
func (e *Endpoint) PolicyDebug(fields logrus.Fields, msg string) {
if dbgLog := e.getPolicyLogger(); dbgLog != nil {
dbgLog.WithFields(fields).Debug(msg)
}
}
// Logger returns a logrus object with EndpointID, containerID and the Endpoint
// revision fields. The caller must specify their subsystem.
func (e *Endpoint) Logger(subsystem string) *logrus.Entry {
if e == nil {
return log.WithField(logfields.LogSubsys, subsystem)
}
return e.getLogger().WithField(logfields.LogSubsys, subsystem)
}
// UpdateLogger creates a logger instance specific to this endpoint. It will
// create a custom Debug logger for this endpoint when the option on it is set.
// If fields is not nil only the those specific fields will be updated in the
// endpoint's logger, otherwise a full update of those fields is executed.
//
// Note: You must hold Endpoint.mutex.Lock() to synchronize logger pointer
// updates if the endpoint is already exposed. Callers that create new
// endopoints do not need locks to call this.
func (e *Endpoint) UpdateLogger(fields map[string]interface{}) {
e.updatePolicyLogger(fields)
v := atomic.LoadPointer(&e.logger)
epLogger := (*logrus.Entry)(v)
if fields != nil && epLogger != nil {
newLogger := epLogger.WithFields(fields)
atomic.StorePointer(&e.logger, unsafe.Pointer(newLogger))
return
}
// We need to update if
// - e.logger is nil (this happens on the first ever call to UpdateLogger via
// Logger above). This clause has to come first to guard the others.
// - If any of EndpointID, containerID or policyRevision are different on the
// endpoint from the logger.
// - The debug option on the endpoint is true, and the logger is not debug,
// or vice versa.
shouldUpdate := epLogger == nil || (e.Options != nil &&
e.Options.IsEnabled(option.Debug) != (epLogger.Level == logrus.DebugLevel))
// do nothing if we do not need an update
if !shouldUpdate {
return
}
// default to a new default logger
baseLogger := logging.InitializeDefaultLogger()
// If this endpoint is set to debug ensure it will print debug by giving it
// an independent logger
if e.Options != nil && e.Options.IsEnabled(option.Debug) {
baseLogger.SetLevel(logrus.DebugLevel)
} else {
// Debug mode takes priority; if not in debug, check what log level user
// has set and set the endpoint's log to log at that level.
baseLogger.SetLevel(logging.DefaultLogger.Level)
}
// When adding new fields, make sure they are abstracted by a setter
// and update the logger when the value is set.
l := baseLogger.WithFields(logrus.Fields{
logfields.LogSubsys: subsystem,
logfields.EndpointID: e.ID,
logfields.ContainerID: e.getShortContainerID(),
logfields.DatapathPolicyRevision: e.policyRevision,
logfields.DesiredPolicyRevision: e.nextPolicyRevision,
logfields.IPv4: e.IPv4.String(),
logfields.IPv6: e.IPv6.String(),
logfields.K8sPodName: e.getK8sNamespaceAndPodName(),
})
if e.SecurityIdentity != nil {
l = l.WithField(logfields.Identity, e.SecurityIdentity.ID.StringID())
}
atomic.StorePointer(&e.logger, unsafe.Pointer(l))
}
// Only to be called from UpdateLogger() above
func (e *Endpoint) updatePolicyLogger(fields map[string]interface{}) {
pv := atomic.LoadPointer(&e.policyLogger)
policyLogger := (*logrus.Entry)(pv)
// e.Options check needed for unit testing.
if policyLogger == nil && e.Options != nil && e.Options.IsEnabled(option.DebugPolicy) {
policyLogOnce.Do(func() {
maxSize := 10 // 10 MB
if ms := os.Getenv("CILIUM_DBG_POLICY_LOG_MAX_SIZE"); ms != "" {
if ms, err := strconv.Atoi(ms); err == nil {
maxSize = ms
}
}
maxBackups := 3
if mb := os.Getenv("CILIUM_DBG_POLICY_LOG_MAX_BACKUPS"); mb != "" {
if mb, err := strconv.Atoi(mb); err == nil {
maxBackups = mb
}
}
lumberjackLogger := &lumberjack.Logger{
Filename: filepath.Join(option.Config.StateDir, "endpoint-policy.log"),
MaxSize: maxSize,
MaxBackups: maxBackups,
MaxAge: 28, // days
LocalTime: true,
Compress: true,
}
policyLog.SetOutput(lumberjackLogger)
policyLog.SetLevel(logrus.DebugLevel)
})
policyLogger = logrus.NewEntry(policyLog)
}
if policyLogger == nil || e.Options == nil {
return
}
if !e.Options.IsEnabled(option.DebugPolicy) {
policyLogger = nil
} else if fields != nil {
policyLogger = policyLogger.WithFields(fields)
} else {
policyLogger = policyLogger.WithFields(logrus.Fields{
logfields.LogSubsys: subsystem,
logfields.EndpointID: e.ID,
logfields.ContainerID: e.getShortContainerID(),
logfields.DatapathPolicyRevision: e.policyRevision,
logfields.DesiredPolicyRevision: e.nextPolicyRevision,
logfields.IPv4: e.IPv4.String(),
logfields.IPv6: e.IPv6.String(),
logfields.K8sPodName: e.getK8sNamespaceAndPodName(),
})
if e.SecurityIdentity != nil {
policyLogger = policyLogger.WithField(logfields.Identity, e.SecurityIdentity.ID.StringID())
}
}
atomic.StorePointer(&e.policyLogger, unsafe.Pointer(policyLogger))
}