-
Notifications
You must be signed in to change notification settings - Fork 8
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
/log/logr/v2: logr, zapr deps updated to v1.2.2
Note: This is a breaking change, hence versioned under /v2 to be imported as "github.com/packethost/pkg/log/logr/v2" With this change, returning *PacketLogr as a logr.Logger isn't possible, since logr.Logger is of type struct and it does not provide the methods that old logr.Logger interface would declare. https://github.com/go-logr/logr/blob/v1.2.2/logr.go#L230 https://github.com/go-logr/logr/blob/v0.4.0/logr.go#L148 The NewPacketLogr() is updated to return type *PacketLogr which embeds the logr.Logger struct type, it inherits various methods of the logr.Logger, although methods expecting a logr.Logger would need to reference the *PacketLogr.Logger struct field. The go-logr/logr v0.4.0 was an BETA API and is worth moving away from, https://github.com/go-logr/logr/blob/v0.4.0/logr.go#L20
- Loading branch information
Showing
6 changed files
with
444 additions
and
0 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
Since this is a multi module repository to ensure clients can import\ | ||
github.com/packethost/pkg/log/logr/v2 or higher releases of this module\ | ||
the repository must be tagged as `log/logr/v2.0.0` | ||
|
||
https://github.com/golang/go/wiki/Modules#is-it-possible-to-add-a-module-to-a-multi-module-repository |
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,15 @@ | ||
module github.com/packethost/pkg/log/logr/v2 | ||
|
||
go 1.16 | ||
|
||
require ( | ||
github.com/go-logr/logr v1.2.2 | ||
github.com/go-logr/zapr v1.2.2 | ||
github.com/jacobweinstock/rollzap v0.1.3 | ||
// parent module imported based on | ||
// https://github.com/golang/go/wiki/Modules#is-it-possible-to-add-a-module-to-a-multi-module-repository | ||
github.com/packethost/pkg/log/logr v0.0.0-20210106215246-8e2e62dc8f0c | ||
github.com/pkg/errors v0.9.1 | ||
github.com/rollbar/rollbar-go v1.2.0 | ||
go.uber.org/zap v1.19.0 | ||
) |
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,72 @@ | ||
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= | ||
github.com/benbjohnson/clock v1.1.0 h1:Q92kusRqC1XV2MjkWETPvjJVqKetz1OzxZB7mHJLju8= | ||
github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= | ||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= | ||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= | ||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= | ||
github.com/go-logr/logr v1.2.2 h1:ahHml/yUpnlb96Rp8HCvtYVPY8ZYpxq3g7UYchIYwbs= | ||
github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= | ||
github.com/go-logr/zapr v1.2.2 h1:5YNlIL6oZLydaV4dOFjL8YpgXF/tPeTbnpatnu3cq6o= | ||
github.com/go-logr/zapr v1.2.2/go.mod h1:eIauM6P8qSvTw5o2ez6UEAfGjQKrxQTl5EoK+Qa2oG4= | ||
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= | ||
github.com/jacobweinstock/rollzap v0.1.3 h1:9nkpwYew+JiDoMWwVIEUpFyos6hdfY3gDmaj6d+Hq9M= | ||
github.com/jacobweinstock/rollzap v0.1.3/go.mod h1:hlnp7hysC0vG3HB+EXl5k8UwCjTroVtvVNqoKUCotak= | ||
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= | ||
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= | ||
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= | ||
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= | ||
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= | ||
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= | ||
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= | ||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= | ||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= | ||
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= | ||
github.com/rollbar/rollbar-go v1.2.0 h1:CUanFtVu0sa3QZ/fBlgevdGQGLWaE3D4HxoVSQohDfo= | ||
github.com/rollbar/rollbar-go v1.2.0/go.mod h1:czC86b8U4xdUH7W2C6gomi2jutLm8qK0OtrF5WMvpcc= | ||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= | ||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= | ||
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= | ||
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= | ||
github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY= | ||
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= | ||
go.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= | ||
go.uber.org/atomic v1.7.0 h1:ADUqmZGgLDDfbSL9ZmPxKTybcoEYHgpYfELNoN+7hsw= | ||
go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= | ||
go.uber.org/goleak v1.1.10 h1:z+mqJhf6ss6BSfSM671tgKyZBFPTTJM+HLxnhPC3wu0= | ||
go.uber.org/goleak v1.1.10/go.mod h1:8a7PlsEVH3e/a/GLqe5IIrQx6GzcnRmZEufDUTk4A7A= | ||
go.uber.org/multierr v1.5.0/go.mod h1:FeouvMocqHpRaaGuG9EjoKcStLC43Zu/fmqdUMPcKYU= | ||
go.uber.org/multierr v1.6.0 h1:y6IPFStTAIT5Ytl7/XYmHvzXQ7S3g/IeZW9hyZ5thw4= | ||
go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU= | ||
go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA= | ||
go.uber.org/zap v1.16.0/go.mod h1:MA8QOfq0BHJwdXa996Y4dYkAqRKB8/1K1QMMZVaNZjQ= | ||
go.uber.org/zap v1.19.0 h1:mZQZefskPPCMIBCSEH0v2/iUqqLrYtaeqwD6FUGUnFE= | ||
go.uber.org/zap v1.19.0/go.mod h1:xg/QME4nWcxGxrpdeYfq7UvYrLh66cuVKdrbD1XF/NI= | ||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= | ||
golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= | ||
golang.org/x/lint v0.0.0-20190930215403-16217165b5de h1:5hukYrvBGR8/eNkX5mdUezrA6JiaEZDtJb9Ei+1LlBs= | ||
golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= | ||
golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= | ||
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= | ||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= | ||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= | ||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= | ||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= | ||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= | ||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= | ||
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= | ||
golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= | ||
golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= | ||
golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= | ||
golang.org/x/tools v0.0.0-20191108193012-7d206e10da11 h1:Yq9t9jnGoR+dBuitxdo9l6Q7xh/zOyNnYUtDKaQ3x0E= | ||
golang.org/x/tools v0.0.0-20191108193012-7d206e10da11/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= | ||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= | ||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= | ||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= | ||
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= | ||
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= | ||
gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10= | ||
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= | ||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= | ||
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo= | ||
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= | ||
honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= |
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,202 @@ | ||
package logr | ||
|
||
import ( | ||
"os" | ||
|
||
"github.com/go-logr/logr" | ||
"github.com/go-logr/zapr" | ||
"github.com/pkg/errors" | ||
"go.uber.org/zap" | ||
"go.uber.org/zap/zapcore" | ||
) | ||
|
||
// WithLogLevel sets the log level | ||
func WithLogLevel(level string) LoggerOption { | ||
return func(args *PacketLogr) { args.logLevel = level } | ||
} | ||
|
||
// WithOutputPaths adds output paths | ||
func WithOutputPaths(paths []string) LoggerOption { | ||
return func(args *PacketLogr) { args.outputPaths = paths } | ||
} | ||
|
||
// WithServiceName adds a service name a logged field | ||
func WithServiceName(name string) LoggerOption { | ||
return func(args *PacketLogr) { args.serviceName = name } | ||
} | ||
|
||
// WithKeysAndValues adds extra key/value fields | ||
func WithKeysAndValues(kvs []interface{}) LoggerOption { | ||
return func(args *PacketLogr) { args.keysAndValues = append(args.keysAndValues, kvs...) } | ||
} | ||
|
||
// WithEnableErrLogsToStderr sends .Error logs to stderr | ||
func WithEnableErrLogsToStderr(enable bool) LoggerOption { | ||
return func(args *PacketLogr) { args.enableErrLogsToStderr = enable } | ||
} | ||
|
||
// WithEnableRollbar sends error logs to Rollbar service | ||
func WithEnableRollbar(enable bool) LoggerOption { | ||
return func(args *PacketLogr) { args.enableRollbar = enable } | ||
} | ||
|
||
// WithRollbarConfig customizes the Rollbar details | ||
func WithRollbarConfig(config rollbarConfig) LoggerOption { | ||
return func(args *PacketLogr) { args.rollbarConfig = config } | ||
} | ||
|
||
// PacketLogr is a wrapper around zap.SugaredLogger | ||
type PacketLogr struct { | ||
logr.Logger | ||
logLevel string | ||
outputPaths []string | ||
serviceName string | ||
keysAndValues []interface{} | ||
enableErrLogsToStderr bool | ||
enableRollbar bool | ||
rollbarConfig rollbarConfig | ||
} | ||
|
||
// LoggerOption for setting optional values | ||
type LoggerOption func(*PacketLogr) | ||
|
||
// NewPacketLogr is the opionated packet logger setup | ||
func NewPacketLogr(opts ...LoggerOption) (*PacketLogr, *zap.Logger, error) { | ||
// defaults | ||
const ( | ||
defaultLogLevel = "info" | ||
defaultServiceName = "not/set" | ||
) | ||
var ( | ||
defaultOutputPaths = []string{"stdout"} | ||
defaultKeysAndValues = []interface{}{} | ||
zapConfig = zap.NewProductionConfig() | ||
zLevel = zap.InfoLevel | ||
defaultZapOpts = []zap.Option{} | ||
rollbarOptions zap.Option | ||
defaultRollbarConfig = rollbarConfig{ | ||
token: "123", | ||
env: "production", | ||
version: "1", | ||
} | ||
) | ||
|
||
pl := &PacketLogr{ | ||
Logger: logr.Logger{}, | ||
logLevel: defaultLogLevel, | ||
outputPaths: defaultOutputPaths, | ||
serviceName: defaultServiceName, | ||
keysAndValues: defaultKeysAndValues, | ||
enableRollbar: false, | ||
rollbarConfig: defaultRollbarConfig, | ||
} | ||
|
||
for _, opt := range opts { | ||
opt(pl) | ||
} | ||
|
||
switch pl.logLevel { | ||
case "debug": | ||
zLevel = zap.DebugLevel | ||
} | ||
zapConfig.Level = zap.NewAtomicLevelAt(zLevel) | ||
zapConfig.OutputPaths = sliceDedupe(pl.outputPaths) | ||
|
||
if pl.enableErrLogsToStderr { | ||
defaultZapOpts = append(defaultZapOpts, errLogsToStderr(zapConfig)) | ||
} | ||
|
||
zapLogger, err := zapConfig.Build(defaultZapOpts...) | ||
if err != nil { | ||
return pl, zapLogger, errors.Wrap(err, "failed to build logger config") | ||
} | ||
if pl.enableRollbar { | ||
rollbarOptions = pl.rollbarConfig.setupRollbar(pl.serviceName, zapLogger) | ||
zapLogger = zapLogger.WithOptions(rollbarOptions) | ||
} | ||
keysAndValues := append(pl.keysAndValues, "service", pl.serviceName) | ||
zapLogger = zapLogger.With(handleFields(zapLogger, keysAndValues)...) | ||
pl.Logger = zapr.NewLogger(zapLogger) | ||
return pl, zapLogger, err | ||
} | ||
|
||
func sliceDedupe(elements []string) []string { | ||
encountered := map[string]bool{} | ||
result := []string{} | ||
|
||
for v := range elements { | ||
if encountered[elements[v]] { | ||
} else { | ||
encountered[elements[v]] = true | ||
result = append(result, elements[v]) | ||
} | ||
} | ||
return result | ||
} | ||
|
||
func errLogsToStderr(c zap.Config) zap.Option { | ||
errorLogs := zap.LevelEnablerFunc(func(lvl zapcore.Level) bool { | ||
return lvl >= zapcore.ErrorLevel | ||
}) | ||
nonErrorLogs := zap.LevelEnablerFunc(func(lvl zapcore.Level) bool { | ||
return !errorLogs(lvl) | ||
}) | ||
console := zapcore.Lock(os.Stdout) | ||
consoleErrors := zapcore.Lock(os.Stderr) | ||
encoder := zapcore.NewJSONEncoder(c.EncoderConfig) | ||
|
||
core := zapcore.NewTee( | ||
zapcore.NewCore(encoder, console, nonErrorLogs), | ||
zapcore.NewCore(encoder, consoleErrors, errorLogs), | ||
) | ||
splitLogger := zap.WrapCore(func(c zapcore.Core) zapcore.Core { | ||
return core | ||
|
||
}) | ||
return splitLogger | ||
} | ||
|
||
// handleFields converts a bunch of arbitrary key-value pairs into Zap fields. It takes | ||
// additional pre-converted Zap fields, for use with automatically attached fields, like | ||
// `error`. copy/paste from https://github.com/go-logr/zapr/blob/146009e52d528183a25bf1a1e3cf56d1ff3919b5/zapr.go#L79 | ||
func handleFields(l *zap.Logger, args []interface{}, additional ...zap.Field) []zap.Field { | ||
// a slightly modified version of zap.SugaredLogger.sweetenFields | ||
if len(args) == 0 { | ||
// fast-return if we have no suggared fields. | ||
return additional | ||
} | ||
|
||
// unlike Zap, we can be pretty sure users aren't passing structured | ||
// fields (since logr has no concept of that), so guess that we need a | ||
// little less space. | ||
fields := make([]zap.Field, 0, len(args)/2+len(additional)) | ||
for i := 0; i < len(args); { | ||
// check just in case for strongly-typed Zap fields, which is illegal (since | ||
// it breaks implementation agnosticism), so we can give a better error message. | ||
if _, ok := args[i].(zap.Field); ok { | ||
l.DPanic("strongly-typed Zap Field passed to logr", zap.Any("zap field", args[i])) | ||
break | ||
} | ||
|
||
// make sure this isn't a mismatched key | ||
if i == len(args)-1 { | ||
l.DPanic("odd number of arguments passed as key-value pairs for logging", zap.Any("ignored key", args[i])) | ||
break | ||
} | ||
|
||
// process a key-value pair, | ||
// ensuring that the key is a string | ||
key, val := args[i], args[i+1] | ||
keyStr, isString := key.(string) | ||
if !isString { | ||
// if the key isn't a string, DPanic and stop logging | ||
l.DPanic("non-string key argument passed to logging, ignoring all later arguments", zap.Any("invalid key", key)) | ||
break | ||
} | ||
|
||
fields = append(fields, zap.Any(keyStr, val)) | ||
i += 2 | ||
} | ||
|
||
return append(fields, additional...) | ||
} |
Oops, something went wrong.