Skip to content

Commit

Permalink
Add zap wrapper which implements opa logger (#240)
Browse files Browse the repository at this point in the history
open-policy-agent/opa#6499

Signed-off-by: Alexander Mckenzie-Kelly <alexmk@uk.ibm.com>
  • Loading branch information
alxmk committed Dec 22, 2023
1 parent 895c4b4 commit 52ce404
Show file tree
Hide file tree
Showing 6 changed files with 210 additions and 0 deletions.
5 changes: 5 additions & 0 deletions logging/plugins/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
Plug-ins
===

This directory contains plug-in support for external logging libraries
to use as a `logging.Logger`.
11 changes: 11 additions & 0 deletions logging/plugins/ozap/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
ozap
===

ozap is a logging plug-in to wrap [zap](https://github.com/uber-go/zap)
as a [`logging.Logger`](https://pkg.go.dev/github.com/open-policy-agent/opa/logging#Logger).

```golang
opa, err := sdk.New(context.Background(), sdk.Options{
Logger: ozap.Wrap(logger, level),
})
```
14 changes: 14 additions & 0 deletions logging/plugins/ozap/go.mod
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
module github.com/open-policy-agent/contrib/logging/plugins/ozap

go 1.19

require (
github.com/open-policy-agent/opa v0.59.0
go.uber.org/zap v1.26.0
)

require (
github.com/sirupsen/logrus v1.9.3 // indirect
go.uber.org/multierr v1.10.0 // indirect
golang.org/x/sys v0.15.0 // indirect
)
24 changes: 24 additions & 0 deletions logging/plugins/ozap/go.sum
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
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/google/uuid v1.4.0 h1:MtMxsa51/r9yyhkyLsVeVt0B+BGQZzpQiTQ4eHZ8bc4=
github.com/open-policy-agent/opa v0.59.0 h1:1WFU/KUhJAr3qatm0Lf8Ea5jp10ZmlE2M07oaLiHypg=
github.com/open-policy-agent/opa v0.59.0/go.mod h1:rdJSkEc4oQ+0074/3Fsgno5bkPsYxTjU5aLNmMujIvI=
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/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ=
github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk=
go.uber.org/goleak v1.2.0 h1:xqgm/S+aQvhWFTtR0XK3Jvg7z8kGV8P4X14IzwN3Eqk=
go.uber.org/multierr v1.10.0 h1:S0h4aNzvfcFsC3dRF1jLoaov7oRaKqRGC/pUEJ2yvPQ=
go.uber.org/multierr v1.10.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y=
go.uber.org/zap v1.26.0 h1:sI7k6L95XOKS281NhVKOFCUNIvv9e0w4BF8N3u+tCRo=
go.uber.org/zap v1.26.0/go.mod h1:dtElttAiwGvoJ/vj4IwHBS/gXsEu/pZ50mUIRWuG0so=
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.15.0 h1:h48lPFYpsTvQJZF4EKyI4aLHaev3CxivZmv7yZig9pc=
golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
100 changes: 100 additions & 0 deletions logging/plugins/ozap/zap.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
package ozap

import (
"fmt"

"github.com/open-policy-agent/opa/logging"
"go.uber.org/zap"
"go.uber.org/zap/zapcore"
)

// Wrap this zap Logger and AtomicLevel as a logging.Logger.
func Wrap(log *zap.Logger, level *zap.AtomicLevel) logging.Logger {
return &Wrapper{internal: log, level: level}
}

// Wrapper implements logging.Logger for a zap Logger.
type Wrapper struct {
internal *zap.Logger
level *zap.AtomicLevel
}

// Debug logs at debug level.
func (w *Wrapper) Debug(f string, a ...interface{}) {
w.internal.Debug(fmt.Sprintf(f, a...))
}

// Info logs at info level.
func (w *Wrapper) Info(f string, a ...interface{}) {
w.internal.Info(fmt.Sprintf(f, a...))
}

// Error logs at error level.
func (w *Wrapper) Error(f string, a ...interface{}) {
w.internal.Error(fmt.Sprintf(f, a...))
}

// Warn logs at warn level.
func (w *Wrapper) Warn(f string, a ...interface{}) {
w.internal.Warn(fmt.Sprintf(f, a...))
}

// WithFields provides additional fields to include in log output.
func (w *Wrapper) WithFields(fields map[string]interface{}) logging.Logger {
return &Wrapper{
internal: w.internal.With(toZapFields(fields)...),
level: w.level,
}
}

// toZapFields converts logging format fields to zap format Fields
func toZapFields(fields map[string]interface{}) []zap.Field {
var zapFields []zap.Field
for k, v := range fields {
switch t := v.(type) {
case error:
zapFields = append(zapFields, zap.NamedError(k, t))
case string:
zapFields = append(zapFields, zap.String(k, t))
case bool:
zapFields = append(zapFields, zap.Bool(k, t))
case int:
zapFields = append(zapFields, zap.Int(k, t))
default:
zapFields = append(zapFields, zap.Any(k, v))
}
}
return zapFields
}

// SetLevel sets the logger level.
func (w *Wrapper) GetLevel() logging.Level {
switch w.internal.Level() {
case zap.ErrorLevel:
return logging.Error
case zap.WarnLevel:
return logging.Warn
case zap.DebugLevel:
return logging.Debug
default:
return logging.Info
}
}

// SetLevel sets the logger level.
func (w *Wrapper) SetLevel(l logging.Level) {
var newLevel zapcore.Level
switch l {
case logging.Error:
newLevel = zap.ErrorLevel
case logging.Warn:
newLevel = zap.WarnLevel
case logging.Info:
newLevel = zap.InfoLevel
case logging.Debug:
newLevel = zap.DebugLevel
default:
return
}
w.level.SetLevel(newLevel)
}
56 changes: 56 additions & 0 deletions logging/plugins/ozap/zap_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
package ozap

import (
"bytes"
"errors"
"log"
"strings"
"testing"

"go.uber.org/zap"
"go.uber.org/zap/zapcore"
)

func TestWrapWithFields(t *testing.T) {
tests := []struct {
name string
fields map[string]interface{}
expect []string
}{
{
name: "Ex1",
fields: map[string]interface{}{
"bad_error": errors.New("something went wrong"),
"context": "everywhere",
"panic": true,
"problems": 99,
"luftballons": int64(99),
},
expect: []string{
`"bad_error":"something went wrong"`,
`"context":"everywhere"`,
`"panic":true`,
`"problems":99`,
`"luftballons":99`,
},
},
}

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
var buf bytes.Buffer
level := zap.NewAtomicLevelAt(zap.InfoLevel)
zaplogger := zap.New(zapcore.NewCore(zapcore.NewJSONEncoder(zap.NewDevelopmentEncoderConfig()), zapcore.AddSync(&buf), zap.LevelEnablerFunc(func(lvl zapcore.Level) bool {
return lvl >= level.Level()
})))
Wrap(zaplogger, &level).WithFields(tt.fields).Info("test")
out := buf.String()
for _, e := range tt.expect {
if !strings.Contains(out, e) {
t.Fail()
log.Printf("Missing %s in %s", e, out)
}
}
})
}
}

0 comments on commit 52ce404

Please sign in to comment.