Newer
Older
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
// Copyright 2017 Monax Industries Limited
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package logging
import (
kitlog "github.com/go-kit/kit/log"
"github.com/hyperledger/burrow/logging/structure"
)
// InfoTraceLogger maintains provides two logging 'channels' that are interlaced
// to provide a coarse grained filter to distinguish human-consumable 'Info'
// messages and execution level 'Trace' messages.
type Logger struct {
// Send a log message to the Info channel, formed of a sequence of key value
// pairs. Info messages should be operationally interesting to a human who is
// monitoring the logs. But not necessarily a human who is trying to
// understand or debug the system. Any handled errors or warnings should be
// sent to the Info channel (where you may wish to tag them with a suitable
// key-value pair to categorise them as such).
Info kitlog.Logger
// Send an log message to the Trace channel, formed of a sequence of key-value
// pairs. Trace messages can be used for any state change in the system that
// may be of interest to a machine consumer or a human who is trying to debug
// the system or trying to understand the system in detail. If the messages
// are very point-like and contain little structure, consider using a metric
// instead.
Trace kitlog.Logger
Output *kitlog.SwapLogger
}
// Create an InfoTraceLogger by passing the initial outputLogger.
func NewLogger(outputLogger kitlog.Logger) *Logger {
// We will never halt the progress of a log emitter. If log output takes too
// long will start dropping log lines by using a ring buffer.
swapLogger := new(kitlog.SwapLogger)
swapLogger.Swap(outputLogger)
return &Logger{
Output: swapLogger,
// logging contexts
Info: kitlog.With(swapLogger,
Trace: kitlog.With(swapLogger,
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
}
func NewNoopLogger() *Logger {
return &Logger{
Info: kitlog.NewNopLogger(),
Trace: kitlog.NewNopLogger(),
Output: new(kitlog.SwapLogger),
}
}
// A logging context (see go-kit log's Context). Takes a sequence key values
// via With or WithPrefix and ensures future calls to log will have those
// contextual values appended to the call to an underlying logger.
// Values can be dynamic by passing an instance of the kitlog.Valuer interface
// This provides an interface version of the kitlog.Context struct to be used
// For implementations that wrap a kitlog.Context. In addition it makes no
// assumption about the name or signature of the logging method(s).
// See InfoTraceLogger
func (l *Logger) With(keyvals ...interface{}) *Logger {
return &Logger{
Output: l.Output,
Info: kitlog.With(l.Info, keyvals...),
Trace: kitlog.With(l.Trace, keyvals...),
}
}
// Establish a context on the Info channel keeping Trace the same
func (l *Logger) WithInfo(keyvals ...interface{}) *Logger {
return &Logger{
Output: l.Output,
Info: kitlog.With(l.Info, keyvals...),
Trace: l.Trace,
}
}
// Establish a context on the Trace channel keeping Info the same
func (l *Logger) WithTrace(keyvals ...interface{}) *Logger {
return &Logger{
Output: l.Output,
Info: l.Info,
Trace: kitlog.With(l.Trace, keyvals...),
}
}
func (l *Logger) WithPrefix(keyvals ...interface{}) *Logger {
return &Logger{
Output: l.Output,
Info: kitlog.WithPrefix(l.Info, keyvals...),
Trace: kitlog.WithPrefix(l.Trace, keyvals...),
}
}
// Hot swap the underlying outputLogger with another one to re-route messages
func (l *Logger) SwapOutput(infoLogger kitlog.Logger) {
l.Output.Swap(infoLogger)
}
// Record structured Info lo`g line with a message
func (l *Logger) InfoMsg(message string, keyvals ...interface{}) error {
return Msg(l.Info, message, keyvals...)
}
// Record structured Trace log line with a message
func (l *Logger) TraceMsg(message string, keyvals ...interface{}) error {
return Msg(l.Trace, message, keyvals...)
}
// Establish or extend the scope of this logger by appending scopeName to the Scope vector.
// Like With the logging scope is append only but can be used to provide parenthetical scopes by hanging on to the
// parent scope and using once the scope has been exited. The scope mechanism does is agnostic to the type of scope
// so can be used to identify certain segments of the call stack, a lexical scope, or any other nested scope.
func (l *Logger) WithScope(scopeName string) *Logger {
// InfoTraceLogger will collapse successive (ScopeKey, scopeName) pairs into a vector in the order which they appear
return l.With(structure.ScopeKey, scopeName)
}
// Record a structured log line with a message
func Msg(logger kitlog.Logger, message string, keyvals ...interface{}) error {
prepended := structure.CopyPrepend(keyvals, structure.MessageKey, message)
return logger.Log(prepended...)
}