Skip to content

Commit 92a9c9f

Browse files
committed
Add logger mechanism
Signed-off-by: Jiangnan Jia <[email protected]>
1 parent 36f411b commit 92a9c9f

File tree

12 files changed

+1198
-0
lines changed

12 files changed

+1198
-0
lines changed

go.mod

+2
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@ module github.com/opensergo/opensergo-go
33
go 1.15
44

55
require (
6+
github.com/envoyproxy/protoc-gen-validate v0.1.0
7+
github.com/pkg/errors v0.9.1
68
google.golang.org/grpc v1.43.0
79
google.golang.org/protobuf v1.27.1
810
)

go.sum

+3
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.m
1717
github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
1818
github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk=
1919
github.com/envoyproxy/go-control-plane v0.9.10-0.20210907150352-cf90f659a021/go.mod h1:AFq3mo9L8Lqqiid3OhADV3RfLJnjiw63cSpi+fDTRC0=
20+
github.com/envoyproxy/protoc-gen-validate v0.1.0 h1:EQciDnbrYxy13PgWoY8AqoxGiPrpgBZ1R8UNe3ddc+A=
2021
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
2122
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
2223
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
@@ -43,6 +44,8 @@ github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU=
4344
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
4445
github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
4546
github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw=
47+
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
48+
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
4649
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
4750
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
4851
github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ=

pkg/common/logging/README.md

+94
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
# logging component
2+
3+
here provider a common Logger interface which is highly extensible and multi implementable
4+
5+
## Quick start
6+
In this logging component, you can have only one global ConsoleLogger, and several FileLogger, By invoking function in [logger.go](./logger.go):
7+
``` go
8+
// AppendLoggerSlice add the Logger into loggerSlice
9+
func AppendLoggerSlice(loggerAppend Logger) {
10+
loggerSlice = append(loggerSlice, loggerAppend)
11+
}
12+
13+
// SetConsoleLogger set the consoleLogger to print int stdout
14+
func SetConsoleLogger(logger Logger) {
15+
consoleLogger = logger
16+
}
17+
```
18+
19+
You can use the default implement of Logger directly, By new Logger instance implemented in [logger_default.go](./logger_default.go),
20+
But first, you should new instances from [logger_default.go](./logger_default.go), like following:
21+
``` go
22+
// new instances
23+
logging.NewDefaultConsoleLogger(logging.DebugLevel)
24+
logging.NewDefaultFileLogger(logging.DebugLevel)
25+
// invoke the function in Logger interface
26+
logging.Error(errors.New("errors.New"), "this is error log in printErrorStack()")
27+
logging.Info("this is info log in printErrorStack()")
28+
logging.Debug("this is debug log in printErrorStack()")
29+
```
30+
31+
You can format you log, by using [logger_assembler.go](./logger_assembler.go),
32+
the assembler provides AssembleMsgJsonFormat and AssembleMsgSeparateFormat can be chosen.
33+
34+
``` go
35+
// the unified entrance for AssembleMsg
36+
func AssembleMsg(logFormat LogFormat, callerDepth int, logLevel, msg string, err error, errWithStack bool, keysAndValues ...interface{}) string
37+
38+
// AssembleMsgJsonFormat Assemble log-msg as json-format
39+
//
40+
// debug/info/warn:
41+
// {"logLevel":"INFO","timestamp":"2006-01-02 15:04:05.000","caller":"opensergo_client.go:74","msg":"openSergoClient is starting..."}
42+
//
43+
// error:
44+
// {"logLevel":"ERROR","timestamp":"2006-01-02 15:04:05.000","caller":"opensergo_client.go:83","msg":"can not connect.","error":"rpc error: code = Unavailable desc = connection error: desc = \"transport: Error while dialing dial tcp 33.1.33.1:10246: connect: connection refused\""}
45+
// [ ERROR CAUSES WITH STACK ][ rpc error: code = Unavailable desc = connection error: desc = "transport: Error while dialing dial tcp 33.1.33.1:10246: connect: connection refused"
46+
// github.com/opensergo/opensergo-go/pkg/client.handleReceive.func1
47+
//
48+
// .../opensergo-go-sdk/pkg/client/opensergo_client.go:82 ][ ERROR CAUSES WITH STACK END ]
49+
func AssembleMsgJsonFormat(callerDepth int, logLevel, msg string, err error, errWithStack bool, keysAndValues ...interface{}) string
50+
51+
// AssembleMsgSeparateFormat Assemble log-msg as separate-format
52+
//
53+
// pattern:
54+
// level | timestamp | callerFile:line | logContentJson | errorInfo
55+
//
56+
// debug/info/warn:
57+
// INFO | 2006-01-02 15:04:05.000 | main.go:30 | {"msg":"connected.", kvs:{}}
58+
//
59+
// error:
60+
// ERROR | 2006-01-02 15:04:05.000 | main.go:30 | {"msg":"connected.", kvs:{}} | rpc error: code = Unavailable desc = connection error: desc = "transport: Error while dialing dial tcp 33.1.33.1:10246: i/o timeout"
61+
// [ ERROR CAUSES WITH STACK ][ rpc error: code = Unavailable desc = connection error: desc = "transport: Error while dialing dial tcp 33.1.33.1:10246: connect: connection refused"
62+
// github.com/opensergo/opensergo-go/pkg/client.handleReceive.func1
63+
//
64+
// .../opensergo-go-sdk/pkg/client/opensergo_client.go:82 ][ ERROR CAUSES WITH STACK END ]
65+
func AssembleMsgSeparateFormat(callerDepth int, logLevel, msg string, err error, errWithStack bool, keysAndValues ...interface{})
66+
```
67+
68+
## Samples
69+
70+
### sample_simple_print
71+
If you only want to use the Logger provided by default, you can new a ConsoleLogger, like following:
72+
``` go
73+
// default ConsoleLogger
74+
// logging.NewDefaultConsoleLogger(logging.DebugLevel)
75+
// custom ConsoleLogger
76+
logging.NewConsoleLogger(logging.DebugLevel, logging.JsonFormat, true)
77+
logging.Error(errors.New("errors.New"), "this is error log in printErrorStack()")
78+
logging.Info("this is info log in printErrorStack()")
79+
logging.Debug("this is debug log in printErrorStack()")
80+
```
81+
For detail, please refer to [sample_simple_print](./samples/sample_simple_print)
82+
83+
### sample_print_impl_logging
84+
If you want to replace the logger implement where has integrated this logging component,
85+
you can implement the [Logger](./logger.go) by your-self, append you Logger after invoke `ClearLoggerSlice()` in Logger,
86+
or invoke `SetConsoleLogger(logger Logger)` to set the global ConsoleLogger.
87+
88+
For detail, please refer to [sample_print_impl_logging](./samples/sample_print_impl_logging)
89+
90+
### sample_print_use_logging
91+
If you want to use this logging component to replace the other has already integrated,
92+
you can re-implement the other Logger by invoking the function in Logger which was instanced.
93+
94+
For detail, please refer to [sample_print_use_logging](./samples/sample_print_use_logging)

