Skip to content

Commit

Permalink
✨ add AccessLogInterceptor (UnaryInterceptor)
Browse files Browse the repository at this point in the history
Signed-off-by: Rintaro Okamura <[email protected]>
  • Loading branch information
rinx committed Nov 25, 2020
1 parent b3a8d01 commit 55b731a
Show file tree
Hide file tree
Showing 5 changed files with 1,655 additions and 15 deletions.
226 changes: 226 additions & 0 deletions internal/log/zap/option_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,226 @@
//
// Copyright (C) 2019-2020 Vdaas.org Vald team ( kpango, rinx, kmrmt )
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
package zap

import (
"reflect"
"testing"

"github.com/vdaas/vald/internal/errors"
"github.com/vdaas/vald/internal/log/format"
"github.com/vdaas/vald/internal/log/level"
"go.uber.org/goleak"
)

func TestWithLevel(t *testing.T) {
type T = logger
type args struct {
lv string
}
type want struct {
obj *T
}
type test struct {
name string
args args
want want
checkFunc func(want, *T) error
beforeFunc func(args)
afterFunc func(args)
}

defaultCheckFunc := func(w want, obj *T) error {
if !reflect.DeepEqual(obj, w.obj) {
return errors.Errorf("got: \"%#v\",\n\t\t\t\twant: \"%#v\"", obj, w.obj)
}
return nil
}

tests := []test{
{
name: "do nothing if lv is empty string",
args: args{
lv: "",
},
want: want{
obj: new(T),
},
},
{
name: "if lv is debug, DEBUG level will be set",
args: args{
lv: "debug",
},
want: want{
obj: &T{
level: level.DEBUG,
},
},
},
}

for _, test := range tests {
t.Run(test.name, func(tt *testing.T) {
defer goleak.VerifyNone(tt)
if test.beforeFunc != nil {
test.beforeFunc(test.args)
}
if test.afterFunc != nil {
defer test.afterFunc(test.args)
}

if test.checkFunc == nil {
test.checkFunc = defaultCheckFunc
}
got := WithLevel(test.args.lv)
obj := new(T)
got(obj)
if err := test.checkFunc(test.want, obj); err != nil {
tt.Errorf("error = %v", err)
}
})
}
}

func TestWithFormat(t *testing.T) {
type T = logger
type args struct {
fmt string
}
type want struct {
obj *T
}
type test struct {
name string
args args
want want
checkFunc func(want, *T) error
beforeFunc func(args)
afterFunc func(args)
}

defaultCheckFunc := func(w want, obj *T) error {
if !reflect.DeepEqual(obj, w.obj) {
return errors.Errorf("got: \"%#v\",\n\t\t\t\twant: \"%#v\"", obj, w.obj)
}
return nil
}

tests := []test{
{
name: "do nothing if fmt is empty string",
args: args{
fmt: "",
},
want: want{
obj: new(T),
},
},
{
name: "if fmt is json, JSON format will be set",
args: args{
fmt: "json",
},
want: want{
obj: &T{
format: format.JSON,
},
},
},
}

for _, test := range tests {
t.Run(test.name, func(tt *testing.T) {
defer goleak.VerifyNone(tt)
if test.beforeFunc != nil {
test.beforeFunc(test.args)
}
if test.afterFunc != nil {
defer test.afterFunc(test.args)
}
if test.checkFunc == nil {
test.checkFunc = defaultCheckFunc
}
got := WithFormat(test.args.fmt)
obj := new(T)
got(obj)
if err := test.checkFunc(test.want, obj); err != nil {
tt.Errorf("error = %v", err)
}
})
}
}

func TestWithCaller(t *testing.T) {
type T = logger
type args struct {
enable bool
}
type want struct {
obj *T
}
type test struct {
name string
args args
want want
checkFunc func(want, *T) error
beforeFunc func(args)
afterFunc func(args)
}

defaultCheckFunc := func(w want, obj *T) error {
if !reflect.DeepEqual(obj, w.obj) {
return errors.Errorf("got: \"%#v\",\n\t\t\t\twant: \"%#v\"", obj, w.obj)
}
return nil
}

tests := []test{
{
name: "given value will be set to enableCaller field",
args: args{
enable: true,
},
want: want{
obj: &T{
enableCaller: true,
},
},
},
}

for _, test := range tests {
t.Run(test.name, func(tt *testing.T) {
defer goleak.VerifyNone(tt)
if test.beforeFunc != nil {
test.beforeFunc(test.args)
}
if test.afterFunc != nil {
defer test.afterFunc(test.args)
}

if test.checkFunc == nil {
test.checkFunc = defaultCheckFunc
}
got := WithCaller(test.args.enable)
obj := new(T)
got(obj)
if err := test.checkFunc(test.want, obj); err != nil {
tt.Errorf("error = %v", err)
}
})
}
}
59 changes: 45 additions & 14 deletions internal/log/zap/zap.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,13 @@ import (

const (
detailsKey = "details"

defaultLevel = zapcore.DebugLevel
)

var (
zapcore_NewConsoleEncoder = zapcore.NewConsoleEncoder
zapcore_NewJSONEncoder = zapcore.NewJSONEncoder
)

type logger struct {
Expand All @@ -44,27 +51,42 @@ func New(opts ...Option) (*logger, error) {
opt(l)
}

err := l.initialize()
err := l.initialize("stdout", "stderr")
if err != nil {
return nil, err
}

return l, nil
}

func (l *logger) initialize() (err error) {
cfg := zap.NewProductionConfig()

cfg.Level.SetLevel(toZapLevel(l.level))
cfg.Encoding = toZapEncoder(l.format)

cfg.DisableCaller = !l.enableCaller
func (l *logger) initialize(sinkPath, errSinkPath string) (err error) {
sink, closeOut, err := zap.Open(sinkPath)
if err != nil {
return err
}

l.logger, err = cfg.Build()
errSink, _, err := zap.Open(errSinkPath)
if err != nil {
closeOut()
return err
}

core := zapcore.NewCore(
toZapEncoder(l.format),
sink,
toZapLevel(l.level),
)

opts := []zap.Option{
zap.ErrorOutput(errSink),
}

if l.enableCaller {
opts = append(opts, zap.AddCaller())
}

l.logger = zap.New(core, opts...)

l.sugar = l.logger.Sugar()

return nil
Expand All @@ -82,19 +104,25 @@ func toZapLevel(lv level.Level) zapcore.Level {
return zapcore.ErrorLevel
case level.FATAL:
return zapcore.FatalLevel
case level.Unknown:
fallthrough
default:
return zapcore.DebugLevel
return defaultLevel
}
}

func toZapEncoder(fmt format.Format) string {
func toZapEncoder(fmt format.Format) zapcore.Encoder {
cfg := zap.NewDevelopmentEncoderConfig()

switch fmt {
case format.RAW:
return "console"
return zapcore_NewConsoleEncoder(cfg)
case format.JSON:
return "json"
return zapcore_NewJSONEncoder(cfg)
case format.Unknown:
fallthrough
default:
return "json"
return zapcore_NewJSONEncoder(cfg)
}
}

Expand All @@ -107,9 +135,12 @@ func (l *logger) log(
if msg, ok := vals[0].(string); ok {
if len(vals[1:]) == 1 {
loggerFunc(msg, zap.Any(detailsKey, vals[1]))

return
}

loggerFunc(msg, zap.Any(detailsKey, vals[1:]))

return
}
}
Expand Down
Loading

0 comments on commit 55b731a

Please sign in to comment.