Compare commits
4 Commits
eb1708a296
...
v0.5.2
| Author | SHA1 | Date | |
|---|---|---|---|
| 24a5d3dd88 | |||
|
|
1de7cc0034 | ||
| 9a61d4b9d3 | |||
|
|
4aef5329c7 |
25
.drone.yml
25
.drone.yml
@@ -70,3 +70,28 @@ steps:
|
||||
volumes:
|
||||
- name: deps
|
||||
temp: {}
|
||||
|
||||
---
|
||||
kind: pipeline
|
||||
type: docker
|
||||
name: zap
|
||||
|
||||
steps:
|
||||
- name: test
|
||||
image: golang:1.21.5
|
||||
volumes:
|
||||
- name: deps
|
||||
path: /go/src/mod
|
||||
commands:
|
||||
- cd handler/zap
|
||||
- go test
|
||||
|
||||
- name: golangci-lint
|
||||
image: golangci/golangci-lint:v1.55
|
||||
commands:
|
||||
- cd handler/zap
|
||||
- golangci-lint run
|
||||
|
||||
volumes:
|
||||
- name: deps
|
||||
temp: {}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package field
|
||||
|
||||
import (
|
||||
"encoding"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
@@ -8,8 +9,18 @@ func NewEncoderText(opts ...func(*BaseEncoder)) BaseEncoder {
|
||||
opts = append([]func(*BaseEncoder){
|
||||
WithGropuConfig(0, 0, ' '),
|
||||
WithNullValue("<nil>"),
|
||||
WithDefaultValue(func(dst []byte, _ Encoder, val Value) []byte {
|
||||
return fmt.Appendf(dst, "%+v", val.Any())
|
||||
WithDefaultValue(func(dst []byte, enc Encoder, val Value) []byte {
|
||||
switch value := val.Any().(type) {
|
||||
case encoding.TextMarshaler:
|
||||
data, err := value.MarshalText()
|
||||
if err != nil {
|
||||
return enc.AppendValue(dst, ErrorValue(err))
|
||||
}
|
||||
|
||||
return enc.AppendValue(dst, StringValue(string(data)))
|
||||
default:
|
||||
return fmt.Appendf(dst, "%+v", val.Any())
|
||||
}
|
||||
}),
|
||||
}, opts...)
|
||||
|
||||
|
||||
@@ -10,7 +10,7 @@ import (
|
||||
|
||||
//nolint:gochecknoglobals
|
||||
var global = With(New(),
|
||||
WithCaller(KeySource, 1, false),
|
||||
WithSource(2),
|
||||
WithLevel(KeyLevel, level.Debug),
|
||||
WithExit(level.Alert),
|
||||
WithPanic(level.Emergency),
|
||||
|
||||
24
global_example_test.go
Normal file
24
global_example_test.go
Normal file
@@ -0,0 +1,24 @@
|
||||
package log_test
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"gitoa.ru/go-4devs/log"
|
||||
"gitoa.ru/go-4devs/log/level"
|
||||
)
|
||||
|
||||
func ExampleDebug() {
|
||||
logger := log.With(log.New(log.WithStdout()),
|
||||
log.WithSource(2),
|
||||
log.WithLevel(log.KeyLevel, level.Debug),
|
||||
log.WithExit(level.Alert),
|
||||
log.WithPanic(level.Emergency),
|
||||
)
|
||||
|
||||
log.SetLogger(logger)
|
||||
|
||||
ctx := context.Background()
|
||||
log.Debug(ctx, "debug message")
|
||||
// Output:
|
||||
// msg="debug message" source=global_example_test.go:21 level=debug
|
||||
}
|
||||
10
handler/zap/go.mod
Normal file
10
handler/zap/go.mod
Normal file
@@ -0,0 +1,10 @@
|
||||
module gitoa.ru/go-4devs/log/handler/zap
|
||||
|
||||
go 1.21.5
|
||||
|
||||
require (
|
||||
gitoa.ru/go-4devs/log v0.5.1
|
||||
go.uber.org/zap v1.26.0
|
||||
)
|
||||
|
||||
require go.uber.org/multierr v1.10.0 // indirect
|
||||
16
handler/zap/go.sum
Normal file
16
handler/zap/go.sum
Normal file
@@ -0,0 +1,16 @@
|
||||
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/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk=
|
||||
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
|
||||
gitoa.ru/go-4devs/log v0.5.1 h1:rrIyjpUaw8AjDCf7ZuH0HgCRf370O3TV29yrU1xizWM=
|
||||
gitoa.ru/go-4devs/log v0.5.1/go.mod h1:tREtjEH2cTHl0p3uCVcH9g5tlqtsVNI/tDQVfq53Ty4=
|
||||
go.uber.org/goleak v1.2.0 h1:xqgm/S+aQvhWFTtR0XK3Jvg7z8kGV8P4X14IzwN3Eqk=
|
||||
go.uber.org/goleak v1.2.0/go.mod h1:XJYK+MuIchqpmGmUSAzotztawfKvYLUIgg7guXrwVUo=
|
||||
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=
|
||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
66
handler/zap/logger.go
Normal file
66
handler/zap/logger.go
Normal file
@@ -0,0 +1,66 @@
|
||||
package zap
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"gitoa.ru/go-4devs/log"
|
||||
"gitoa.ru/go-4devs/log/entry"
|
||||
"gitoa.ru/go-4devs/log/field"
|
||||
"gitoa.ru/go-4devs/log/level"
|
||||
"go.uber.org/zap"
|
||||
)
|
||||
|
||||
func Nop() log.Logger {
|
||||
return New(zap.NewNop())
|
||||
}
|
||||
|
||||
func Example(options ...zap.Option) log.Logger {
|
||||
return New(zap.NewExample(options...))
|
||||
}
|
||||
|
||||
func Production(options ...zap.Option) log.Logger {
|
||||
z, err := zap.NewProduction(options...)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
return New(z)
|
||||
}
|
||||
|
||||
func Development(options ...zap.Option) log.Logger {
|
||||
z, err := zap.NewDevelopment(options...)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
return New(z)
|
||||
}
|
||||
|
||||
// New create handler by zap logger.
|
||||
func New(logger *zap.Logger) log.Logger {
|
||||
return func(ctx context.Context, data *entry.Entry) (int, error) {
|
||||
zf := make([]zap.Field, 0, data.Fields().Len())
|
||||
data.Fields().Fields(func(f field.Field) bool {
|
||||
zf = append(zf, zap.Any(f.Key, f.Value.Any()))
|
||||
|
||||
return true
|
||||
})
|
||||
|
||||
switch data.Level() {
|
||||
case level.Emergency:
|
||||
logger.Fatal(data.Message(), zf...)
|
||||
case level.Alert:
|
||||
logger.Panic(data.Message(), zf...)
|
||||
case level.Critical, level.Error:
|
||||
logger.Error(data.Message(), zf...)
|
||||
case level.Warning:
|
||||
logger.Warn(data.Message(), zf...)
|
||||
case level.Notice, level.Info:
|
||||
logger.Info(data.Message(), zf...)
|
||||
case level.Debug:
|
||||
logger.Debug(data.Message(), zf...)
|
||||
}
|
||||
|
||||
return 0, nil
|
||||
}
|
||||
}
|
||||
23
handler/zap/logger_example_test.go
Normal file
23
handler/zap/logger_example_test.go
Normal file
@@ -0,0 +1,23 @@
|
||||
package zap_test
|
||||
|
||||
import (
|
||||
"context"
|
||||
"io"
|
||||
|
||||
"gitoa.ru/go-4devs/log/field"
|
||||
"gitoa.ru/go-4devs/log/handler/zap"
|
||||
uzap "go.uber.org/zap"
|
||||
)
|
||||
|
||||
func ExampleNew_zapHandler() {
|
||||
ctx := context.Background()
|
||||
log := zap.New(uzap.NewExample())
|
||||
log.Err(ctx, "log zap")
|
||||
log.ErrKV(ctx, "log zap kv", field.Int("int", 42))
|
||||
log.ErrKVs(ctx, "log zap kv sugar", "err", io.EOF)
|
||||
|
||||
// Output:
|
||||
// {"level":"error","msg":"log zap"}
|
||||
// {"level":"error","msg":"log zap kv","int":42}
|
||||
// {"level":"error","msg":"log zap kv sugar","err":"EOF"}
|
||||
}
|
||||
43
handler/zap/logger_test.go
Normal file
43
handler/zap/logger_test.go
Normal file
@@ -0,0 +1,43 @@
|
||||
package zap_test
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"testing"
|
||||
|
||||
"gitoa.ru/go-4devs/log/entry"
|
||||
"gitoa.ru/go-4devs/log/field"
|
||||
zlog "gitoa.ru/go-4devs/log/handler/zap"
|
||||
"gitoa.ru/go-4devs/log/level"
|
||||
"go.uber.org/zap"
|
||||
"go.uber.org/zap/zapcore"
|
||||
)
|
||||
|
||||
func TestNew(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
ctx := context.Background()
|
||||
buf := &bytes.Buffer{}
|
||||
core := zapcore.NewCore(zapcore.NewJSONEncoder(zapcore.EncoderConfig{
|
||||
MessageKey: "msg",
|
||||
LevelKey: "level",
|
||||
NameKey: "logger",
|
||||
EncodeLevel: zapcore.LowercaseLevelEncoder,
|
||||
EncodeTime: zapcore.ISO8601TimeEncoder,
|
||||
EncodeDuration: zapcore.StringDurationEncoder,
|
||||
}), zapcore.AddSync(buf), zapcore.DebugLevel)
|
||||
logger := zlog.New(zap.New(core))
|
||||
expect := `{"level":"info","msg":"handle zap message","env":"test"}` + "\n"
|
||||
|
||||
if _, err := logger(ctx, entry.New(
|
||||
entry.WithFields(field.String("env", "test")),
|
||||
entry.WithLevel(level.Notice),
|
||||
entry.WithMessage("handle zap message"),
|
||||
)); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
if buf.String() != expect {
|
||||
t.Errorf("invalid message\n got: %s\nexpect:%s\n", buf.String(), expect)
|
||||
}
|
||||
}
|
||||
@@ -9,14 +9,14 @@ func ExampleNew_withCaller() {
|
||||
logger := log.With(
|
||||
log.New(log.WithStdout()),
|
||||
log.WithLevel("level", level.Debug),
|
||||
log.WithCaller("caller", 2, false),
|
||||
log.WithSource(3),
|
||||
)
|
||||
logger.Err(ctx, "same error message")
|
||||
logger.InfoKVs(ctx, "same info message", "api-version", 0.1)
|
||||
_, _ = logger.Write([]byte("same write message"))
|
||||
|
||||
// Output:
|
||||
// msg="same error message" level=error caller=logger_example_caller_test.go:14
|
||||
// msg="same info message" api-version=0.1 level=info caller=logger_example_caller_test.go:15
|
||||
// msg="same write message" level=info caller=logger_example_caller_test.go:16
|
||||
// msg="same error message" level=error source=logger_example_caller_test.go:14
|
||||
// msg="same info message" api-version=0.1 level=info source=logger_example_caller_test.go:15
|
||||
// msg="same write message" level=info source=logger_example_caller_test.go:16
|
||||
}
|
||||
|
||||
@@ -86,6 +86,7 @@ func WithContextValue(keys ...fmt.Stringer) Middleware {
|
||||
}
|
||||
|
||||
// WithCaller adds called file.
|
||||
// Deprecated: use WithSource.
|
||||
func WithCaller(key string, depth int, full bool) Middleware {
|
||||
const offset = 2
|
||||
|
||||
|
||||
45
source.go
Normal file
45
source.go
Normal file
@@ -0,0 +1,45 @@
|
||||
package log
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
|
||||
"gitoa.ru/go-4devs/log/entry"
|
||||
"gitoa.ru/go-4devs/log/field"
|
||||
)
|
||||
|
||||
func WithSource(depth int) Middleware {
|
||||
const offset = 3
|
||||
|
||||
return func(ctx context.Context, data *entry.Entry, handler Logger) (int, error) {
|
||||
pc, file, line, has := runtime.Caller(depth + offset)
|
||||
if !has {
|
||||
return handler(ctx, data.AddAny(KeyLevel, field.NilValue()))
|
||||
}
|
||||
|
||||
fnc := runtime.FuncForPC(pc)
|
||||
|
||||
return handler(ctx, data.AddAny(KeySource, Source{
|
||||
Func: filepath.Base(fnc.Name()),
|
||||
File: filepath.Base(file),
|
||||
Line: line,
|
||||
}))
|
||||
}
|
||||
}
|
||||
|
||||
// Source describes the location of a line of source code.
|
||||
type Source struct {
|
||||
Func string `json:"func"`
|
||||
File string `json:"file"`
|
||||
Line int `json:"line"`
|
||||
}
|
||||
|
||||
func (l Source) MarshalText() ([]byte, error) {
|
||||
return []byte(fmt.Sprintf("%s:%d", l.File, l.Line)), nil
|
||||
}
|
||||
|
||||
func (l Source) MarshalJSON() ([]byte, error) {
|
||||
return fmt.Appendf([]byte{}, `{"file":"%s","line":%d,"func":"%s"}`, l.File, l.Line, l.Func), nil
|
||||
}
|
||||
25
source_example_test.go
Normal file
25
source_example_test.go
Normal file
@@ -0,0 +1,25 @@
|
||||
package log_test
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"gitoa.ru/go-4devs/log"
|
||||
)
|
||||
|
||||
func ExampleWithSource() {
|
||||
ctx := context.Background()
|
||||
logger := log.New(log.WithStdout()).With(log.WithSource(1))
|
||||
|
||||
logger.Debug(ctx, "debug message")
|
||||
// Output:
|
||||
// msg="debug message" source=source_example_test.go:13
|
||||
}
|
||||
|
||||
func ExampleWithSource_json() {
|
||||
ctx := context.Background()
|
||||
logger := log.New(log.WithStdout(), log.WithJSONFormat()).With(log.WithSource(1))
|
||||
|
||||
logger.Debug(ctx, "debug message")
|
||||
// Output:
|
||||
// {"msg":"debug message","source":{"file":"source_example_test.go","line":22,"func":"log_test.ExampleWithSource_json"}}
|
||||
}
|
||||
Reference in New Issue
Block a user