Skip to content

Commit

Permalink
Merge pull request #45 from gatewayd-io/add-logging-adapter
Browse files Browse the repository at this point in the history
Add logging adapter for the plugin system
  • Loading branch information
mostafa authored Dec 13, 2022
2 parents 6a4ba89 + 6c17a97 commit e84ee33
Show file tree
Hide file tree
Showing 4 changed files with 230 additions and 11 deletions.
8 changes: 1 addition & 7 deletions cmd/run.go
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ var runCmd = &cobra.Command{
// Create a new logger from the config
loggerCfg := loggerConfig()
logger := logging.NewLogger(loggerCfg)
// TODO: Use https://github.com/dcarbone/zadapters to adapt hclog to zerolog

// This is a notification hook, so we don't care about the result.
data, err := structpb.NewStruct(map[string]interface{}{
"timeFormat": loggerCfg.TimeFormat,
Expand Down Expand Up @@ -215,12 +215,6 @@ var runCmd = &cobra.Command{
// Internal event-loop load balancing options
gnet.WithLoadBalancing(serverConfig.LoadBalancer),

// Logger options
// TODO: This is a temporary solution and will be replaced.
// gnet.WithLogger(logrus.New()),
// gnet.WithLogPath("./gnet.log"),
// gnet.WithLogLevel(zapcore.DebugLevel),

// Buffer options
gnet.WithReadBufferCap(serverConfig.ReadBufferCap),
gnet.WithWriteBufferCap(serverConfig.WriteBufferCap),
Expand Down
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ go 1.19
require (
github.com/fergusstrange/embedded-postgres v1.19.0
github.com/google/go-cmp v0.5.9
github.com/hashicorp/go-hclog v1.4.0
github.com/hashicorp/go-plugin v1.4.8
github.com/knadh/koanf v1.4.4
github.com/mitchellh/mapstructure v1.5.0
Expand All @@ -21,7 +22,6 @@ require (
github.com/fatih/color v1.13.0 // indirect
github.com/fsnotify/fsnotify v1.4.9 // indirect
github.com/golang/protobuf v1.5.2 // indirect
github.com/hashicorp/go-hclog v1.4.0 // indirect
github.com/hashicorp/yamux v0.1.1 // indirect
github.com/inconshreveable/mousetrap v1.1.0 // indirect
github.com/lib/pq v1.10.7 // indirect
Expand Down
220 changes: 220 additions & 0 deletions logging/hclog_adapter.go
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
}
11 changes: 8 additions & 3 deletions plugin/registry.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"context"
"os/exec"

"github.com/gatewayd-io/gatewayd/logging"
pluginV1 "github.com/gatewayd-io/gatewayd/plugin/v1"
"github.com/gatewayd-io/gatewayd/pool"
goplugin "github.com/hashicorp/go-plugin"
Expand All @@ -13,9 +14,10 @@ import (
)

const (
DefaultMinPort uint = 50000
DefaultMaxPort uint = 60000
PluginPriorityStart uint = 1000
DefaultMinPort uint = 50000
DefaultMaxPort uint = 60000
PluginPriorityStart uint = 1000
LoggerName string = "plugin"
)

var handshakeConfig = goplugin.HandshakeConfig{
Expand Down Expand Up @@ -140,6 +142,8 @@ func (reg *RegistryImpl) LoadPlugins(pluginConfig *koanf.Koanf) {
// have a priority of 0 to 999, and user-defined plugins have a priority of 1000 or greater.
plugin.Priority = Priority(PluginPriorityStart + uint(priority))

logAdapter := logging.NewHcLogAdapter(&reg.hooksConfig.Logger, LoggerName)

plugin.client = goplugin.NewClient(
&goplugin.ClientConfig{
HandshakeConfig: handshakeConfig,
Expand All @@ -149,6 +153,7 @@ func (reg *RegistryImpl) LoadPlugins(pluginConfig *koanf.Koanf) {
goplugin.ProtocolGRPC,
},
// SecureConfig: nil,
Logger: logAdapter,
Managed: true,
MinPort: DefaultMinPort,
MaxPort: DefaultMaxPort,
Expand Down

0 comments on commit e84ee33

Please sign in to comment.