-
Notifications
You must be signed in to change notification settings - Fork 18
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 #45 from gatewayd-io/add-logging-adapter
Add logging adapter for the plugin system
- Loading branch information
Showing
4 changed files
with
230 additions
and
11 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,220 @@ | ||
package logging | ||
|
||
import ( | ||
"fmt" | ||
"io" | ||
"log" | ||
"reflect" | ||
|
||
"github.com/hashicorp/go-hclog" | ||
"github.com/rs/zerolog" | ||
) | ||
|
||
// NewHcLogAdapter creates a new hclog.Logger that wraps a zerolog.Logger. | ||
func NewHcLogAdapter(logger *zerolog.Logger, name string) hclog.Logger { | ||
return &HcLogAdapter{logger, name, nil} | ||
} | ||
|
||
type HcLogAdapter struct { | ||
logger *zerolog.Logger | ||
name string | ||
|
||
impliedArgs []interface{} | ||
} | ||
|
||
func (h HcLogAdapter) Log(level hclog.Level, msg string, args ...interface{}) { | ||
switch level { | ||
case hclog.Off: | ||
return | ||
case hclog.NoLevel: | ||
return | ||
case hclog.Trace: | ||
h.Trace(msg, args...) | ||
case hclog.Debug: | ||
h.Debug(msg, args...) | ||
case hclog.Info: | ||
h.Info(msg, args...) | ||
case hclog.Warn: | ||
h.Warn(msg, args...) | ||
case hclog.Error: | ||
h.Error(msg, args...) | ||
} | ||
} | ||
|
||
func (h HcLogAdapter) Trace(msg string, args ...interface{}) { | ||
h.logger.Trace().Fields(ToMap(args)).Msg(msg) | ||
} | ||
|
||
func (h HcLogAdapter) Debug(msg string, args ...interface{}) { | ||
h.logger.Debug().Fields(ToMap(args)).Msg(msg) | ||
} | ||
|
||
func (h HcLogAdapter) Info(msg string, args ...interface{}) { | ||
h.logger.Info().Fields(ToMap(args)).Msg(msg) | ||
} | ||
|
||
func (h HcLogAdapter) Warn(msg string, args ...interface{}) { | ||
h.logger.Warn().Fields(ToMap(args)).Msg(msg) | ||
} | ||
|
||
func (h HcLogAdapter) Error(msg string, args ...interface{}) { | ||
h.logger.Error().Fields(ToMap(args)).Msg(msg) | ||
} | ||
|
||
func (h HcLogAdapter) GetLevel() hclog.Level { | ||
switch h.logger.GetLevel() { | ||
case zerolog.Disabled: | ||
return hclog.Off | ||
case zerolog.NoLevel: | ||
return hclog.NoLevel | ||
case zerolog.TraceLevel: | ||
return hclog.Trace | ||
case zerolog.DebugLevel: | ||
return hclog.Debug | ||
case zerolog.InfoLevel: | ||
return hclog.Info | ||
case zerolog.WarnLevel: | ||
return hclog.Warn | ||
case zerolog.ErrorLevel: | ||
return hclog.Error | ||
case zerolog.FatalLevel: | ||
return hclog.Error | ||
case zerolog.PanicLevel: | ||
return hclog.Error | ||
} | ||
return hclog.NoLevel | ||
} | ||
|
||
func (h HcLogAdapter) IsTrace() bool { | ||
return h.logger.GetLevel() >= zerolog.TraceLevel | ||
} | ||
|
||
func (h HcLogAdapter) IsDebug() bool { | ||
return h.logger.GetLevel() >= zerolog.DebugLevel | ||
} | ||
|
||
func (h HcLogAdapter) IsInfo() bool { | ||
return h.logger.GetLevel() >= zerolog.InfoLevel | ||
} | ||
|
||
func (h HcLogAdapter) IsWarn() bool { | ||
return h.logger.GetLevel() >= zerolog.WarnLevel | ||
} | ||
|
||
func (h HcLogAdapter) IsError() bool { | ||
return h.logger.GetLevel() >= zerolog.ErrorLevel | ||
} | ||
|
||
func (h HcLogAdapter) ImpliedArgs() []interface{} { | ||
// Not supported | ||
return nil | ||
} | ||
|
||
func (h HcLogAdapter) With(args ...interface{}) hclog.Logger { | ||
logger := h.logger.With().Fields(ToMap(args)).Logger() | ||
return NewHcLogAdapter(&logger, h.Name()) | ||
} | ||
|
||
func (h HcLogAdapter) Name() string { | ||
return h.name | ||
} | ||
|
||
func (h HcLogAdapter) Named(name string) hclog.Logger { | ||
return NewHcLogAdapter(h.logger, name) | ||
} | ||
|
||
func (h HcLogAdapter) ResetNamed(name string) hclog.Logger { | ||
return &h | ||
} | ||
|
||
func (h *HcLogAdapter) SetLevel(level hclog.Level) { | ||
leveledLog := h.logger.Level(convertLevel(level)) | ||
h.logger = &leveledLog | ||
} | ||
|
||
func (h HcLogAdapter) StandardLogger(opts *hclog.StandardLoggerOptions) *log.Logger { | ||
if opts == nil { | ||
opts = &hclog.StandardLoggerOptions{} | ||
} | ||
return log.New(h.StandardWriter(opts), "", 0) | ||
} | ||
|
||
func (h HcLogAdapter) StandardWriter(opts *hclog.StandardLoggerOptions) io.Writer { | ||
v := reflect.ValueOf(h.logger) | ||
w := v.FieldByName("w") | ||
writer, ok := w.Interface().(zerolog.LevelWriter) | ||
if !ok { | ||
return nil | ||
} | ||
return writer | ||
} | ||
|
||
func convertLevel(level hclog.Level) zerolog.Level { | ||
switch level { | ||
case hclog.Off: | ||
return zerolog.Disabled | ||
case hclog.NoLevel: | ||
return zerolog.NoLevel | ||
case hclog.Trace: | ||
return zerolog.TraceLevel | ||
case hclog.Debug: | ||
return zerolog.DebugLevel | ||
case hclog.Info: | ||
return zerolog.InfoLevel | ||
case hclog.Warn: | ||
return zerolog.WarnLevel | ||
case hclog.Error: | ||
return zerolog.ErrorLevel | ||
} | ||
return zerolog.NoLevel | ||
} | ||
|
||
func ToMap(keyValues []interface{}) map[string]interface{} { | ||
mapped := map[string]interface{}{} | ||
|
||
if len(keyValues) == 0 { | ||
return mapped | ||
} | ||
|
||
if len(keyValues)%2 == 1 { | ||
keyValues = append(keyValues, nil) | ||
} | ||
|
||
for i := 0; i < len(keyValues); i += 2 { | ||
merge(mapped, keyValues[i], keyValues[i+1]) | ||
} | ||
|
||
return mapped | ||
} | ||
|
||
func merge(mapped map[string]interface{}, key, value interface{}) { | ||
var casted string | ||
|
||
switch castedKey := key.(type) { | ||
case string: | ||
casted = castedKey | ||
case fmt.Stringer: | ||
casted = safeString(castedKey) | ||
default: | ||
casted = fmt.Sprint(castedKey) | ||
} | ||
|
||
mapped[casted] = value | ||
} | ||
|
||
//nolint:nonamedreturns | ||
func safeString(str fmt.Stringer) (s string) { | ||
defer func() { | ||
if panicVal := recover(); panicVal != nil { | ||
if v := reflect.ValueOf(str); v.Kind() == reflect.Ptr && v.IsNil() { | ||
s = "NULL" | ||
} else { | ||
panic(panicVal) | ||
} | ||
} | ||
}() | ||
|
||
s = str.String() | ||
|
||
return | ||
} |
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