pkg/common/logging/doc.go

+16
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
// Copyright 2022, OpenSergo Authors
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
// Package logging.
16+
package logging

pkg/common/logging/logger.go

+252
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,252 @@
1+
// Copyright 2022, OpenSergo Authors
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
package logging
16+
17+
import (
18+
"github.com/pkg/errors"
19+
"reflect"
20+
)
21+
22+
// Logger the common interface for logging.
23+
type Logger interface {
24+
25+
// Print logs message no format as what the msg presents.
26+
Print(msg string)
27+
28+
// DebugEnabled judge is the DebugLevel enabled
29+
DebugEnabled() bool
30+
// Debug logs a non-error message with the given key/value pairs as context.
31+
//
32+
// The msg argument should be used to add some constant description to
33+
// the log line. The key/value pairs can then be used to add additional
34+
// variable information. The key/value pairs should alternate string
35+
// keys and arbitrary values.
36+
Debug(msg string, keysAndValues ...interface{})
37+
38+
// InfoEnabled judge is the InfoLevel enabled
39+
InfoEnabled() bool
40+
// Info logs a non-error message with the given key/value pairs as context.
41+
//
42+
// The msg argument should be used to add some constant description to
43+
// the log line. The key/value pairs can then be used to add additional
44+
// variable information. The key/value pairs should alternate string
45+
// keys and arbitrary values.
46+
Info(msg string, keysAndValues ...interface{})
47+
48+
// WarnEnabled judge is the WarnLevel enabled
49+
WarnEnabled() bool
50+
// Warn logs a non-error message with the given key/value pairs as context.
51+
//
52+
// The msg argument should be used to add some constant description to
53+
// the log line. The key/value pairs can then be used to add additional
54+
// variable information. The key/value pairs should alternate string
55+
// keys and arbitrary values.
56+
Warn(msg string, keysAndValues ...interface{})
57+
58+
// ErrorEnabled judge is the ErrorLevel enabled
59+
ErrorEnabled() bool
60+
// Error logs an error message with error and the given key/value pairs as context.
61+
//
62+
// The msg argument should be used to add some constant description to
63+
// the log line. The key/value pairs can then be used to add additional
64+
// variable information. The key/value pairs should alternate string
65+
// keys and arbitrary values.
66+
Error(err error, msg string, keysAndValues ...interface{})
67+
}
68+
69+
var (
70+
loggerSlice = make([]Logger, 0)
71+
72+
consoleLogger Logger
73+
)
74+
75+
// Print logs message no format as what the msg presents.
76+
func Print(msg string) {
77+
doLog("Print", nil, msg)
78+
}
79+
80+
// Debug logs a non-error message with the given key/value pairs as context.
81+
//
82+
// The msg argument should be used to add some constant description to
83+
// the log line. The key/value pairs can then be used to add additional
84+
// variable information. The key/value pairs should alternate string
85+
// keys and arbitrary values.
86+
func Debug(msg string, keysAndValues ...interface{}) {
87+
doLog("Debug", nil, msg, keysAndValues...)
88+
}
89+
90+
// DebugWithCallerDepth logs a non-error message with the given key/value pairs as context.
91+
//
92+
// logCallerDepth: to calculate the caller:line
93+
//
94+
// The msg argument should be used to add some constant description to
95+
// the log line. The key/value pairs can then be used to add additional
96+
// variable information. The key/value pairs should alternate string
97+
// keys and arbitrary values.
98+
func DebugWithCallerDepth(logger Logger, logFormat LogFormat, logCallerDepth int, msg string, keysAndValues ...interface{}) {
99+
if !logger.DebugEnabled() {
100+
return
101+
}
102+
logger.Print(AssembleMsg(logFormat, logCallerDepth, "DEBUG", msg, nil, false, keysAndValues...))
103+
}
104+
105+
// Info logs a non-error message with the given key/value pairs as context.
106+
//
107+
// The msg argument should be used to add some constant description to
108+
// the log line. The key/value pairs can then be used to add additional
109+
// variable information. The key/value pairs should alternate string
110+
// keys and arbitrary values.
111+
func Info(msg string, keysAndValues ...interface{}) {
112+
doLog("Info", nil, msg, keysAndValues...)
113+
}
114+
115+
// InfoWithCallerDepth logs a non-error message with the given key/value pairs as context.
116+
//
117+
// logCallerDepth: to calculate the caller:line
118+
//
119+
// The msg argument should be used to add some constant description to
120+
// the log line. The key/value pairs can then be used to add additional
121+
// variable information. The key/value pairs should alternate string
122+
// keys and arbitrary values.
123+
func InfoWithCallerDepth(logger Logger, logFormat LogFormat, logCallerDepth int, msg string, keysAndValues ...interface{}) {
124+
if !logger.InfoEnabled() {
125+
return
126+
}
127+
logger.Print(AssembleMsg(logFormat, logCallerDepth, "INFO", msg, nil, false, keysAndValues...))
128+
}
129+
130+
// Warn logs a non-error message with the given key/value pairs as context.
131+
//
132+
// The msg argument should be used to add some constant description to
133+
// the log line. The key/value pairs can then be used to add additional
134+
// variable information. The key/value pairs should alternate string
135+
// keys and arbitrary values.
136+
func Warn(msg string, keysAndValues ...interface{}) {
137+
doLog("Warn", nil, msg, keysAndValues...)
138+
}
139+
140+
// WarnWithCallerDepth logs a non-error message with the given key/value pairs as context.
141+
//
142+
// logCallerDepth: to calculate the caller:line
143+
//
144+
// The msg argument should be used to add some constant description to
145+
// the log line. The key/value pairs can then be used to add additional
146+
// variable information. The key/value pairs should alternate string
147+
// keys and arbitrary values.
148+
func WarnWithCallerDepth(logger Logger, logFormat LogFormat, logCallerDepth int, msg string, keysAndValues ...interface{}) {
149+
if !logger.WarnEnabled() {
150+
return
151+
}
152+
153+
logger.Print(AssembleMsg(logFormat, logCallerDepth, "WARN", msg, nil, false, keysAndValues...))
154+
}
155+
156+
// Error logs an error message with error and the given key/value pairs as context.
157+
//
158+
// The msg argument should be used to add some constant description to
159+
// the log line. The key/value pairs can then be used to add additional
160+
// variable information. The key/value pairs should alternate string
161+
// keys and arbitrary values.
162+
func Error(err error, msg string, keysAndValues ...interface{}) {
163+
doLog("Error", err, msg, keysAndValues...)
164+
}
165+
166+
// ErrorWithCallerDepth logs an error message with error and the given key/value pairs as context.
167+
//
168+
// logCallerDepth: to calculate the caller:line
169+
//
170+
// The msg argument should be used to add some constant description to
171+
// the log line. The key/value pairs can then be used to add additional
172+
// variable information. The key/value pairs should alternate string
173+
// keys and arbitrary values.
174+
func ErrorWithCallerDepth(logger Logger, logFormat LogFormat, logCallerDepth int, err error, errorWithStack bool, msg string, keysAndValues ...interface{}) {
175+
if !logger.ErrorEnabled() {
176+
return
177+
}
178+
logger.Print(AssembleMsg(logFormat, logCallerDepth, "ERROR", msg, err, errorWithStack, keysAndValues...))
179+
}
180+
181+
// AppendLoggerSlice add the Logger into loggerSlice
182+
func AppendLoggerSlice(loggerAppend Logger) {
183+
loggerSlice = append(loggerSlice, loggerAppend)
184+
}
185+
186+
// ClearLoggerSlice clear the Logger into loggerSlice
187+
func ClearLoggerSlice() {
188+
loggerSlice = make([]Logger, 0)
189+
}
190+
191+
// SetConsoleLogger set the consoleLogger to print int stdout
192+
func SetConsoleLogger(logger Logger) {
193+
consoleLogger = logger
194+
}
195+
196+
// doLog do log
197+
// funcNameFromInterface funcName in Logger
198+
// err
199+
// msg
200+
// keysAndValues
201+
func doLog(funcNameFromInterface string, err error, msg string, keysAndValues ...interface{}) {
202+
if consoleLogger == nil && len(loggerSlice) == 0 {
203+
NewDefaultConsoleLogger(InfoLevel)
204+
}
205+
206+
if consoleLogger != nil {
207+
invokeLogger(consoleLogger, funcNameFromInterface, err, msg, keysAndValues...)
208+
}
209+
210+
if len(loggerSlice) > 0 {
211+
for _, logger := range loggerSlice {
212+
invokeLogger(logger, funcNameFromInterface, err, msg, keysAndValues...)
213+
}
214+
}
215+
}
216+
217+
// invokeLogger do log actually by invoke function of Logger
218+
// logger Logger to print
219+
// funcNameFromInterface funcName in Logger
220+
// err
221+
// msg
222+
// keysAndValues
223+
func invokeLogger(logger Logger, funcNameFromInterface string, err error, msg string, keysAndValues ...interface{}) {
224+
method, ok := reflect.TypeOf(logger).MethodByName(funcNameFromInterface)
225+
if !ok {
226+
assembleMsg := AssembleMsg(SeparateFormat, 4, "WARN", "no function named '"+funcNameFromInterface+"' was found in interface 'opensergo-go/pkg/logging/Logger'", nil, false)
227+
logger.Print(assembleMsg)
228+
return
229+
}
230+
231+
keysAndValuesLen := len(keysAndValues)
232+
params := make([]reflect.Value, 0)
233+
params = append(params, reflect.ValueOf(logger))
234+
if "Error" == funcNameFromInterface {
235+
if err == nil {
236+
err = errors.New("")
237+
}
238+
params = append(params, reflect.ValueOf(err))
239+
}
240+
params = append(params, reflect.ValueOf(msg))
241+
242+
if keysAndValuesLen != 0 {
243+
if keysAndValuesLen == 1 && keysAndValues[0] == nil {
244+
245+
} else {
246+
for _, keyOrValue := range keysAndValues {
247+
params = append(params, reflect.ValueOf(keyOrValue))
248+
}
249+
}
250+
}
251+
method.Func.Call(params)
252+
}

0 commit comments

Comments
 (0)