-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #66 from Frontman-Labs/init-logger
feat(logger): add structured logging wrapper for zap
- Loading branch information
Showing
7 changed files
with
234 additions
and
22 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,68 @@ | ||
package log | ||
|
||
import "fmt" | ||
|
||
type logLevel string | ||
|
||
const ( | ||
InfoLevel logLevel = "info" | ||
DebugLevel logLevel = "debug" | ||
WarnLevel logLevel = "warn" | ||
ErrorLevel logLevel = "error" | ||
) | ||
|
||
type Logger interface { | ||
Debug(args ...interface{}) | ||
Debugf(format string, args ...interface{}) | ||
Info(args ...interface{}) | ||
Infof(format string, args ...interface{}) | ||
Error(args ...interface{}) | ||
Errorf(format string, args ...interface{}) | ||
Warn(args ...interface{}) | ||
Warnf(format string, args ...interface{}) | ||
Fatal(args ...interface{}) | ||
Fatalf(format string, args ...interface{}) | ||
WithFields(level logLevel, msg string, fields ...Field) | ||
} | ||
|
||
// Field used for structured logging | ||
type Field struct { | ||
key string | ||
value string | ||
} | ||
|
||
func String(key string, value string) Field { | ||
return Field{ | ||
key: key, | ||
value: value, | ||
} | ||
} | ||
|
||
func Error(value string) Field { | ||
return Field{ | ||
key: "err", | ||
value: value, | ||
} | ||
} | ||
|
||
func ParseLevel(str string) logLevel { | ||
var lvl logLevel | ||
lvl.unmarshalString(str) | ||
return lvl | ||
} | ||
|
||
func (l *logLevel) unmarshalString(str string) { | ||
switch str { | ||
case "debug", "DEBUG": | ||
*l = DebugLevel | ||
case "info", "INFO", "": // make the zero value useful | ||
*l = InfoLevel | ||
case "warn", "WARN": | ||
*l = WarnLevel | ||
case "error", "ERROR": | ||
*l = ErrorLevel | ||
default: | ||
fmt.Println("unknown log level ", str, " proceeding with log levle Info") | ||
*l = InfoLevel | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
package log | ||
|
||
import ( | ||
"testing" | ||
) | ||
|
||
func TestLogger(t *testing.T) { | ||
logger, err := NewDefaultLogger("debug") | ||
if err != nil { | ||
t.Error(err) | ||
} | ||
// For illustrative purposes | ||
logger.Info("basic ", "logging") | ||
logger.Infof("info formatted log: %s to %d", "I can count", 123) | ||
logger.Debug("basic ", "logging") | ||
logger.Debugf("debug formatted log: %s to %d", "I can count", 123) | ||
logger.Error("basic ", "logging") | ||
logger.Errorf("error formatted log: %s to %d", "I could not count", 123) | ||
logger.WithFields(ErrorLevel, "unexpected traffic received", Error("terrible error message")) | ||
logger.WithFields(InfoLevel, "ingress traffic received", String("url", "https://github.com/Frontman-Labs/frontman"), String("host", "162.1.3.2"), String("port", "32133")) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,90 @@ | ||
package log | ||
|
||
import ( | ||
"os" | ||
|
||
"go.uber.org/zap" | ||
"go.uber.org/zap/zapcore" | ||
) | ||
|
||
type ZapLogger struct { | ||
zap *zap.Logger | ||
sugarZap *zap.SugaredLogger | ||
} | ||
|
||
func (l ZapLogger) Debugf(format string, args ...interface{}) { | ||
l.sugarZap.Debugf(format, args...) | ||
} | ||
|
||
func (l ZapLogger) Debug(args ...interface{}) { | ||
l.sugarZap.Debug(args...) | ||
} | ||
|
||
func (l ZapLogger) Fatalf(format string, args ...interface{}) { | ||
l.sugarZap.Fatalf(format, args...) | ||
} | ||
|
||
func (l ZapLogger) Fatal(args ...interface{}) { | ||
l.sugarZap.Fatal(args...) | ||
} | ||
|
||
func (l ZapLogger) Infof(format string, args ...interface{}) { | ||
l.sugarZap.Infof(format, args...) | ||
} | ||
|
||
func (l ZapLogger) Info(args ...interface{}) { | ||
l.sugarZap.Info(args...) | ||
} | ||
|
||
func (l ZapLogger) Warnf(format string, args ...interface{}) { | ||
l.sugarZap.Warnf(format, args...) | ||
} | ||
|
||
func (l ZapLogger) Warn(args ...interface{}) { | ||
l.sugarZap.Warn(args...) | ||
} | ||
func (l ZapLogger) Errorf(format string, args ...interface{}) { | ||
l.sugarZap.Errorf(format, args...) | ||
} | ||
|
||
func (l ZapLogger) Error(args ...interface{}) { | ||
l.sugarZap.Error(args...) | ||
} | ||
|
||
func fieldsToZap(fields ...Field) (zfields []zapcore.Field) { | ||
for _, field := range fields { | ||
zfields = append(zfields, zap.String(field.key, field.value)) | ||
} | ||
return zfields | ||
} | ||
|
||
func (l ZapLogger) WithFields(level logLevel, msg string, fields ...Field) { | ||
lvl, err := zapcore.ParseLevel(string(level)) | ||
if err != nil { | ||
l.Fatalf("Unknown log level: %s", level) | ||
os.Exit(1) | ||
} | ||
l.zap.Log(lvl, msg, fieldsToZap(fields...)...) | ||
} | ||
|
||
func NewZapLogger(level logLevel) (Logger, error) { | ||
cfg := zap.NewProductionConfig() | ||
lvl, err := zapcore.ParseLevel(string(level)) | ||
if err != nil { | ||
return nil, err | ||
} | ||
cfg.Level = zap.NewAtomicLevelAt(lvl) | ||
zap, err := cfg.Build(zap.AddCallerSkip(1)) | ||
if err != nil { | ||
return nil, err | ||
} | ||
logger := &ZapLogger{ | ||
zap: zap, | ||
sugarZap: zap.Sugar(), | ||
} | ||
return logger, nil | ||
} | ||
|
||
func NewDefaultLogger(level logLevel) (Logger, error) { | ||
return NewZapLogger(level) | ||
} |