3 Commits

Author SHA1 Message Date
andrey1s
6befe17e32 mod tidy
Some checks failed
continuous-integration/drone/push Build is failing
continuous-integration/drone/pr Build is failing
2021-09-19 18:46:08 +03:00
andrey1s
fc133148dc update golang version
Some checks failed
continuous-integration/drone/push Build is failing
continuous-integration/drone/pr Build is failing
2021-09-19 18:42:33 +03:00
andrey1s
a8f5213750 update zap/logrus hanler
Some checks failed
continuous-integration/drone/push Build is failing
continuous-integration/drone/pr Build is failing
2021-09-19 18:14:34 +03:00
53 changed files with 1935 additions and 2496 deletions

BIN
.DS_Store vendored Normal file

Binary file not shown.

View File

@@ -1,11 +1,9 @@
---
kind: pipeline kind: pipeline
type: docker name: default
name: logger
steps: steps:
- name: test - name: test
image: golang:1.21.5 image: golang:1.17.1
volumes: volumes:
- name: deps - name: deps
path: /go/src/mod path: /go/src/mod
@@ -13,85 +11,10 @@ steps:
- go test - go test
- name: golangci-lint - name: golangci-lint
image: golangci/golangci-lint:v1.55 image: golangci/golangci-lint:v1.42
commands: commands:
- golangci-lint run - golangci-lint run
volumes: volumes:
- name: deps - name: deps
temp: {} temp: {}
---
kind: pipeline
type: docker
name: otel
steps:
- name: test
image: golang:1.21.5
volumes:
- name: deps
path: /go/src/mod
commands:
- cd handler/otel
- go test
- name: golangci-lint
image: golangci/golangci-lint:v1.55
commands:
- cd handler/otel
- golangci-lint run
volumes:
- name: deps
temp: {}
---
kind: pipeline
type: docker
name: logrus
steps:
- name: test
image: golang:1.21.5
volumes:
- name: deps
path: /go/src/mod
commands:
- cd handler/logrus
- go test
- name: golangci-lint
image: golangci/golangci-lint:v1.55
commands:
- cd handler/logrus
- golangci-lint run
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: {}

View File

@@ -1,6 +1,3 @@
run:
timeout: 5m
linters-settings: linters-settings:
dupl: dupl:
threshold: 100 threshold: 100
@@ -12,50 +9,21 @@ linters-settings:
min-occurrences: 2 min-occurrences: 2
gocyclo: gocyclo:
min-complexity: 15 min-complexity: 15
golint:
min-confidence: 0
govet: govet:
check-shadowing: true check-shadowing: true
lll: lll:
line-length: 140 line-length: 140
fieldalignment: maligned:
suggest-new: true suggest-new: true
misspell: misspell:
locale: US locale: US
exhaustive: exhaustive:
default-signifies-exhaustive: true default-signifies-exhaustive: true
varnamelen:
min-name-length: 2
ignore-names:
- err
- n
- i
- w
tagliatelle:
case:
use-field-name: true
rules:
json: snake
yaml: camel
xml: camel
bson: camel
avro: snake
linters: linters:
enable-all: true enable-all: true
disable:
# deprecated
- interfacer
- structcheck
- varcheck
- golint
- deadcode
- scopelint
- exhaustivestruct
- ifshort
- nosnakecase
- maligned
- depguard # need configure
- nolintlint # use with space
issues: issues:
# Excluding configuration per-path, per-linter, per-text and per-source # Excluding configuration per-path, per-linter, per-text and per-source
@@ -63,10 +31,3 @@ issues:
- path: _test\.go - path: _test\.go
linters: linters:
- gomnd - gomnd
- ireturn
- exhaustruct
- gochecknoglobals
- path: _example_test\.go
linters:
- lll
- goerr113

View File

@@ -1,4 +1,4 @@
MIT License Copyright (c) 2020-2022 4devs MIT License Copyright (c) 2020 go-4devs
Permission is hereby granted, free of charge, to any person obtaining a copy Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal of this software and associated documentation files (the "Software"), to deal

View File

@@ -4,7 +4,7 @@ import (
"context" "context"
"errors" "errors"
"fmt" "fmt"
"io" "io/ioutil"
"testing" "testing"
"time" "time"
@@ -12,6 +12,7 @@ import (
"gitoa.ru/go-4devs/log/field" "gitoa.ru/go-4devs/log/field"
) )
// nolint: gochecknoglobals
var ( var (
errExample = errors.New("fail") errExample = errors.New("fail")
_messages = fakeMessages(1000) _messages = fakeMessages(1000)
@@ -117,7 +118,7 @@ func fakeSugarFields() []interface{} {
} }
func NewLogger() log.Logger { func NewLogger() log.Logger {
return log.New(log.WithWriter(io.Discard)) return log.New(log.WithWriter(ioutil.Discard))
} }
func BenchmarkDisabledWithoutFields(b *testing.B) { func BenchmarkDisabledWithoutFields(b *testing.B) {

View File

@@ -7,14 +7,14 @@ import (
) )
func Caller(depth int, full bool) string { func Caller(depth int, full bool) string {
const offset = 3 const offset = 4
_, file, line, has := runtime.Caller(depth + offset) _, file, line, ok := runtime.Caller(depth + offset)
if !has { if !ok {
file, line = "???", 0 file, line = "???", 0
} }
if !full && has { if !full && ok {
file = filepath.Base(file) file = filepath.Base(file)
} }

View File

@@ -1,7 +1,6 @@
package entry package entry
import ( import (
"fmt"
"strings" "strings"
"gitoa.ru/go-4devs/log/field" "gitoa.ru/go-4devs/log/field"
@@ -14,9 +13,9 @@ const (
type Option func(*Entry) type Option func(*Entry)
func WithCapacity(c int) Option { func WithCapacity(cap int) Option {
return func(e *Entry) { return func(e *Entry) {
e.fields = make(field.Fields, 0, c+1) e.fields = make(field.Fields, 0, cap+1)
} }
} }
@@ -28,14 +27,7 @@ func WithFields(fields ...field.Field) Option {
func WithMessage(msg string) Option { func WithMessage(msg string) Option {
return func(e *Entry) { return func(e *Entry) {
e.format = msg e.msg = msg
}
}
func WithMessagef(format string, args ...interface{}) Option {
return func(e *Entry) {
e.format = format
e.args = args
} }
} }
@@ -46,32 +38,27 @@ func WithLevel(lvl level.Level) Option {
} }
func New(opts ...Option) *Entry { func New(opts ...Option) *Entry {
entry := &Entry{ e := &Entry{
fields: make(field.Fields, 0, defaultCap+1), fields: make(field.Fields, 0, defaultCap+1),
level: level.Debug, level: level.Debug,
format: "",
args: make([]interface{}, 0, defaultCap+1),
} }
for _, opt := range opts { for _, opt := range opts {
opt(entry) opt(e)
} }
return entry return e
} }
// Entry slice field. // Entry slice field.
type Entry struct { type Entry struct {
format string msg string
args []interface{}
level level.Level level level.Level
fields field.Fields fields field.Fields
} }
func (e *Entry) Reset() { func (e *Entry) Reset() {
e.fields = e.fields[:0] e.fields = e.fields[:0]
e.args = e.args[:0]
e.format = ""
} }
func (e *Entry) Fields() field.Fields { func (e *Entry) Fields() field.Fields {
@@ -85,7 +72,7 @@ func (e *Entry) String() string {
} }
str := make([]string, len(e.fields)+1) str := make([]string, len(e.fields)+1)
str[0] = e.Message() str[0] = e.msg
for i, field := range e.fields { for i, field := range e.fields {
str[i+1] = field.String() str[i+1] = field.String()
@@ -95,14 +82,7 @@ func (e *Entry) String() string {
} }
func (e *Entry) Message() string { func (e *Entry) Message() string {
switch { return e.msg
case len(e.args) > 0 && e.format != "":
return fmt.Sprintf(e.format, e.args...)
case len(e.args) > 0:
return fmt.Sprint(e.args...)
default:
return e.format
}
} }
func (e *Entry) Level() level.Level { func (e *Entry) Level() level.Level {
@@ -128,18 +108,7 @@ func (e *Entry) SetMessage(msg string) *Entry {
return New().SetMessage(msg) return New().SetMessage(msg)
} }
e.format = msg e.msg = msg
return e
}
func (e *Entry) SetMessagef(format string, args ...interface{}) *Entry {
if e == nil {
return New().SetMessagef(format, args...)
}
e.format = format
e.args = append(e.args[:0], args...)
return e return e
} }

View File

@@ -2,14 +2,13 @@ package entry
import "sync" import "sync"
//nolint:gochecknoglobals // nolint: gochecknoglobals
var pool = sync.Pool{ var pool = sync.Pool{
New: func() interface{} { New: func() interface{} {
return New() return New()
}, },
} }
//nolint:forcetypeassert
func Get() *Entry { func Get() *Entry {
e := pool.Get().(*Entry) e := pool.Get().(*Entry)
e.Reset() e.Reset()

View File

@@ -1,281 +1,31 @@
//nolint:gomnd
package field package field
import ( import "time"
"fmt"
"strconv"
"time"
"unicode"
"unicode/utf8"
)
type Encoder interface { type Encoder interface {
AppendField(dst []byte, field Field) []byte // Built-in types.
AppendValue(dst []byte, val Value) []byte AddArray(key string, value Value)
} AddAny(key string, value Value)
AddNil(key string)
func WithAppendString(fn func(dst []byte, in string) []byte) func(*BaseEncoder) { AddBool(key string, value bool)
return func(be *BaseEncoder) { AddBinary(key string, value []byte)
be.AppendString = fn AddInt(key string, value int)
} AddInt8(key string, value int8)
} AddInt16(key string, value int16)
AddInt32(key string, value int32)
func WithNullValue(in string) func(*BaseEncoder) { AddInt64(key string, value int64)
return func(be *BaseEncoder) { AddUint(key string, value uint)
be.nullValue = []byte(in) AddUint8(key string, value uint8)
} AddUint16(key string, value uint16)
} AddUint32(key string, value uint32)
AddUint64(key string, value uint64)
func WithDelimeter(in byte) func(*BaseEncoder) { AddUintptr(key string, value uintptr)
return func(be *BaseEncoder) { AddTime(key string, value time.Time)
be.delimeter = in AddDuration(key string, value time.Duration)
} AddFloat32(key string, value float32)
} AddFloat64(key string, value float64)
AddComplex64(key string, value complex64)
func WithGropuConfig(start, end, deli byte) func(*BaseEncoder) { AddComplex128(key string, value complex128)
return func(be *BaseEncoder) { AddString(key, value string)
be.group = groupConfig{ AddError(key string, value error)
start: start,
end: end,
deli: deli,
}
}
}
func WithDefaultValue(fn func(dst []byte, e Encoder, val Value) []byte) func(*BaseEncoder) {
return func(be *BaseEncoder) {
be.DefaultValue = fn
}
}
func NewEncoder(opts ...func(*BaseEncoder)) BaseEncoder {
be := BaseEncoder{
nullValue: []byte("null"),
group: groupConfig{
start: '{',
end: '}',
deli: ',',
},
array: groupConfig{
start: '[',
end: ']',
deli: ',',
},
timeFormat: time.RFC3339,
AppendString: AppendString,
delimeter: '=',
DefaultValue: func(dst []byte, e Encoder, val Value) []byte {
return e.AppendValue(dst, StringValue(fmt.Sprintf("%+v", val.Any())))
},
}
for _, opt := range opts {
opt(&be)
}
return be
}
type groupConfig struct {
start byte
end byte
deli byte
}
type BaseEncoder struct {
nullValue []byte
group groupConfig
array groupConfig
timeFormat string
AppendString func(dst []byte, in string) []byte
delimeter byte
DefaultValue func(dst []byte, e Encoder, val Value) []byte
}
func (b BaseEncoder) AppendValue(dst []byte, val Value) []byte {
return b.appendValue(dst, val, "", 0)
}
func (b BaseEncoder) AppendDelimiter(dst []byte, deli byte) []byte {
if deli == 0 {
return dst
}
return append(dst, deli)
}
//nolint:gocyclo,cyclop
func (b BaseEncoder) appendValue(dst []byte, val Value, prefix string, deli byte) []byte {
switch val.Kind {
case KindGroup:
return b.appendGroup(dst, val.AsGroup(), prefix)
case KindClosure:
return b.appendValue(dst, AnyValue(val.Resolve()), prefix, deli)
case KindArray:
return b.AppendArray(b.AppendDelimiter(dst, deli), val.AsArray())
case KindNil:
return b.AppendNull(b.AppendDelimiter(dst, deli))
case KindBool:
return b.AppendBool(b.AppendDelimiter(dst, deli), val.AsBool())
case KindBinary:
return b.AppendBytes(b.AppendDelimiter(dst, deli), val.AsBinary())
case KindComplex128:
return b.AppendComplex(b.AppendDelimiter(dst, deli), val.AsComplex128())
case KindInt64:
return b.AppendInt(b.AppendDelimiter(dst, deli), val.AsInt64())
case KindFloat32:
return b.AppendFloat(b.AppendDelimiter(dst, deli), float64(val.AsFloat32()), 32)
case KindFloat64:
return b.AppendFloat(b.AppendDelimiter(dst, deli), val.AsFloat64(), 64)
case KindUint64:
return b.AppendUint(b.AppendDelimiter(dst, deli), val.AsUint64())
case KindError:
return b.AppendString(b.AppendDelimiter(dst, deli), val.AsError().Error())
case KindString:
return b.AppendString(b.AppendDelimiter(dst, deli), val.AsString())
case KindDuration:
return b.AppendDuration(b.AppendDelimiter(dst, deli), val.AsDuration())
case KindTime:
return b.AppendTime(b.AppendDelimiter(dst, deli), val.AsTime())
case KindAny:
return b.DefaultValue(b.AppendDelimiter(dst, deli), b, val)
}
return b.DefaultValue(b.AppendDelimiter(dst, deli), b, val)
}
func (b BaseEncoder) AppendDuration(dst []byte, d time.Duration) []byte {
return b.AppendString(dst, d.String())
}
func (b BaseEncoder) AppendTime(dst []byte, t time.Time) []byte {
return b.AppendString(dst, t.Format(b.timeFormat))
}
func AppendString(dst []byte, in string) []byte {
if needsQuoting(in) {
return strconv.AppendQuote(dst, in)
}
return append(dst, in...)
}
//nolint:cyclop
func needsQuoting(in string) bool {
if len(in) == 0 {
return true
}
for i := 0; i < len(in); {
char := in[i]
if char < utf8.RuneSelf {
// Quote anything except a backslash that would need quoting in a
// JSON string, as well as space and '='
if char != '\\' && (char == ' ' || char == '=' || !safeSet[char]) {
return true
}
i++
continue
}
decodeRune, size := utf8.DecodeRuneInString(in[i:])
if decodeRune == utf8.RuneError || unicode.IsSpace(decodeRune) || !unicode.IsPrint(decodeRune) {
return true
}
i += size
}
return false
}
func (b BaseEncoder) AppendField(dst []byte, field Field) []byte {
prefix := ""
if len(dst) != 0 {
prew := dst[len(dst)-1]
if prew != '{' && prew != '.' {
prefix = string(b.group.deli)
}
}
return b.appendField(dst, field, prefix, b.delimeter)
}
func (b BaseEncoder) appendField(dst []byte, field Field, prefix string, deli byte) []byte {
dst = b.AppendKey(dst, field.Key, prefix)
return b.appendValue(dst, field.Value, field.Key+".", deli)
}
func (b BaseEncoder) AppendKey(dst []byte, key string, prefix string) []byte {
if prefix != "" {
dst = append(dst, prefix...)
}
return b.AppendString(dst, key)
}
func (b BaseEncoder) AppendComplex(dst []byte, c complex128) []byte {
cmplx := strconv.FormatComplex(c, 'g', -1, 128)
return b.AppendString(dst, cmplx)
}
func (b BaseEncoder) AppendFloat(dst []byte, f float64, bitSize int) []byte {
return strconv.AppendFloat(dst, f, 'g', -1, bitSize)
}
func (b BaseEncoder) AppendUint(dst []byte, u uint64) []byte {
return strconv.AppendUint(dst, u, 10)
}
func (b BaseEncoder) AppendNull(dst []byte) []byte {
return append(dst, b.nullValue...)
}
func (b BaseEncoder) AppendInt(dst []byte, val int64) []byte {
return strconv.AppendInt(dst, val, 10)
}
func (b BaseEncoder) AppendBool(dst []byte, val bool) []byte {
return strconv.AppendBool(dst, val)
}
func (b BaseEncoder) AppendGroup(dst []byte, fields []Field) []byte {
dst = append(dst, b.group.start)
dst = b.appendGroup(dst, fields, "")
return append(dst, b.group.end)
}
func (b BaseEncoder) appendGroup(dst []byte, fields []Field, prefix string) []byte {
if len(fields) > 0 {
dst = b.appendField(dst, fields[0], ".", b.delimeter)
for _, field := range fields[1:] {
dst = b.appendField(append(dst, b.group.deli), field, prefix, b.delimeter)
}
}
return dst
}
func (b BaseEncoder) AppendArray(dst []byte, in []Value) []byte {
dst = append(dst, b.array.start)
if len(in) > 0 {
dst = b.appendValue(dst, in[0], "", 0)
for _, value := range in[1:] {
dst = b.appendValue(append(dst, b.array.deli), value, "", 0)
}
}
return append(dst, b.array.end)
}
func (b BaseEncoder) AppendBytes(dst, in []byte) []byte {
dst = append(dst, '"')
dst = append(dst, in...)
return append(dst, '"')
} }

View File

@@ -1,23 +0,0 @@
package field
import (
"encoding/json"
"strconv"
)
func NewEncoderJSON(opts ...func(*BaseEncoder)) BaseEncoder {
opts = append([]func(*BaseEncoder){
WithAppendString(strconv.AppendQuote),
WithDelimeter(':'),
WithDefaultValue(func(dst []byte, e Encoder, val Value) []byte {
js, err := json.Marshal(val.Any())
if err != nil {
return e.AppendValue(dst, ErrorValue(err))
}
return append(dst, js...)
}),
}, opts...)
return NewEncoder(opts...)
}

View File

@@ -1,38 +0,0 @@
package field_test
import (
"testing"
"gitoa.ru/go-4devs/log/field"
"gitoa.ru/go-4devs/log/internal/buffer"
)
func TestEncoderJSONAppendField_string(t *testing.T) {
t.Parallel()
const expect = `"array":["value","other"],"str":"value","nullableStr":"value","nullstr":null`
encode := field.NewEncoderJSON()
buf := buffer.New()
defer func() {
buf.Free()
}()
val := "value"
strs := field.Strings("array", val, "other")
*buf = encode.AppendField(*buf, strs)
str := field.String("str", val)
*buf = encode.AppendField(*buf, str)
strp := field.Stringp("nullableStr", &val)
*buf = encode.AppendField(*buf, strp)
nullStr := field.Stringp("nullstr", nil)
*buf = encode.AppendField(*buf, nullStr)
if buf.String() != expect {
t.Errorf("json string expect:%v got:%s", expect, buf)
}
}

View File

@@ -1,28 +0,0 @@
package field
import (
"encoding"
"fmt"
)
func NewEncoderText(opts ...func(*BaseEncoder)) BaseEncoder {
opts = append([]func(*BaseEncoder){
WithGropuConfig(0, 0, ' '),
WithNullValue("<nil>"),
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...)
return NewEncoder(opts...)
}

View File

@@ -1,5 +0,0 @@
package field
import "errors"
var ErrUndefined = errors.New("indefined")

View File

@@ -5,499 +5,329 @@ import (
"time" "time"
) )
func Any(key string, value any) Field { func Any(key string, value interface{}) Field {
return Field{ return Key(key).Any(value)
Key: key,
Value: AnyValue(value),
}
} }
func String(key, value string) Field { func String(key, value string) Field {
return Field{ return Key(key).String(value)
Key: key,
Value: StringValue(value),
}
} }
func Stringp(key string, value *string) Field { func Stringp(key string, value *string) Field {
return Field{ return Key(key).Stringp(value)
Key: key,
Value: StringpValue(value),
}
} }
func Strings(key string, value ...string) Field { func Strings(key string, value ...string) Field {
return Field{ return Key(key).Strings(value...)
Key: key,
Value: StringsValue(value),
}
} }
func Bool(key string, value bool) Field { func Bool(key string, value bool) Field {
return Field{ return Key(key).Bool(value)
Key: key,
Value: BoolValue(value),
}
} }
func Bools(key string, value ...bool) Field { func Bools(key string, value ...bool) Field {
return Field{ return Key(key).Bools(value...)
Key: key,
Value: BoolsValue(value),
}
} }
func Boolp(key string, value *bool) Field { func Boolp(key string, value *bool) Field {
return Field{ return Key(key).Boolp(value)
Key: key,
Value: BoolpValue(value),
}
} }
func Uint(key string, value uint) Field { func Uint(key string, value uint) Field {
return Field{ return Key(key).Uint(value)
Key: key,
Value: Uint64Value(uint64(value)),
}
} }
func Uints(key string, value ...uint) Field { func Uints(key string, value ...uint) Field {
return Field{ return Key(key).Uints(value...)
Key: key,
Value: AnyValue(value),
}
} }
func Uintp(key string, value *uint) Field { func Uintp(key string, value *uint) Field {
return Field{ return Key(key).Uintp(value)
Key: key,
Value: AnyValue(value),
}
} }
func Uint8(key string, value uint8) Field { func Uint8(key string, value uint8) Field {
return Field{ return Key(key).Uint8(value)
Key: key,
Value: Uint64Value(uint64(value)),
}
} }
func Uint8s(key string, value ...uint8) Field { func Uint8s(key string, value ...uint8) Field {
return Field{ return Key(key).Uint8s(value...)
Key: key,
Value: Uint8sValue(value),
}
} }
func Uint8p(key string, value *uint8) Field { func Uint8p(key string, value *uint8) Field {
return Field{ return Key(key).Uint8p(value)
Key: key,
Value: AnyValue(value),
}
} }
func Uint16(key string, value uint16) Field { func Uint16(key string, value uint16) Field {
return Field{ return Key(key).Uint16(value)
Key: key,
Value: Uint64Value(uint64(value)),
}
} }
func Uint16s(key string, value ...uint16) Field { func Uint16s(key string, value ...uint16) Field {
return Field{ return Key(key).Uint16s(value...)
Key: key,
Value: AnyValue(value),
}
} }
func Uint16p(key string, value *uint16) Field { func Uint16p(key string, value *uint16) Field {
return Field{ return Key(key).Uint16p(value)
Key: key,
Value: AnyValue(value),
}
} }
func Uint32(key string, value uint32) Field { func Uint32(key string, value uint32) Field {
return Field{ return Key(key).Uint32(value)
Key: key,
Value: Uint64Value(uint64(value)),
}
} }
func Uint32s(key string, value ...uint32) Field { func Uint32s(key string, value ...uint32) Field {
return Field{ return Key(key).Uint32s(value...)
Key: key,
Value: AnyValue(value),
}
} }
func Uint32p(key string, value *uint32) Field { func Uint32p(key string, value *uint32) Field {
return Field{ return Key(key).Uint32p(value)
Key: key,
Value: AnyValue(value),
}
} }
func Uint64(key string, value uint64) Field { func Uint64(key string, value uint64) Field {
return Field{ return Key(key).Uint64(value)
Key: key,
Value: Uint64Value(value),
}
} }
func Uint64s(key string, value ...uint64) Field { func Uint64s(key string, value ...uint64) Field {
return Field{ return Key(key).Uint64s(value...)
Key: key,
Value: Uint64sValue(value),
}
} }
func Uint64p(key string, value *uint64) Field { func Uint64p(key string, value *uint64) Field {
return Field{ return Key(key).Uint64p(value)
Key: key,
Value: Uint64pValue(value),
}
} }
func Int(key string, value int) Field { func Int(key string, value int) Field {
return Field{ return Key(key).Int(value)
Key: key,
Value: Int64Value(int64(value)),
}
} }
func Ints(key string, value ...int) Field { func Ints(key string, value ...int) Field {
return Field{ return Key(key).Ints(value...)
Key: key,
Value: AnyValue(value),
}
} }
func Intp(key string, value *int) Field { func Intp(key string, value *int) Field {
return Field{ return Key(key).Intp(value)
Key: key,
Value: AnyValue(value),
}
} }
func Int8(key string, value int8) Field { func Int8(key string, value int8) Field {
return Field{ return Key(key).Int8(value)
Key: key,
Value: Int64Value(int64(value)),
}
} }
func Int8s(key string, value ...int8) Field { func Int8s(key string, value ...int8) Field {
return Field{ return Key(key).Int8s(value...)
Key: key,
Value: AnyValue(value),
}
} }
func Int8p(key string, value *int8) Field { func Int8p(key string, value *int8) Field {
return Field{ return Key(key).Int8p(value)
Key: key,
Value: AnyValue(value),
}
} }
func Int16(key string, value int16) Field { func Int16(key string, value int16) Field {
return Field{ return Key(key).Int16(value)
Key: key,
Value: Int64Value(int64(value)),
}
} }
func Int16s(key string, value ...int16) Field { func Int16s(key string, value ...int16) Field {
return Field{ return Key(key).Int16s(value...)
Key: key,
Value: AnyValue(value),
}
} }
func Int16p(key string, value *int16) Field { func Int16p(key string, value *int16) Field {
return Field{ return Key(key).Int16p(value)
Key: key,
Value: AnyValue(value),
}
} }
func Int32(key string, value int32) Field { func Int32(key string, value int32) Field {
return Field{ return Key(key).Int32(value)
Key: key,
Value: Int64Value(int64(value)),
}
} }
func Int32s(key string, value ...int32) Field { func Int32s(key string, value ...int32) Field {
return Field{ return Key(key).Int32s(value...)
Key: key,
Value: AnyValue(value),
}
} }
func Int32p(key string, value *int32) Field { func Int32p(key string, value *int32) Field {
return Field{ return Key(key).Int32p(value)
Key: key,
Value: AnyValue(value),
}
} }
func Int64(key string, value int64) Field { func Int64(key string, value int64) Field {
return Field{ return Key(key).Int64(value)
Key: key,
Value: Int64Value(value),
}
} }
func Int64s(key string, value ...int64) Field { func Int64s(key string, value ...int64) Field {
return Field{ return Key(key).Int64s(value...)
Key: key,
Value: Int64sValue(value),
}
} }
func Int64p(key string, value *int64) Field { func Int64p(key string, value *int64) Field {
return Field{ return Key(key).Int64p(value)
Key: key,
Value: Int64pValue(value),
}
} }
func Float32(key string, value float32) Field { func Float32(key string, value float32) Field {
return Field{ return Key(key).Float32(value)
Key: key,
Value: Float64Value(float64(value)),
}
} }
func Float32s(key string, value ...float32) Field { func Float32s(key string, value ...float32) Field {
return Field{ return Key(key).Float32s(value...)
Key: key,
Value: AnyValue(value),
}
} }
func Float32p(key string, value *float32) Field { func Float32p(key string, value *float32) Field {
return Field{ return Key(key).Float32p(value)
Key: key,
Value: AnyValue(value),
}
} }
func Float64(key string, value float64) Field { func Float64(key string, value float64) Field {
return Field{ return Key(key).Float64(value)
Key: key,
Value: Float64Value(value),
}
} }
func Float64s(key string, value ...float64) Field { func Float64s(key string, value ...float64) Field {
return Field{ return Key(key).Float64s(value...)
Key: key,
Value: Float64sValue(value),
}
} }
func Float64p(key string, value *float64) Field { func Float64p(key string, value *float64) Field {
return Field{ return Key(key).Float64p(value)
Key: key,
Value: Float64pValue(value),
}
} }
func Complex64(key string, value complex64) Field { func Complex64(key string, value complex64) Field {
return Field{ return Key(key).Complex64(value)
Key: key,
Value: Complex128Value(complex128(value)),
}
} }
func Complex64s(key string, value ...complex64) Field { func Complex64s(key string, value ...complex64) Field {
return Field{ return Key(key).Complex64s(value...)
Key: key,
Value: Complex64sValue(value),
}
} }
func Complex64p(key string, value *complex64) Field { func Complex64p(key string, value *complex64) Field {
return Field{ return Key(key).Complex64p(value)
Key: key,
Value: AnyValue(value),
}
}
func Complex128(key string, value complex128) Field {
return Field{
Key: key,
Value: Complex128Value(value),
}
}
func Complex128s(key string, value ...complex128) Field {
return Field{
Key: key,
Value: Complex128sValue(value),
}
}
func Complex128p(key string, value *complex128) Field {
return Field{
Key: key,
Value: Complex128pValue(value),
}
} }
func Uintptr(key string, value uintptr) Field { func Uintptr(key string, value uintptr) Field {
return Field{ return Key(key).Uintptr(value)
Key: key,
Value: Uint64Value(uint64(value)),
}
} }
func Uintptrs(key string, value ...uintptr) Field { func Uintptrs(key string, value ...uintptr) Field {
return Field{ return Key(key).Uintptrs(value...)
Key: key,
Value: AnyValue(value),
}
} }
func Uintptrp(key string, value *uintptr) Field { func Uintptrp(key string, value *uintptr) Field {
return Field{ return Key(key).Uintptrp(value)
Key: key,
Value: AnyValue(value),
}
} }
func Bytes(key string, value []byte) Field { func Bytes(key string, value []byte) Field {
return Field{ return Key(key).Bytes(value)
Key: key,
Value: BytesValue(value),
}
} }
func Duration(key string, value time.Duration) Field { func Duration(key string, value time.Duration) Field {
return Field{ return Key(key).Dureation(value)
Key: key,
Value: DurationValue(value),
}
} }
func Durations(key string, value ...time.Duration) Field { func Durations(key string, value ...time.Duration) Field {
return Field{ return Key(key).Dureations(value)
Key: key,
Value: DurationsValue(value),
}
} }
func Durationp(key string, value *time.Duration) Field { func Durationp(key string, value *time.Duration) Field {
return Field{ return Key(key).Dureationp(value)
Key: key,
Value: DurationpValue(value),
}
} }
func Time(key string, value time.Time) Field { func Time(key string, value time.Time) Field {
return Field{ return Key(key).Time(value)
Key: key,
Value: TimeValue(value),
}
} }
func Times(key string, value ...time.Time) Field { func Times(key string, value ...time.Time) Field {
return Field{ return Key(key).Times(value...)
Key: key,
Value: TimesValue(value),
}
} }
func Timep(key string, value *time.Time) Field { func Timep(key string, value *time.Time) Field {
return Field{ return Key(key).Timep(value)
Key: key,
Value: TimepValue(value),
}
} }
func FormatTime(key, format string, value time.Time) Field { func FormatTime(key, format string, value time.Time) Field {
return Field{ return Key(key).FormatTime(format, value)
Key: key,
Value: ClosureValue(func() any {
return value.Format(format)
}),
}
} }
func FormatTimes(key, format string, value ...time.Time) Field { func FormatTimes(key, foramt string, value ...time.Time) Field {
return Field{ return Key(key).FormatTimes(foramt, value...)
Key: key,
Value: ClosureValue(func() any {
times := make([]any, len(value))
for idx, val := range value {
times[idx] = val.Format(format)
}
return times
}),
}
} }
func FormatTimep(key, format string, value *time.Time) Field { func FormatTimep(key, foramt string, value *time.Time) Field {
isNill := value == nil return Key(key).FormatTimep(foramt, value)
return Field{
Key: key,
Value: ClosureValue(func() any {
if isNill {
return NilValue()
}
return value.Format(format)
}),
}
} }
func Error(key string, value error) Field { func Error(key string, value error) Field {
return Field{ return Key(key).Error(value)
Key: key,
Value: ErrorValue(value),
}
} }
func Errors(key string, value ...error) Field { func Errors(key string, value ...error) Field {
return Field{ return Key(key).Errors(value...)
Key: key,
Value: ErrorsValue(value),
}
}
func Groups(key string, value ...Field) Field {
return Field{
Key: key,
Value: GroupValue(value...),
}
}
func Valuer(key string, value LogValuer) Field {
return Field{
Key: key,
Value: AnyValue(value),
}
}
func ValuerFn(key string, value ClosureFn) Field {
return Field{
Key: key,
Value: ClosureValue(value),
}
} }
// Field struct. // Field struct.
type Field struct { type Field struct {
Key string key Key
Value Value value Value
}
//nolint: gocyclo
func (f Field) AddTo(enc Encoder) {
key := string(f.key)
switch {
case f.value.IsArray():
enc.AddAny(key, f.value)
case f.value.IsNil():
enc.AddNil(key)
case f.value.IsBool():
enc.AddBool(key, f.value.asBool())
case f.value.IsBinary():
enc.AddBinary(key, f.value.asBinary())
case f.value.IsInt():
enc.AddInt(key, f.value.asInt())
case f.value.IsInt8():
enc.AddInt8(key, f.value.asInt8())
case f.value.IsInt16():
enc.AddInt16(key, f.value.asInt16())
case f.value.IsInt32():
enc.AddInt32(key, f.value.asInt32())
case f.value.IsInt64():
enc.AddInt64(key, f.value.asInt64())
case f.value.IsUint():
enc.AddUint(key, f.value.asUint())
case f.value.IsUint8():
enc.AddUint8(key, f.value.asUint8())
case f.value.IsUint16():
enc.AddUint16(key, f.value.asUint16())
case f.value.IsUint32():
enc.AddUint32(key, f.value.asUint32())
case f.value.IsUint64():
enc.AddUint64(key, f.value.asUint64())
case f.value.IsUintptr():
enc.AddUintptr(key, f.value.asUintptr())
case f.value.IsTime():
enc.AddTime(key, f.value.asTime())
case f.value.IsDuration():
enc.AddDuration(key, f.value.asDuration())
case f.value.IsFloat32():
enc.AddFloat32(key, f.value.asFloat32())
case f.value.IsFloat64():
enc.AddFloat64(key, f.value.asFloat64())
case f.value.IsComplex64():
enc.AddComplex64(key, f.value.asComplex64())
case f.value.IsComplex128():
enc.AddComplex128(key, f.value.asComplex128())
case f.value.IsString():
enc.AddString(key, f.value.asString())
case f.value.IsError():
enc.AddError(key, f.value.asError())
default:
enc.AddAny(key, f.value)
}
}
func (f Field) Type() Type {
return f.value.vtype
}
func (f Field) Key() Key {
return f.key
}
func (f Field) Value() Value {
return f.value
}
func (f Field) AsInterface() interface{} {
return f.value.AsInterface()
} }
// String implent stringer. // String implent stringer.
func (f Field) String() string { func (f Field) String() string {
return fmt.Sprintf("%s=%+v", f.Key, f.Value) return fmt.Sprintf("%s=%+v", f.key, f.value.AsInterface())
} }

View File

@@ -2,22 +2,7 @@ package field
type Fields []Field type Fields []Field
func (f Fields) Fields(fn func(Field) bool) { type MapField map[Key]Value
for idx := range f {
if !fn(f[idx]) {
return
}
}
}
func (f Fields) Any() any {
fields := make(map[string]any)
for idx := range f {
fields[f[idx].Key] = f[idx].Value.Any()
}
return fields
}
func (f Fields) Append(fields ...Field) Fields { func (f Fields) Append(fields ...Field) Fields {
f = append(f, fields...) f = append(f, fields...)
@@ -32,3 +17,13 @@ func (f Fields) Set(idx int, field Field) {
func (f Fields) Len() int { func (f Fields) Len() int {
return len(f) return len(f)
} }
func (f Fields) AsMap() MapField {
m := make(MapField, len(f))
for _, field := range f {
m[field.Key()] = field.Value()
}
return m
}

View File

@@ -1,18 +0,0 @@
package field_test
import (
"testing"
"gitoa.ru/go-4devs/log/field"
)
func TestFields_Append(t *testing.T) {
t.Parallel()
fields := field.Fields{field.Any("any", "value")}
fields = fields.Append(field.String("string", "value"))
if len(fields) != 2 {
t.Fatalf("require 2 field got %v", len(fields))
}
}

568
field/key.go Normal file
View File

@@ -0,0 +1,568 @@
package field
import (
"time"
)
type Key string
//nolint: gocyclo, funlen
func (k Key) Any(value interface{}) Field {
switch v := value.(type) {
case string:
return k.String(v)
case *string:
return k.Stringp(v)
case []string:
return k.Strings(v...)
case bool:
return k.Bool(v)
case *bool:
return k.Boolp(v)
case []bool:
return k.Bools(v...)
case int8:
return k.Int8(v)
case []int8:
return k.Int8s(v...)
case *int8:
return k.Int8p(v)
case int16:
return k.Int16(v)
case []int16:
return k.Int16s(v...)
case *int16:
return k.Int16p(v)
case int32:
return k.Int32(v)
case []int32:
return k.Int32s(v...)
case *int32:
return k.Int32p(v)
case int64:
return k.Int64(v)
case []int64:
return k.Int64s(v...)
case *int64:
return k.Int64p(v)
case uint:
return k.Uint(v)
case []uint:
return k.Uints(v...)
case *uint:
return k.Uintp(v)
case uint8:
return k.Uint8(v)
case *uint8:
return k.Uint8p(v)
case uint16:
return k.Uint16(v)
case []uint16:
return k.Uint16s(v...)
case *uint16:
return k.Uint16p(v)
case uint32:
return k.Uint32(v)
case []uint32:
return k.Uint32s(v...)
case *uint32:
return k.Uint32p(v)
case uint64:
return k.Uint64(v)
case []uint64:
return k.Uint64s(v...)
case *uint64:
return k.Uint64p(v)
case float32:
return k.Float32(v)
case []float32:
return k.Float32s(v...)
case *float32:
return k.Float32p(v)
case float64:
return k.Float64(v)
case []float64:
return k.Float64s(v...)
case *float64:
return k.Float64p(v)
case complex64:
return k.Complex64(v)
case []complex64:
return k.Complex64s(v...)
case *complex64:
return k.Complex64p(v)
case uintptr:
return k.Uintptr(v)
case []uintptr:
return k.Uintptrs(v...)
case *uintptr:
return k.Uintptrp(v)
case []byte:
return k.Bytes(v)
case time.Duration:
return k.Dureation(v)
case []time.Duration:
return k.Dureations(v)
case *time.Duration:
return k.Dureationp(v)
case time.Time:
return k.Time(v)
case []time.Time:
return k.Times(v...)
case *time.Time:
return k.Timep(v)
case error:
return k.Error(v)
case []error:
return k.Errors(v...)
}
return Field{
key: k,
value: Value{
value: value,
vtype: TypeAny,
},
}
}
func (k Key) String(value string) Field {
return Field{
key: k,
value: stringValue(value),
}
}
func (k Key) Strings(value ...string) Field {
return Field{
key: k,
value: stringsValue(value),
}
}
func (k Key) Stringp(value *string) Field {
return Field{
key: k,
value: stringpValue(value),
}
}
func (k Key) Bool(value bool) Field {
return Field{
key: k,
value: boolValue(value),
}
}
func (k Key) Bools(value ...bool) Field {
return Field{
key: k,
value: boolsValue(value),
}
}
func (k Key) Boolp(value *bool) Field {
return Field{
key: k,
value: boolpValue(value),
}
}
func (k Key) Int(value int) Field {
return Field{
key: k,
value: intValue(value),
}
}
func (k Key) Ints(value ...int) Field {
return Field{
key: k,
value: intsValue(value),
}
}
func (k Key) Intp(value *int) Field {
return Field{
key: k,
value: intpValue(value),
}
}
func (k Key) Int8(value int8) Field {
return Field{
key: k,
value: int8Value(value),
}
}
func (k Key) Int8s(value ...int8) Field {
return Field{
key: k,
value: int8sValue(value),
}
}
func (k Key) Int8p(value *int8) Field {
return Field{
key: k,
value: int8pValue(value),
}
}
func (k Key) Int16(value int16) Field {
return Field{
key: k,
value: int16Value(value),
}
}
func (k Key) Int16s(value ...int16) Field {
return Field{
key: k,
value: int16sValue(value),
}
}
func (k Key) Int16p(value *int16) Field {
return Field{
key: k,
value: int16pValue(value),
}
}
func (k Key) Int32(value int32) Field {
return Field{
key: k,
value: int32Value(value),
}
}
func (k Key) Int32s(value ...int32) Field {
return Field{
key: k,
value: int32sValue(value),
}
}
func (k Key) Int32p(value *int32) Field {
return Field{
key: k,
value: int32pValue(value),
}
}
func (k Key) Int64(value int64) Field {
return Field{
key: k,
value: int64Value(value),
}
}
func (k Key) Int64s(value ...int64) Field {
return Field{
key: k,
value: int64sValue(value),
}
}
func (k Key) Int64p(value *int64) Field {
return Field{
key: k,
value: int64pValue(value),
}
}
func (k Key) Uint(value uint) Field {
return Field{
key: k,
value: uintValue(value),
}
}
func (k Key) Uints(value ...uint) Field {
return Field{
key: k,
value: uintsValue(value),
}
}
func (k Key) Uintp(value *uint) Field {
return Field{
key: k,
value: uintpValue(value),
}
}
func (k Key) Uint8(value uint8) Field {
return Field{
key: k,
value: uint8Value(value),
}
}
func (k Key) Uint8s(value ...uint8) Field {
return Field{
key: k,
value: uint8sValue(value),
}
}
func (k Key) Uint8p(value *uint8) Field {
return Field{
key: k,
value: uint8pValue(value),
}
}
func (k Key) Uint16(value uint16) Field {
return Field{
key: k,
value: uint16Value(value),
}
}
func (k Key) Uint16s(value ...uint16) Field {
return Field{
key: k,
value: uint16sValue(value),
}
}
func (k Key) Uint16p(value *uint16) Field {
return Field{
key: k,
value: uint16pValue(value),
}
}
func (k Key) Uint32(value uint32) Field {
return Field{
key: k,
value: uint32Value(value),
}
}
func (k Key) Uint32s(value ...uint32) Field {
return Field{
key: k,
value: uint32sValue(value),
}
}
func (k Key) Uint32p(value *uint32) Field {
return Field{
key: k,
value: uint32pValue(value),
}
}
func (k Key) Uint64(value uint64) Field {
return Field{
key: k,
value: uint64Value(value),
}
}
func (k Key) Uint64s(value ...uint64) Field {
return Field{
key: k,
value: uint64sValue(value),
}
}
func (k Key) Uint64p(value *uint64) Field {
return Field{
key: k,
value: uint64pValue(value),
}
}
func (k Key) Float32(value float32) Field {
return Field{
key: k,
value: float32Value(value),
}
}
func (k Key) Float32s(value ...float32) Field {
return Field{
key: k,
value: float32sValue(value),
}
}
func (k Key) Float32p(value *float32) Field {
return Field{
key: k,
value: float32pValue(value),
}
}
func (k Key) Float64(value float64) Field {
return Field{
key: k,
value: float64Value(value),
}
}
func (k Key) Float64s(value ...float64) Field {
return Field{
key: k,
value: float64sValue(value),
}
}
func (k Key) Float64p(value *float64) Field {
return Field{
key: k,
value: float64pValue(value),
}
}
func (k Key) Complex64(value complex64) Field {
return Field{
key: k,
value: complex64Value(value),
}
}
func (k Key) Complex64s(value ...complex64) Field {
return Field{
key: k,
value: complex64sValue(value),
}
}
func (k Key) Complex64p(value *complex64) Field {
return Field{
key: k,
value: complex64pValue(value),
}
}
func (k Key) Complex128(value complex128) Field {
return Field{
key: k,
value: complex128Value(value),
}
}
func (k Key) Complex128s(value []complex128) Field {
return Field{
key: k,
value: complex128sValue(value),
}
}
func (k Key) Complex128p(value *complex128) Field {
return Field{
key: k,
value: complex128pValue(value),
}
}
func (k Key) Uintptr(value uintptr) Field {
return Field{
key: k,
value: uintptrValue(value),
}
}
func (k Key) Uintptrs(value ...uintptr) Field {
return Field{
key: k,
value: uintptrsValue(value),
}
}
func (k Key) Uintptrp(value *uintptr) Field {
return Field{
key: k,
value: uintptrpValue(value),
}
}
func (k Key) Bytes(value []byte) Field {
return Field{
key: k,
value: bytesValue(value),
}
}
func (k Key) Dureation(value time.Duration) Field {
return Field{
key: k,
value: durationValue(value),
}
}
func (k Key) Dureations(value []time.Duration) Field {
return Field{
key: k,
value: durationsValue(value),
}
}
func (k Key) Dureationp(value *time.Duration) Field {
return Field{
key: k,
value: durationpValue(value),
}
}
func (k Key) Time(value time.Time) Field {
return Field{
key: k,
value: timeValue(value),
}
}
func (k Key) Times(value ...time.Time) Field {
return Field{
key: k,
value: timesValue(value),
}
}
func (k Key) Timep(value *time.Time) Field {
return Field{
key: k,
value: timepValue(value),
}
}
func (k Key) FormatTime(format string, value time.Time) Field {
return Field{
key: k,
value: formatTimeValue(format, value),
}
}
func (k Key) FormatTimes(format string, value ...time.Time) Field {
return Field{
key: k,
value: formatTimesValue(format, value),
}
}
func (k Key) FormatTimep(format string, value *time.Time) Field {
return Field{
key: k,
value: formatTimepValue(format, value),
}
}
func (k Key) Error(value error) Field {
return Field{
key: k,
value: errorValue(value),
}
}
func (k Key) Errors(value ...error) Field {
return Field{
key: k,
value: errorsValue(value),
}
}

View File

@@ -1,86 +0,0 @@
package field
import "fmt"
//go:generate stringer -type=Kind -linecomment -output=kind_string.go
type Kind int
const (
KindAny Kind = iota // any
KindArray // array
KindNil // nil
KindString // string
KindBool // bool
KindInt64 // int64
KindUint64 // uint64
KindFloat32 // float32
KindFloat64 // float64
KindComplex128 // complex128
KindBinary // bytes
KindDuration // duration
KindTime // time
KindError // error
KindGroup // group
KindClosure // closure
)
func (l Kind) MarshalJSON() ([]byte, error) {
return []byte("\"" + l.String() + "\""), nil
}
func (l *Kind) UnmarshalJSON(in []byte) error {
return l.UnmarshalText(in[1 : len(in)-1])
}
func (l Kind) MarshalText() ([]byte, error) {
return []byte(l.String()), nil
}
//nolint:gocyclo,cyclop
func (l *Kind) UnmarshalText(in []byte) error {
switch string(in) {
case KindAny.String():
*l = KindAny
case KindArray.String():
*l = KindArray
case KindNil.String():
*l = KindNil
case KindString.String():
*l = KindString
case KindBool.String():
*l = KindBool
case KindInt64.String():
*l = KindInt64
case KindUint64.String():
*l = KindUint64
case KindFloat32.String():
*l = KindFloat32
case KindFloat64.String():
*l = KindFloat64
case KindComplex128.String():
*l = KindComplex128
case KindBinary.String():
*l = KindBinary
case KindDuration.String():
*l = KindDuration
case KindTime.String():
*l = KindTime
case KindError.String():
*l = KindError
case KindGroup.String():
*l = KindGroup
case KindClosure.String():
*l = KindClosure
}
return fmt.Errorf("%w:filed(%v)", ErrUndefined, string(in))
}
func (l Kind) MarshalBinary() ([]byte, error) {
return []byte(l.String()), nil
}
func (l *Kind) UnmarshalBinary(in []byte) error {
return l.UnmarshalText(in)
}

View File

@@ -1,38 +0,0 @@
// Code generated by "stringer -type=Kind -linecomment -output=kind_string.go"; DO NOT EDIT.
package field
import "strconv"
func _() {
// An "invalid array index" compiler error signifies that the constant values have changed.
// Re-run the stringer command to generate them again.
var x [1]struct{}
_ = x[KindAny-0]
_ = x[KindArray-1]
_ = x[KindNil-2]
_ = x[KindString-3]
_ = x[KindBool-4]
_ = x[KindInt64-5]
_ = x[KindUint64-6]
_ = x[KindFloat32-7]
_ = x[KindFloat64-8]
_ = x[KindComplex128-9]
_ = x[KindBinary-10]
_ = x[KindDuration-11]
_ = x[KindTime-12]
_ = x[KindError-13]
_ = x[KindGroup-14]
_ = x[KindClosure-15]
}
const _Kind_name = "anyarraynilstringboolint64uint64float32float64complex128bytesdurationtimeerrorgroupclosure"
var _Kind_index = [...]uint8{0, 3, 8, 11, 17, 21, 26, 32, 39, 46, 56, 61, 69, 73, 78, 83, 90}
func (i Kind) String() string {
if i < 0 || i >= Kind(len(_Kind_index)-1) {
return "Kind(" + strconv.FormatInt(int64(i), 10) + ")"
}
return _Kind_name[_Kind_index[i]:_Kind_index[i+1]]
}

View File

@@ -1,11 +0,0 @@
package field
type LogValuer interface {
LogValue() any
}
type ClosureFn func() any
func (v ClosureFn) LogValue() any {
return v()
}

View File

@@ -1,112 +0,0 @@
package field
import "unicode/utf8"
// Copied from encoding/json/tables.go.
//
// safeSet holds the value true if the ASCII character with the given array
// position can be represented inside a JSON string without any further
// escaping.
//
// All values are true except for the ASCII control characters (0-31), the
// double quote ("), and the backslash character ("\").
//
//nolint:gochecknoglobals
var safeSet = [utf8.RuneSelf]bool{
' ': true,
'!': true,
'"': false,
'#': true,
'$': true,
'%': true,
'&': true,
'\'': true,
'(': true,
')': true,
'*': true,
'+': true,
',': true,
'-': true,
'.': true,
'/': true,
'0': true,
'1': true,
'2': true,
'3': true,
'4': true,
'5': true,
'6': true,
'7': true,
'8': true,
'9': true,
':': true,
';': true,
'<': true,
'=': true,
'>': true,
'?': true,
'@': true,
'A': true,
'B': true,
'C': true,
'D': true,
'E': true,
'F': true,
'G': true,
'H': true,
'I': true,
'J': true,
'K': true,
'L': true,
'M': true,
'N': true,
'O': true,
'P': true,
'Q': true,
'R': true,
'S': true,
'T': true,
'U': true,
'V': true,
'W': true,
'X': true,
'Y': true,
'Z': true,
'[': true,
'\\': false,
']': true,
'^': true,
'_': true,
'`': true,
'a': true,
'b': true,
'c': true,
'd': true,
'e': true,
'f': true,
'g': true,
'h': true,
'i': true,
'j': true,
'k': true,
'l': true,
'm': true,
'n': true,
'o': true,
'p': true,
'q': true,
'r': true,
's': true,
't': true,
'u': true,
'v': true,
'w': true,
'x': true,
'y': true,
'z': true,
'{': true,
'|': true,
'}': true,
'~': true,
'\u007f': true,
}

126
field/type.go Normal file
View File

@@ -0,0 +1,126 @@
package field
type Type uint32
const (
TypeAny Type = 1 << iota // any
TypeArray // array
TypeNil // nil
TypeString // string
TypeBool // bool
TypeInt // int
TypeInt8 // int8
TypeInt16 // int16
TypeInt32 // int32
TypeInt64 // int64
TypeUint // uint
TypeUint8 // uint8
TypeUint16 // uint16
TypeUint32 // uint32
TypeUint64 // uint64
TypeFloat32 // float32
TypeFloat64 // float64
TypeComplex64 // complex64
TypeComplex128 // complex128
TypeUintptr // uintptr
TypeBinary // bytes
TypeDuration // duration
TypeTime // time
TypeError // error
)
func (t Type) IsAny() bool {
return t&TypeAny > 0
}
func (t Type) IsArray() bool {
return t&TypeArray > 0
}
func (t Type) IsNil() bool {
return t&TypeNil > 0
}
func (t Type) IsBool() bool {
return t&TypeBool > 0
}
func (t Type) IsString() bool {
return t&TypeString > 0
}
func (t Type) IsInt() bool {
return t&TypeInt > 0
}
func (t Type) IsInt8() bool {
return t&TypeInt8 > 0
}
func (t Type) IsInt16() bool {
return t&TypeInt16 > 0
}
func (t Type) IsInt32() bool {
return t&TypeInt32 > 0
}
func (t Type) IsInt64() bool {
return t&TypeInt64 > 0
}
func (t Type) IsUint() bool {
return t&TypeUint > 0
}
func (t Type) IsUint8() bool {
return t&TypeUint8 > 0
}
func (t Type) IsUint16() bool {
return t&TypeUint16 > 0
}
func (t Type) IsUint32() bool {
return t&TypeUint32 > 0
}
func (t Type) IsUint64() bool {
return t&TypeUint64 > 0
}
func (t Type) IsFloat32() bool {
return t&TypeFloat32 > 0
}
func (t Type) IsFloat64() bool {
return t&TypeFloat64 > 0
}
func (t Type) IsComplex64() bool {
return t&TypeComplex64 > 0
}
func (t Type) IsComplex128() bool {
return t&TypeComplex128 > 0
}
func (t Type) IsUintptr() bool {
return t&TypeUintptr > 0
}
func (t Type) IsBinary() bool {
return t&TypeBinary > 0
}
func (t Type) IsDuration() bool {
return t&TypeDuration > 0
}
func (t Type) IsTime() bool {
return t&TypeTime > 0
}
func (t Type) IsError() bool {
return t&TypeError > 0
}

File diff suppressed because it is too large Load Diff

View File

@@ -10,8 +10,8 @@ import (
//nolint:gochecknoglobals //nolint:gochecknoglobals
var global = With(New(), var global = With(New(),
WithSource(2), WithCaller("caller", 1, false),
WithLevel(KeyLevel, level.Debug), WithLevel("level", level.Debug),
WithExit(level.Alert), WithExit(level.Alert),
WithPanic(level.Emergency), WithPanic(level.Emergency),
) )

View File

@@ -1,24 +0,0 @@
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
}

9
go.mod
View File

@@ -1,3 +1,10 @@
module gitoa.ru/go-4devs/log module gitoa.ru/go-4devs/log
go 1.20 go 1.17
require (
github.com/sirupsen/logrus v1.7.0
go.opentelemetry.io/otel v0.13.0
go.opentelemetry.io/otel/sdk v0.13.0
go.uber.org/zap v1.16.0
)

70
go.sum
View File

@@ -0,0 +1,70 @@
github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ=
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
github.com/DataDog/sketches-go v0.0.1/go.mod h1:Q5DbzQ+3AkgGwymQO7aZFNP7ns2lZKGtvRBzRXfdi60=
github.com/benbjohnson/clock v1.0.3/go.mod h1:bGMdMPoPVvcYyt1gHDf4J2KE153Yf9BuiUKYMaxlTDM=
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/go-cmp v0.5.2 h1:X2ev0eStA3AbceY54o37/0PQ/UWqKEiiO2dKL5OPaFM=
github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/gofuzz v1.1.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I=
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
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/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
github.com/sirupsen/logrus v1.7.0 h1:ShrD1U9pZB12TX0cVy0DtePoCH97K8EtX+mg7ZARUtM=
github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
github.com/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd0=
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
go.opentelemetry.io/otel v0.13.0 h1:2isEnyzjjJZq6r2EKMsFj4TxiQiexsM04AVhwbR/oBA=
go.opentelemetry.io/otel v0.13.0/go.mod h1:dlSNewoRYikTkotEnxdmuBHgzT+k/idJSfDv/FxEnOY=
go.opentelemetry.io/otel/sdk v0.13.0 h1:4VCfpKamZ8GtnepXxMRurSpHpMKkcxhtO33z1S4rGDQ=
go.opentelemetry.io/otel/sdk v0.13.0/go.mod h1:dKvLH8Uu8LcEPlSAUsfW7kMGaJBhk/1NYvpPZ6wIMbU=
go.uber.org/atomic v1.6.0 h1:Ezj3JGmsOnG1MoRWQkPBsKLe9DwWD9QeXzTRzzldNVk=
go.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ=
go.uber.org/multierr v1.5.0 h1:KCa4XfM8CWFCpxXRGok+Q0SS/0XBhMDbHHGABQLvD2A=
go.uber.org/multierr v1.5.0/go.mod h1:FeouvMocqHpRaaGuG9EjoKcStLC43Zu/fmqdUMPcKYU=
go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee h1:0mgffUl7nfd+FpvXMVz4IDEaUSmT1ysygQC7qYo7sG4=
go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA=
go.uber.org/zap v1.16.0 h1:uFRZXykJGK9lLY4HtgSw44DnIcAM+kRBP7x5m+NpAOM=
go.uber.org/zap v1.16.0/go.mod h1:MA8QOfq0BHJwdXa996Y4dYkAqRKB8/1K1QMMZVaNZjQ=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/lint v0.0.0-20190930215403-16217165b5de h1:5hukYrvBGR8/eNkX5mdUezrA6JiaEZDtJb9Ei+1LlBs=
golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc=
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037 h1:YyJpGZS1sBuBCzLAR1VEpK193GlqGZbnPFnPV/5Rsb4=
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5 h1:hKsoRgsbwY1NafxrwTs+k64bikrLBkAgPir1TNCj3Zs=
golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
honnef.co/go/tools v0.0.1-2019.2.3 h1:3JgtbtFHMiCmsznwGVTUWbgGov+pVqnlf1dEJTNAXeM=
honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=

View File

@@ -1,10 +0,0 @@
module gitoa.ru/go-4devs/log/handler/logrus
go 1.20
require (
github.com/sirupsen/logrus v1.9.3
gitoa.ru/go-4devs/log v0.5.1
)
require golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8 // indirect

View File

@@ -1,17 +0,0 @@
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/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 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
gitoa.ru/go-4devs/log v0.5.1 h1:rrIyjpUaw8AjDCf7ZuH0HgCRf370O3TV29yrU1xizWM=
gitoa.ru/go-4devs/log v0.5.1/go.mod h1:tREtjEH2cTHl0p3uCVcH9g5tlqtsVNI/tDQVfq53Ty4=
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8 h1:0A+M6Uqn+Eje4kHMK80dtF3JCXC4ykBgQG4Fe06QRhQ=
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=

View File

@@ -6,7 +6,6 @@ import (
"github.com/sirupsen/logrus" "github.com/sirupsen/logrus"
"gitoa.ru/go-4devs/log" "gitoa.ru/go-4devs/log"
"gitoa.ru/go-4devs/log/entry" "gitoa.ru/go-4devs/log/entry"
"gitoa.ru/go-4devs/log/field"
"gitoa.ru/go-4devs/log/level" "gitoa.ru/go-4devs/log/level"
) )
@@ -17,29 +16,25 @@ func Standard() log.Logger {
// New create new logrus handler. // New create new logrus handler.
func New(log *logrus.Logger) log.Logger { func New(log *logrus.Logger) log.Logger {
return func(ctx context.Context, data *entry.Entry) (int, error) { return func(ctx context.Context, e *entry.Entry) (int, error) {
lrgFields := make(logrus.Fields, data.Fields().Len()) lrgFields := make(logrus.Fields, e.Fields().Len())
data.Fields().Fields(func(f field.Field) bool { for _, field := range e.Fields() {
lrgFields[f.Key] = f.Value.Any() lrgFields[string(field.Key())] = field.AsInterface()
}
return true write := log.WithContext(ctx).WithFields(lrgFields)
}) switch e.Level() {
entry := log.WithContext(ctx).WithFields(lrgFields)
switch data.Level() {
case level.Emergency: case level.Emergency:
entry.Panic(data.Message()) write.Panic(e.Message())
case level.Alert: case level.Alert:
entry.Fatal(data.Message()) write.Fatal(e.Message())
case level.Critical, level.Error: case level.Critical, level.Error:
entry.Error(data.Message()) write.Error(e.Message())
case level.Warning: case level.Warning:
entry.Warn(data.Message()) write.Warn(e.Message())
case level.Notice, level.Info: case level.Notice, level.Info:
entry.Info(data.Message()) write.Info(e.Message())
case level.Debug: case level.Debug:
entry.Debug(data.Message()) write.Debug(e.Message())
} }
return 0, nil return 0, nil

View File

@@ -13,8 +13,6 @@ import (
) )
func TestNew(t *testing.T) { func TestNew(t *testing.T) {
t.Parallel()
ctx := context.Background() ctx := context.Background()
buf := &bytes.Buffer{} buf := &bytes.Buffer{}

View File

@@ -1,17 +0,0 @@
module gitoa.ru/go-4devs/log/handler/otel
go 1.21.5
require (
gitoa.ru/go-4devs/log v0.5.1
go.opentelemetry.io/otel v1.21.0
go.opentelemetry.io/otel/sdk v1.21.0
go.opentelemetry.io/otel/trace v1.21.0
)
require (
github.com/go-logr/logr v1.3.0 // indirect
github.com/go-logr/stdr v1.2.2 // indirect
go.opentelemetry.io/otel/metric v1.21.0 // indirect
golang.org/x/sys v0.14.0 // indirect
)

View File

@@ -1,27 +0,0 @@
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/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
github.com/go-logr/logr v1.3.0 h1:2y3SDp0ZXuc6/cjLSZ+Q3ir+QB9T/iG5yYRXqsagWSY=
github.com/go-logr/logr v1.3.0/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=
github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
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.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
gitoa.ru/go-4devs/log v0.5.1 h1:rrIyjpUaw8AjDCf7ZuH0HgCRf370O3TV29yrU1xizWM=
gitoa.ru/go-4devs/log v0.5.1/go.mod h1:tREtjEH2cTHl0p3uCVcH9g5tlqtsVNI/tDQVfq53Ty4=
go.opentelemetry.io/otel v1.21.0 h1:hzLeKBZEL7Okw2mGzZ0cc4k/A7Fta0uoPgaJCr8fsFc=
go.opentelemetry.io/otel v1.21.0/go.mod h1:QZzNPQPm1zLX4gZK4cMi+71eaorMSGT3A4znnUvNNEo=
go.opentelemetry.io/otel/metric v1.21.0 h1:tlYWfeo+Bocx5kLEloTjbcDwBuELRrIFxwdQ36PlJu4=
go.opentelemetry.io/otel/metric v1.21.0/go.mod h1:o1p3CA8nNHW8j5yuQLdc1eeqEaPfzug24uvsyIEJRWM=
go.opentelemetry.io/otel/sdk v1.21.0 h1:FTt8qirL1EysG6sTQRZ5TokkU8d0ugCj8htOgThZXQ8=
go.opentelemetry.io/otel/sdk v1.21.0/go.mod h1:Nna6Yv7PWTdgJHVRD9hIYywQBRx7pbox6nwBnZIxl/E=
go.opentelemetry.io/otel/trace v1.21.0 h1:WD9i5gzvoUPuXIXH24ZNBudiarZDKuekPqi/E8fpfLc=
go.opentelemetry.io/otel/trace v1.21.0/go.mod h1:LGbsEB0f9LGjN+OZaQQ26sohbOmiMR+BaslueVtS/qQ=
golang.org/x/sys v0.14.0 h1:Vz7Qs629MkJkGyHxUlRHizWJRG2j8fbQKjELVSNhy7Q=
golang.org/x/sys v0.14.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=

View File

@@ -4,10 +4,9 @@ import (
"context" "context"
"gitoa.ru/go-4devs/log/entry" "gitoa.ru/go-4devs/log/entry"
"gitoa.ru/go-4devs/log/field"
"gitoa.ru/go-4devs/log/level" "gitoa.ru/go-4devs/log/level"
"go.opentelemetry.io/otel/attribute" "go.opentelemetry.io/otel/api/trace"
"go.opentelemetry.io/otel/trace" "go.opentelemetry.io/otel/label"
) )
const ( const (
@@ -39,21 +38,19 @@ func levels(lvl level.Level) Level {
return 0 return 0
} }
func addEvent(ctx context.Context, data *entry.Entry) { func addEvent(ctx context.Context, e *entry.Entry) {
span := trace.SpanFromContext(ctx) span := trace.SpanFromContext(ctx)
attrs := make([]attribute.KeyValue, 0, data.Fields().Len()+levelFields) attrs := make([]label.KeyValue, 0, e.Fields().Len()+levelFields)
lvl := levels(data.Level()) lvl := levels(e.Level())
attrs = append(attrs, attrs = append(attrs,
attribute.String(fieldSeverityText, lvl.String()), label.String(fieldSeverityText, lvl.String()),
attribute.Int(fieldSeverityNumber, int(lvl)), label.Int(fieldSeverityNumber, int(lvl)),
) )
data.Fields().Fields(func(f field.Field) bool { for _, field := range e.Fields() {
attrs = append(attrs, attribute.String(f.Key, f.Value.String())) attrs = append(attrs, label.String(string(field.Key()), field.Value().String()))
}
return true span.AddEvent(ctx, e.Message(), attrs...)
})
span.AddEvent(data.Message(), trace.WithAttributes(attrs...))
} }

View File

@@ -1,10 +0,0 @@
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

View File

@@ -1,16 +0,0 @@
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=

View File

@@ -5,7 +5,6 @@ import (
"gitoa.ru/go-4devs/log" "gitoa.ru/go-4devs/log"
"gitoa.ru/go-4devs/log/entry" "gitoa.ru/go-4devs/log/entry"
"gitoa.ru/go-4devs/log/field"
"gitoa.ru/go-4devs/log/level" "gitoa.ru/go-4devs/log/level"
"go.uber.org/zap" "go.uber.org/zap"
) )
@@ -37,28 +36,26 @@ func Development(options ...zap.Option) log.Logger {
} }
// New create handler by zap logger. // New create handler by zap logger.
func New(logger *zap.Logger) log.Logger { func New(z *zap.Logger) log.Logger {
return func(ctx context.Context, data *entry.Entry) (int, error) { return func(ctx context.Context, e *entry.Entry) (int, error) {
zf := make([]zap.Field, 0, data.Fields().Len()) zf := make([]zap.Field, e.Fields().Len())
data.Fields().Fields(func(f field.Field) bool { for i, field := range e.Fields() {
zf = append(zf, zap.Any(f.Key, f.Value.Any())) zf[i] = zap.Any(string(field.Key()), field.AsInterface())
}
return true switch e.Level() {
})
switch data.Level() {
case level.Emergency: case level.Emergency:
logger.Fatal(data.Message(), zf...) z.Fatal(e.Message(), zf...)
case level.Alert: case level.Alert:
logger.Panic(data.Message(), zf...) z.Panic(e.Message(), zf...)
case level.Critical, level.Error: case level.Critical, level.Error:
logger.Error(data.Message(), zf...) z.Error(e.Message(), zf...)
case level.Warning: case level.Warning:
logger.Warn(data.Message(), zf...) z.Warn(e.Message(), zf...)
case level.Notice, level.Info: case level.Notice, level.Info:
logger.Info(data.Message(), zf...) z.Info(e.Message(), zf...)
case level.Debug: case level.Debug:
logger.Debug(data.Message(), zf...) z.Debug(e.Message(), zf...)
} }
return 0, nil return 0, nil

View File

@@ -14,8 +14,6 @@ import (
) )
func TestNew(t *testing.T) { func TestNew(t *testing.T) {
t.Parallel()
ctx := context.Background() ctx := context.Background()
buf := &bytes.Buffer{} buf := &bytes.Buffer{}
core := zapcore.NewCore(zapcore.NewJSONEncoder(zapcore.EncoderConfig{ core := zapcore.NewCore(zapcore.NewJSONEncoder(zapcore.EncoderConfig{

View File

@@ -1,42 +0,0 @@
package buffer
import "sync"
const bufferSize = 1024
type Buffer []byte
// Having an initial size gives a dramatic speedup.
//
//nolint:gochecknoglobals
var bufPool = sync.Pool{
New: func() any {
b := make([]byte, 0, bufferSize)
return (*Buffer)(&b)
},
}
//nolint:forcetypeassert
func New() *Buffer {
return bufPool.Get().(*Buffer)
}
func (b *Buffer) Free() {
// To reduce peak allocation, return only smaller buffers to the pool.
const maxBufferSize = 16 << 10
if cap(*b) <= maxBufferSize {
*b = (*b)[:0]
bufPool.Put(b)
}
}
func (b *Buffer) WriteString(s string) (int, error) {
*b = append(*b, s...)
return len(s), nil
}
func (b *Buffer) String() string {
return string(*b)
}

View File

@@ -1,7 +1,6 @@
package level package level
import ( import (
"encoding"
"encoding/json" "encoding/json"
"strings" "strings"
) )
@@ -9,12 +8,8 @@ import (
//go:generate stringer -type=Level -linecomment //go:generate stringer -type=Level -linecomment
var ( var (
_ json.Marshaler = Level(0) _ json.Marshaler = Level(0)
_ json.Unmarshaler = (*Level)(nil) _ json.Unmarshaler = (*Level)(nil)
_ encoding.TextMarshaler = Level(0)
_ encoding.TextUnmarshaler = (*Level)(nil)
_ encoding.BinaryMarshaler = Level(0)
_ encoding.BinaryUnmarshaler = (*Level)(nil)
) )
// Level log. // Level log.
@@ -22,9 +17,9 @@ type Level uint32
// available log levels. // available log levels.
const ( const (
Emergency Level = iota // emerg Emergency Level = iota // emergency
Alert // alert Alert // alert
Critical // crit Critical // critical
Error // error Error // error
Warning // warning Warning // warning
Notice // notice Notice // notice
@@ -32,6 +27,10 @@ const (
Debug // debug Debug // debug
) )
func (l Level) MarshalJSON() ([]byte, error) {
return json.Marshal(l.String())
}
func (l Level) Is(level Level) bool { func (l Level) Is(level Level) bool {
return level == l return level == l
} }
@@ -40,34 +39,13 @@ func (l Level) Enabled(level Level) bool {
return l <= level return l <= level
} }
func (l Level) MarshalJSON() ([]byte, error) {
return []byte("\"" + l.String() + "\""), nil
}
func (l *Level) UnmarshalJSON(in []byte) error { func (l *Level) UnmarshalJSON(in []byte) error {
lvl := Parse(string(in[1 : len(in)-1])) var v string
*l = lvl if err := json.Unmarshal(in, &v); err != nil {
return err
}
return nil lvl := Parse(v)
}
func (l Level) MarshalText() ([]byte, error) {
return []byte(l.String()), nil
}
func (l *Level) UnmarshalText(in []byte) error {
lvl := Parse(string(in))
*l = lvl
return nil
}
func (l Level) MarshalBinary() ([]byte, error) {
return []byte(l.String()), nil
}
func (l *Level) UnmarshalBinary(in []byte) error {
lvl := Parse(string(in))
*l = lvl *l = lvl
return nil return nil
@@ -81,11 +59,11 @@ func Parse(lvl string) Level {
return Info return Info
case "notice", "Notice", "NOTICE": case "notice", "Notice", "NOTICE":
return Notice return Notice
case "warning", "Warning", "WARNING", "warm", "Warm", "WARN": case "warning", "Warning", "WARNING":
return Warning return Warning
case "error", "Error", "ERROR", "err", "Err", "ERR": case "error", "Error", "ERROR":
return Error return Error
case "critical", "Critical", "CRITICAL", "crit", "Crit", "CRIT": case "critical", "Critical", "CRITICAL":
return Critical return Critical
case "alert", "Alert", "ALERT": case "alert", "Alert", "ALERT":
return Alert return Alert

View File

@@ -18,9 +18,9 @@ func _() {
_ = x[Debug-7] _ = x[Debug-7]
} }
const _Level_name = "emergalertcriterrorwarningnoticeinfodebug" const _Level_name = "emergencyalertcriticalerrorwarningnoticeinfodebug"
var _Level_index = [...]uint8{0, 5, 10, 14, 19, 26, 32, 36, 41} var _Level_index = [...]uint8{0, 9, 14, 22, 27, 34, 40, 44, 49}
func (i Level) String() string { func (i Level) String() string {
if i >= Level(len(_Level_index)-1) { if i >= Level(len(_Level_index)-1) {

View File

@@ -1,65 +0,0 @@
package level_test
import (
"testing"
"gitoa.ru/go-4devs/log/level"
)
func TestMarshalJSON(t *testing.T) {
t.Parallel()
levels := map[level.Level]string{
level.Emergency: `"emerg"`,
level.Alert: `"alert"`,
level.Critical: `"crit"`,
level.Error: `"error"`,
level.Warning: `"warning"`,
level.Notice: `"notice"`,
level.Info: `"info"`,
level.Debug: `"debug"`,
}
for level, expect := range levels {
actual, err := level.MarshalJSON()
if err != nil {
t.Errorf("%s got err: %s", level, err)
continue
}
if string(actual) != expect {
t.Errorf("%s got: %s expect: %s", level, actual, expect)
}
}
}
func TestUnmarshalJSON(t *testing.T) {
t.Parallel()
levels := map[level.Level][]string{
level.Emergency: {`"emerg"`, `"Emerg"`},
level.Alert: {`"alert"`, `"ALERT"`},
level.Critical: {`"crit"`, `"critical"`},
level.Error: {`"error"`, `"ERR"`},
level.Warning: {`"warning"`, `"Warning"`},
level.Notice: {`"notice"`},
level.Info: {`"info"`},
level.Debug: {`"debug"`, `"DEBUG"`},
}
for expect, actuals := range levels {
for _, actual := range actuals {
var level level.Level
if err := level.UnmarshalJSON([]byte(actual)); err != nil {
t.Errorf("%s got err: %s", level, err)
continue
}
if !level.Is(expect) {
t.Errorf("%s got: %s expect: %s", actual, level, expect)
}
}
}
}

142
logger.go
View File

@@ -2,6 +2,7 @@ package log
import ( import (
"context" "context"
"errors"
"fmt" "fmt"
"io" "io"
"os" "os"
@@ -13,7 +14,10 @@ import (
var _ io.Writer = (Logger)(nil) var _ io.Writer = (Logger)(nil)
const badKey = "!BADKEY" var (
ErrIgnoredKey = errors.New("ignored key without a value")
ErrNonStringKeys = errors.New("ignored key-value pairs with non-string keys")
)
func writeOutput(_ int, err error) { func writeOutput(_ int, err error) {
if err != nil { if err != nil {
@@ -24,62 +28,73 @@ func writeOutput(_ int, err error) {
// Logger logged message. // Logger logged message.
type Logger func(ctx context.Context, entry *entry.Entry) (int, error) type Logger func(ctx context.Context, entry *entry.Entry) (int, error)
func (l Logger) log(ctx context.Context, level level.Level, args ...interface{}) {
writeOutput(l.write(ctx, level, fmt.Sprint(args...)))
}
func (l Logger) Write(in []byte) (int, error) { func (l Logger) Write(in []byte) (int, error) {
return l.write(context.Background(), level.Info, string(in)) return l.write(context.Background(), level.Info, string(in))
} }
func (l Logger) write(ctx context.Context, level level.Level, msg string, fields ...field.Field) (int, error) { func (l Logger) write(ctx context.Context, level level.Level, msg string, fields ...field.Field) (int, error) {
data := entry.Get() e := entry.Get()
defer func() { defer func() {
entry.Put(data) entry.Put(e)
}() }()
return l(ctx, data.SetLevel(level).SetMessage(msg).Add(fields...)) return l(ctx, e.SetLevel(level).SetMessage(msg).Add(fields...))
} }
func (l Logger) writef(ctx context.Context, level level.Level, format string, args ...interface{}) (int, error) { func (l Logger) logKVs(ctx context.Context, level level.Level, msg string, args ...interface{}) {
data := entry.Get() writeOutput(l.write(ctx, level, msg, l.kv(ctx, args...)...))
defer func() {
entry.Put(data)
}()
return l(ctx, data.SetLevel(level).SetMessagef(format, args...))
} }
func (l Logger) kv(_ context.Context, args ...interface{}) field.Fields { func (l Logger) logKV(ctx context.Context, level level.Level, msg string, fields ...field.Field) {
kvEntry := entry.Get() writeOutput(l.write(ctx, level, msg, fields...))
}
func (l Logger) logf(ctx context.Context, level level.Level, format string, args ...interface{}) {
writeOutput(l.write(ctx, level, fmt.Sprintf(format, args...)))
}
func (l Logger) logln(ctx context.Context, level level.Level, args ...interface{}) {
writeOutput(l.write(ctx, level, fmt.Sprintln(args...)))
}
func (l Logger) kv(ctx context.Context, args ...interface{}) field.Fields {
e := entry.Get()
defer func() { defer func() {
entry.Put(kvEntry) entry.Put(e)
}() }()
for i := 0; i < len(args); i++ { for i := 0; i < len(args); i++ {
if f, ok := args[i].(field.Field); ok { if f, ok := args[i].(field.Field); ok {
kvEntry = kvEntry.Add(f) e = e.Add(f)
continue continue
} }
if i == len(args)-1 { if i == len(args)-1 {
kvEntry = kvEntry.AddAny(badKey, args[i]) l.logKV(ctx, level.Critical, fmt.Sprint("Ignored key without a value.", args[i]), e.Fields()...)
break break
} }
key, val := args[i], args[i+1] i++
key, val := args[i-1], args[i]
if keyStr, ok := key.(string); ok { if keyStr, ok := key.(string); ok {
kvEntry = kvEntry.AddAny(keyStr, val) e = e.AddAny(keyStr, val)
i++
continue continue
} }
kvEntry = kvEntry.AddAny(badKey, args[i]) l.logKV(ctx, level.Critical, fmt.Sprint("Ignored key-value pairs with non-string keys.", key, val), e.Fields()...)
} }
return kvEntry.Fields() return e.Fields()
} }
// With adds middlewares to logger. // With adds middlewares to logger.
@@ -89,207 +104,207 @@ func (l Logger) With(mw ...Middleware) Logger {
// Emerg log by emergency level. // Emerg log by emergency level.
func (l Logger) Emerg(ctx context.Context, args ...interface{}) { func (l Logger) Emerg(ctx context.Context, args ...interface{}) {
writeOutput(l.writef(ctx, level.Emergency, "", args...)) l.log(ctx, level.Emergency, args...)
} }
// Alert log by alert level. // Alert log by alert level.
func (l Logger) Alert(ctx context.Context, args ...interface{}) { func (l Logger) Alert(ctx context.Context, args ...interface{}) {
writeOutput(l.writef(ctx, level.Alert, "", args...)) l.log(ctx, level.Alert, args...)
} }
// Crit log by critical level. // Crit log by critical level.
func (l Logger) Crit(ctx context.Context, args ...interface{}) { func (l Logger) Crit(ctx context.Context, args ...interface{}) {
writeOutput(l.writef(ctx, level.Critical, "", args...)) l.log(ctx, level.Critical, args...)
} }
// Err log by error level. // Err log by error level.
func (l Logger) Err(ctx context.Context, args ...interface{}) { func (l Logger) Err(ctx context.Context, args ...interface{}) {
writeOutput(l.writef(ctx, level.Error, "", args...)) l.log(ctx, level.Error, args...)
} }
// Warn log by warning level. // Warn log by warning level.
func (l Logger) Warn(ctx context.Context, args ...interface{}) { func (l Logger) Warn(ctx context.Context, args ...interface{}) {
writeOutput(l.writef(ctx, level.Warning, "", args...)) l.log(ctx, level.Warning, args...)
} }
// Notice log by notice level. // Notice log by notice level.
func (l Logger) Notice(ctx context.Context, args ...interface{}) { func (l Logger) Notice(ctx context.Context, args ...interface{}) {
writeOutput(l.writef(ctx, level.Notice, "", args...)) l.log(ctx, level.Notice, args...)
} }
// Info log by info level. // Info log by info level.
func (l Logger) Info(ctx context.Context, args ...interface{}) { func (l Logger) Info(ctx context.Context, args ...interface{}) {
writeOutput(l.writef(ctx, level.Info, "", args...)) l.log(ctx, level.Info, args...)
} }
// Debug log by debug level. // Debug log by debug level.
func (l Logger) Debug(ctx context.Context, args ...interface{}) { func (l Logger) Debug(ctx context.Context, args ...interface{}) {
writeOutput(l.writef(ctx, level.Debug, "", args...)) l.log(ctx, level.Debug, args...)
} }
// Print log by info level and arguments. // Print log by info level and arguments.
func (l Logger) Print(args ...interface{}) { func (l Logger) Print(args ...interface{}) {
writeOutput(l.writef(context.Background(), level.Info, "", args...)) l.log(context.Background(), level.Info, args...)
} }
// Fatal log by alert level and arguments. // Fatal log by alert level and arguments.
func (l Logger) Fatal(args ...interface{}) { func (l Logger) Fatal(args ...interface{}) {
writeOutput(l.writef(context.Background(), level.Alert, "", args...)) l.log(context.Background(), level.Alert, args...)
} }
// Panic log by emergency level and arguments. // Panic log by emergency level and arguments.
func (l Logger) Panic(args ...interface{}) { func (l Logger) Panic(args ...interface{}) {
writeOutput(l.writef(context.Background(), level.Emergency, "", args...)) l.log(context.Background(), level.Emergency, args...)
} }
// Println log by info level and arguments. // Println log by info level and arguments.
func (l Logger) Println(args ...interface{}) { func (l Logger) Println(args ...interface{}) {
writeOutput(l.write(context.Background(), level.Info, fmt.Sprintln(args...))) l.logln(context.Background(), level.Info, args...)
} }
// Fatalln log by alert level and arguments. // Fatalln log by alert level and arguments.
func (l Logger) Fatalln(args ...interface{}) { func (l Logger) Fatalln(args ...interface{}) {
writeOutput(l.write(context.Background(), level.Alert, fmt.Sprintln(args...))) l.logln(context.Background(), level.Alert, args...)
} }
// Panicln log by emergency level and arguments. // Panicln log by emergency level and arguments.
func (l Logger) Panicln(args ...interface{}) { func (l Logger) Panicln(args ...interface{}) {
writeOutput(l.write(context.Background(), level.Emergency, fmt.Sprintln(args...))) l.logln(context.Background(), level.Emergency, args...)
} }
// EmergKVs sugared log by emergency level and key-values. // EmergKVs sugared log by emergency level and key-values.
func (l Logger) EmergKVs(ctx context.Context, msg string, args ...interface{}) { func (l Logger) EmergKVs(ctx context.Context, msg string, args ...interface{}) {
writeOutput(l.write(ctx, level.Emergency, msg, l.kv(ctx, args...)...)) l.logKVs(ctx, level.Emergency, msg, args...)
} }
// AlertKVs sugared log by alert level and key-values. // AlertKVs sugared log by alert level and key-values.
func (l Logger) AlertKVs(ctx context.Context, msg string, args ...interface{}) { func (l Logger) AlertKVs(ctx context.Context, msg string, args ...interface{}) {
writeOutput(l.write(ctx, level.Alert, msg, l.kv(ctx, args...)...)) l.logKVs(ctx, level.Alert, msg, args...)
} }
// CritKVs sugared log by critcal level and key-values. // CritKVs sugared log by critcal level and key-values.
func (l Logger) CritKVs(ctx context.Context, msg string, args ...interface{}) { func (l Logger) CritKVs(ctx context.Context, msg string, args ...interface{}) {
writeOutput(l.write(ctx, level.Critical, msg, l.kv(ctx, args...)...)) l.logKVs(ctx, level.Critical, msg, args...)
} }
// ErrKVs sugared log by error level and key-values. // ErrKVs sugared log by error level and key-values.
func (l Logger) ErrKVs(ctx context.Context, msg string, args ...interface{}) { func (l Logger) ErrKVs(ctx context.Context, msg string, args ...interface{}) {
writeOutput(l.write(ctx, level.Error, msg, l.kv(ctx, args...)...)) l.logKVs(ctx, level.Error, msg, args...)
} }
// WarnKVs sugared log by warning level and key-values. // WarnKVs sugared log by warning level and key-values.
func (l Logger) WarnKVs(ctx context.Context, msg string, args ...interface{}) { func (l Logger) WarnKVs(ctx context.Context, msg string, args ...interface{}) {
writeOutput(l.write(ctx, level.Warning, msg, l.kv(ctx, args...)...)) l.logKVs(ctx, level.Warning, msg, args...)
} }
// NoticeKVs sugared log by notice level and key-values. // NoticeKVs sugared log by notice level and key-values.
func (l Logger) NoticeKVs(ctx context.Context, msg string, args ...interface{}) { func (l Logger) NoticeKVs(ctx context.Context, msg string, args ...interface{}) {
writeOutput(l.write(ctx, level.Notice, msg, l.kv(ctx, args...)...)) l.logKVs(ctx, level.Notice, msg, args...)
} }
// InfoKVs sugared log by info level and key-values. // InfoKVs sugared log by info level and key-values.
func (l Logger) InfoKVs(ctx context.Context, msg string, args ...interface{}) { func (l Logger) InfoKVs(ctx context.Context, msg string, args ...interface{}) {
writeOutput(l.write(ctx, level.Info, msg, l.kv(ctx, args...)...)) l.logKVs(ctx, level.Info, msg, args...)
} }
// DebugKVs sugared log by debug level and key-values. // DebugKVs sugared log by debug level and key-values.
func (l Logger) DebugKVs(ctx context.Context, msg string, args ...interface{}) { func (l Logger) DebugKVs(ctx context.Context, msg string, args ...interface{}) {
writeOutput(l.write(ctx, level.Debug, msg, l.kv(ctx, args...)...)) l.logKVs(ctx, level.Debug, msg, args...)
} }
// EmergKV log by emergency level and key-values. // EmergKV log by emergency level and key-values.
func (l Logger) EmergKV(ctx context.Context, msg string, args ...field.Field) { func (l Logger) EmergKV(ctx context.Context, msg string, args ...field.Field) {
writeOutput(l.write(ctx, level.Emergency, msg, args...)) l.logKV(ctx, level.Emergency, msg, args...)
} }
// AlertKV log by alert level and key-values. // AlertKV log by alert level and key-values.
func (l Logger) AlertKV(ctx context.Context, msg string, args ...field.Field) { func (l Logger) AlertKV(ctx context.Context, msg string, args ...field.Field) {
writeOutput(l.write(ctx, level.Alert, msg, args...)) l.logKV(ctx, level.Alert, msg, args...)
} }
// CritKV log by critcal level and key-values. // CritKV log by critcal level and key-values.
func (l Logger) CritKV(ctx context.Context, msg string, args ...field.Field) { func (l Logger) CritKV(ctx context.Context, msg string, args ...field.Field) {
writeOutput(l.write(ctx, level.Critical, msg, args...)) l.logKV(ctx, level.Critical, msg, args...)
} }
// ErrKV log by error level and key-values. // ErrKV log by error level and key-values.
func (l Logger) ErrKV(ctx context.Context, msg string, args ...field.Field) { func (l Logger) ErrKV(ctx context.Context, msg string, args ...field.Field) {
writeOutput(l.write(ctx, level.Error, msg, args...)) l.logKV(ctx, level.Error, msg, args...)
} }
// WarnKV log by warning level and key-values. // WarnKV log by warning level and key-values.
func (l Logger) WarnKV(ctx context.Context, msg string, args ...field.Field) { func (l Logger) WarnKV(ctx context.Context, msg string, args ...field.Field) {
writeOutput(l.write(ctx, level.Warning, msg, args...)) l.logKV(ctx, level.Warning, msg, args...)
} }
// NoticeKV log by notice level and key-values. // NoticeKV log by notice level and key-values.
func (l Logger) NoticeKV(ctx context.Context, msg string, args ...field.Field) { func (l Logger) NoticeKV(ctx context.Context, msg string, args ...field.Field) {
writeOutput(l.write(ctx, level.Notice, msg, args...)) l.logKV(ctx, level.Notice, msg, args...)
} }
// InfoKV log by info level and key-values. // InfoKV log by info level and key-values.
func (l Logger) InfoKV(ctx context.Context, msg string, args ...field.Field) { func (l Logger) InfoKV(ctx context.Context, msg string, args ...field.Field) {
writeOutput(l.write(ctx, level.Info, msg, args...)) l.logKV(ctx, level.Info, msg, args...)
} }
// DebugKV log by debug level and key-values. // DebugKV log by debug level and key-values.
func (l Logger) DebugKV(ctx context.Context, msg string, args ...field.Field) { func (l Logger) DebugKV(ctx context.Context, msg string, args ...field.Field) {
writeOutput(l.write(ctx, level.Debug, msg, args...)) l.logKV(ctx, level.Debug, msg, args...)
} }
// Emergf log by emergency level by format and arguments. // Emergf log by emergency level by format and arguments.
func (l Logger) Emergf(ctx context.Context, format string, args ...interface{}) { func (l Logger) Emergf(ctx context.Context, format string, args ...interface{}) {
writeOutput(l.writef(ctx, level.Emergency, format, args...)) l.logf(ctx, level.Emergency, format, args...)
} }
// Alertf log by alert level by format and arguments. // Alertf log by alert level by format and arguments.
func (l Logger) Alertf(ctx context.Context, format string, args ...interface{}) { func (l Logger) Alertf(ctx context.Context, format string, args ...interface{}) {
writeOutput(l.writef(ctx, level.Alert, format, args...)) l.logf(ctx, level.Alert, format, args...)
} }
// Critf log by critical level by format and arguments. // Critf log by critical level by format and arguments.
func (l Logger) Critf(ctx context.Context, format string, args ...interface{}) { func (l Logger) Critf(ctx context.Context, format string, args ...interface{}) {
writeOutput(l.writef(ctx, level.Critical, format, args...)) l.logf(ctx, level.Critical, format, args...)
} }
// Errf log by error level by format and arguments. // Errf log by error level by format and arguments.
func (l Logger) Errf(ctx context.Context, format string, args ...interface{}) { func (l Logger) Errf(ctx context.Context, format string, args ...interface{}) {
writeOutput(l.writef(ctx, level.Error, format, args...)) l.logf(ctx, level.Error, format, args...)
} }
// Warnf log by warning level by format and arguments. // Warnf log by warning level by format and arguments.
func (l Logger) Warnf(ctx context.Context, format string, args ...interface{}) { func (l Logger) Warnf(ctx context.Context, format string, args ...interface{}) {
writeOutput(l.writef(ctx, level.Warning, format, args...)) l.logf(ctx, level.Warning, format, args...)
} }
// Noticef log by notice level by format and arguments. // Noticef log by notice level by format and arguments.
func (l Logger) Noticef(ctx context.Context, format string, args ...interface{}) { func (l Logger) Noticef(ctx context.Context, format string, args ...interface{}) {
writeOutput(l.writef(ctx, level.Notice, format, args...)) l.logf(ctx, level.Notice, format, args...)
} }
// Infof log by info level by format and arguments. // Infof log by info level by format and arguments.
func (l Logger) Infof(ctx context.Context, format string, args ...interface{}) { func (l Logger) Infof(ctx context.Context, format string, args ...interface{}) {
writeOutput(l.writef(ctx, level.Info, format, args...)) l.logf(ctx, level.Info, format, args...)
} }
// Debugf log by debug level by format and arguments. // Debugf log by debug level by format and arguments.
func (l Logger) Debugf(ctx context.Context, format string, args ...interface{}) { func (l Logger) Debugf(ctx context.Context, format string, args ...interface{}) {
writeOutput(l.writef(ctx, level.Debug, format, args...)) l.logf(ctx, level.Debug, format, args...)
} }
// Printf log by info level by format and arguments without context. // Printf log by info level by format and arguments without context.
func (l Logger) Printf(format string, args ...interface{}) { func (l Logger) Printf(format string, args ...interface{}) {
writeOutput(l.writef(context.Background(), level.Info, format, args...)) l.logf(context.Background(), level.Info, format, args...)
} }
// Fatalf log by alert level by format and arguments without context. // Fatalf log by alert level by format and arguments without context.
func (l Logger) Fatalf(format string, args ...interface{}) { func (l Logger) Fatalf(format string, args ...interface{}) {
writeOutput(l.writef(context.Background(), level.Alert, format, args...)) l.logf(context.Background(), level.Alert, format, args...)
} }
// Panicf log by emergency level and arguments without context. // Panicf log by emergency level and arguments without context.
func (l Logger) Panicf(format string, args ...interface{}) { func (l Logger) Panicf(format string, args ...interface{}) {
writeOutput(l.writef(context.Background(), level.Emergency, format, args...)) l.logf(context.Background(), level.Emergency, format, args...)
} }
func (l Logger) Writer(ctx context.Context, level level.Level, fields ...field.Field) io.Writer { func (l Logger) Writer(ctx context.Context, level level.Level, fields ...field.Field) io.Writer {
@@ -301,7 +316,6 @@ func (l Logger) Writer(ctx context.Context, level level.Level, fields ...field.F
} }
} }
//nolint:containedctx
type writer struct { type writer struct {
ctx context.Context ctx context.Context
level level.Level level level.Level

View File

@@ -9,14 +9,12 @@ func ExampleNew_withCaller() {
logger := log.With( logger := log.With(
log.New(log.WithStdout()), log.New(log.WithStdout()),
log.WithLevel("level", level.Debug), log.WithLevel("level", level.Debug),
log.WithSource(3), log.WithCaller("caller", 2, false),
) )
logger.Err(ctx, "same error message") logger.Err(ctx, "same error message")
logger.InfoKVs(ctx, "same info message", "api-version", 0.1) logger.InfoKVs(ctx, "same info message", "api-version", 0.1)
_, _ = logger.Write([]byte("same write message"))
// Output: // Output:
// msg="same error message" level=error source=logger_example_caller_test.go:14 // msg="same error message" level=error caller=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 info message" api-version=0.1 level=info caller=logger_example_caller_test.go:15
// msg="same write message" level=info source=logger_example_caller_test.go:16
} }

View File

@@ -1,7 +1,6 @@
package logrus_test package log_test
import ( import (
"context"
"io" "io"
"os" "os"
@@ -11,7 +10,6 @@ import (
) )
func ExampleNew_logrusHandler() { func ExampleNew_logrusHandler() {
ctx := context.Background()
lgrs := slogrus.New() lgrs := slogrus.New()
lgrs.SetOutput(os.Stdout) lgrs.SetOutput(os.Stdout)
lgrs.SetFormatter(&slogrus.TextFormatter{ lgrs.SetFormatter(&slogrus.TextFormatter{

View File

@@ -2,12 +2,9 @@ package log_test
import ( import (
"context" "context"
"errors"
"fmt" "fmt"
"math"
"os" "os"
"sync/atomic" "sync/atomic"
"time"
"gitoa.ru/go-4devs/log" "gitoa.ru/go-4devs/log"
"gitoa.ru/go-4devs/log/entry" "gitoa.ru/go-4devs/log/entry"
@@ -15,11 +12,12 @@ import (
"gitoa.ru/go-4devs/log/level" "gitoa.ru/go-4devs/log/level"
) )
//nolint:gochecknoglobals
var ctx = context.Background() var ctx = context.Background()
func setStdout() { func setStdout() {
// set stout for example by default stderror // set stout for example by default stderror
log.SetLogger(log.New(log.WithStdout()).With(log.WithLevel(log.KeyLevel, level.Debug))) log.SetLogger(log.New(log.WithStdout()).With(log.WithLevel("level", level.Debug)))
} }
func ExampleNew() { func ExampleNew() {
@@ -37,7 +35,7 @@ func ExampleInfo() {
func ExampleErrKV() { func ExampleErrKV() {
setStdout() setStdout()
log.ErrKVs(ctx, "same message", "key", "addition value") log.ErrKVs(ctx, "same message", "key", "addition value")
// Output: msg="same message" key="addition value" level=error // Output: msg="same message" key=addition value level=error
} }
func ExampleNew_errf() { func ExampleNew_errf() {
@@ -49,186 +47,40 @@ func ExampleNew_errf() {
func ExampleNew_debugKV() { func ExampleNew_debugKV() {
logger := log.New(log.WithStdout()).With(log.WithLevel("level", level.Debug)) logger := log.New(log.WithStdout()).With(log.WithLevel("level", level.Debug))
logger.DebugKVs(ctx, "same message", "error", os.ErrNotExist) logger.DebugKVs(ctx, "same message", "error", os.ErrNotExist)
// Output: msg="same message" error="file does not exist" level=debug // Output: msg="same message" error=file does not exist level=debug
} }
func ExampleNew_level() { func ExampleNew_level() {
logger := log.New(log.WithStdout()).With(log.WithLevel("level", level.Error))
logger.Err(ctx, "same error message")
// Output: msg="same error message" level=error
}
func ExampleNew_level_info() {
logger := log.New(log.WithStdout()).With(log.WithLevel("level", level.Error)) logger := log.New(log.WithStdout()).With(log.WithLevel("level", level.Error))
logger.Info(ctx, "same message") logger.Info(ctx, "same message")
// Output: // Output:
}
type Obj struct { logger.Err(ctx, "same error message")
Name string // Output: msg="same error message" level=error
IsEnable bool
}
var (
obj = Obj{
Name: "test obj",
}
str = "test str"
boolsVal = true
intVal = int(math.MaxInt)
int8Val = int8(math.MaxInt8)
int16Val = int16(math.MaxInt16)
int32Val = int32(math.MaxInt32)
int64Val = int64(math.MaxInt64)
uintVal = uint(math.MaxUint)
uint8Val = uint8(math.MaxUint8)
uint16Val = uint16(math.MaxInt16)
uint32Val = uint32(math.MaxInt32)
uint64Val = uint64(math.MaxInt64)
float32Val = float32(math.MaxFloat32)
float64Val = float64(math.MaxFloat64)
minute = time.Minute
timeVal = time.Unix(0, math.MaxInt32).In(time.UTC)
)
func ExampleNew_anyField() {
logger := log.New(log.WithStdout(), log.WithJSONFormat())
logger.InfoKV(ctx, "any info message",
field.Any("obj", Obj{Name: "obj name"}),
field.Any("obj", &obj),
field.Any("int", intVal),
field.Any("uint", uintVal),
field.Any("float", float64Val),
field.Any("time", timeVal),
field.Any("duration", time.Hour),
field.Any("error", errors.New("error")),
)
// Output:
// {"msg":"any info message","obj":{"Name":"obj name","IsEnable":false},"obj":{"Name":"test obj","IsEnable":false},"int":9223372036854775807,"uint":18446744073709551615,"float":1.7976931348623157e+308,"time":"1970-01-01T00:00:02Z","duration":"1h0m0s","error":"error"}
}
func ExampleNew_arrayField() {
logger := log.New(log.WithStdout(), log.WithJSONFormat())
logger.InfoKV(ctx, "array info message",
field.Strings("strings", "string", str),
field.Bools("bools", true, false),
field.Ints("ints", 42, 24),
field.Int8s("int8s", 42, 24),
field.Int16s("int16s", 42, 24),
field.Int32s("int32s", 42, 24),
field.Int64s("int64s", 42, 24),
field.Uint8s("uint8s", uint8Val, 0),
field.Uint16s("uint16s", 42, 24),
field.Uint32s("uint32s", 42, 24),
field.Uint64s("uint64s", 42, 24),
field.Float32s("float32s", 42, 24),
field.Float64s("float64s", 42, 24),
field.Complex64s("complex64s", 42, 24),
field.Complex128s("complex128s", 42, 24),
field.Durations("durations", time.Minute, time.Second),
field.Times("times", time.Unix(0, 42).In(time.UTC), time.Unix(0, 24).In(time.UTC)),
field.Errors("errors", errors.New("error"), errors.New("error2")),
)
// Output:
// {"msg":"array info message","strings":["string","test str"],"bools":[true,false],"ints":[42,24],"int8s":[42,24],"int16s":[42,24],"int32s":[42,24],"int64s":[42,24],"uint8s":[255,0],"uint16s":[42,24],"uint32s":[42,24],"uint64s":[42,24],"float32s":[42,24],"float64s":[42,24],"complex64s":["(42+0i)","(24+0i)"],"complex128s":["(42+0i)","(24+0i)"],"durations":["1m0s","1s"],"times":["1970-01-01T00:00:00Z","1970-01-01T00:00:00Z"],"errors":["error","error2"]}
}
func ExampleNew_pointerField() {
logger := log.New(log.WithStdout(), log.WithJSONFormat())
logger.InfoKV(ctx, "pointer info message",
field.Stringp("stringp", &str),
field.Stringp("stringp", nil),
field.Boolp("boolp", &boolsVal),
field.Boolp("boolp", nil),
field.Intp("intp", &intVal),
field.Intp("intp", nil),
field.Int8p("int8p", &int8Val),
field.Int8p("int8p", nil),
field.Int16p("int16p", &int16Val),
field.Int16p("int16p", nil),
field.Int32p("int32p", &int32Val),
field.Int32p("int32p", nil),
field.Int64p("int64p", &int64Val),
field.Int64p("int64p", nil),
field.Uintp("uintp", &uintVal),
field.Uintp("uintp", nil),
field.Uint8p("uint8p", &uint8Val),
field.Uint8p("uint8p", nil),
field.Uint16p("uint16p", &uint16Val),
field.Uint16p("uint16p", nil),
field.Uint32p("uint32p", &uint32Val),
field.Uint32p("uint32p", nil),
field.Uint64p("uint64p", &uint64Val),
field.Uint64p("uint64p", nil),
field.Float32p("float32p", &float32Val),
field.Float32p("float32p", nil),
field.Float64p("float64p", &float64Val),
field.Float64p("float64p", nil),
field.Durationp("durationp", &minute),
field.Durationp("durationp", nil),
field.Timep("timep", &timeVal),
field.Timep("timep", nil),
)
// Output:
// {"msg":"pointer info message","stringp":"test str","stringp":null,"boolp":true,"boolp":null,"intp":9223372036854775807,"intp":null,"int8p":127,"int8p":null,"int16p":32767,"int16p":null,"int32p":2147483647,"int32p":null,"int64p":9223372036854775807,"int64p":null,"uintp":18446744073709551615,"uintp":null,"uint8p":255,"uint8p":null,"uint16p":32767,"uint16p":null,"uint32p":2147483647,"uint32p":null,"uint64p":9223372036854775807,"uint64p":null,"float32p":3.4028235e+38,"float32p":null,"float64p":1.7976931348623157e+308,"float64p":null,"durationp":"1m0s","durationp":null,"timep":"1970-01-01T00:00:02Z","timep":null}
}
func ExampleNew_fields() {
logger := log.New(log.WithStdout(), log.WithJSONFormat())
logger.InfoKV(ctx, "info message",
field.String("string", str),
field.Bool("bool", true),
field.Int("int", 42),
field.Int8("int8", 42),
field.Int16("int16", 42),
field.Int32("int32", 42),
field.Int64("int64", 42),
field.Uint8("uint8", uint8Val),
field.Uint16("uint16", 42),
field.Uint32("uint32", 42),
field.Uint64("uint64", 42),
field.Float32("float32", 42),
field.Float64("float64", 42),
field.Complex64("complex16", 42),
field.Complex128("complex128", 42),
field.Duration("duration", time.Minute),
field.Time("time", timeVal),
field.FormatTime("format_time", time.UnixDate, timeVal),
field.Error("error", errors.New("error")),
)
// Output:
// {"msg":"info message","string":"test str","bool":true,"int":42,"int8":42,"int16":42,"int32":42,"int64":42,"uint8":255,"uint16":42,"uint32":42,"uint64":42,"float32":42,"float64":42,"complex16":"(42+0i)","complex128":"(42+0i)","duration":"1m0s","time":"1970-01-01T00:00:02Z","format_time":"Thu Jan 1 00:00:02 UTC 1970","error":"error"}
} }
func ExampleNew_jsonFormat() { func ExampleNew_jsonFormat() {
logger := log.New(log.WithStdout(), log.WithJSONFormat()). logger := log.New(log.WithStdout(), log.WithJSONFormat()).
With( With(
log.WithLevel(log.KeyLevel, level.Debug), log.WithLevel("level", level.Debug),
log.GoVersion("go-version"), log.GoVersion("go-version"),
) )
logger.Err(ctx, "same error message") logger.Err(ctx, "same error message")
logger.WarnKVs(ctx, "same warn message", "obj", Obj{Name: "obj name"}) // Output: {"go-version":"go1.15.2","level":"error","msg":"same error message"}
// Output:
// {"msg":"same error message","level":"error","go-version":"go1.21.5"}
// {"msg":"same warn message","obj":{"Name":"obj name","IsEnable":false},"level":"warning","go-version":"go1.21.5"}
} }
func ExampleNew_textEncoding() { func ExampleNew_textEncoding() {
logger := log.With( logger := log.With(
log.New(log.WithStdout()), log.New(log.WithStdout()),
log.WithLevel(log.KeyLevel, level.Debug), log.WithLevel("level", level.Debug),
log.GoVersion("go-version"), log.GoVersion("go-version"),
) )
logger.Err(ctx, "same error message") logger.Err(ctx, "same error message")
logger.InfoKVs(ctx, "same info message", "api-version", 0.1, "obj", Obj{Name: "text value", IsEnable: true}) logger.InfoKVs(ctx, "same info message", "api-version", 0.1)
// Output: // Output:
// msg="same error message" level=error go-version=go1.21.5 // msg="same error message" level=error go-version=go1.15.2
// msg="same info message" api-version=0.1 obj={Name:text value IsEnable:true} level=info go-version=go1.21.5 // msg="same info message" api-version=0.1 level=info go-version=go1.15.2
} }
type ctxKey string type ctxKey string
@@ -250,7 +102,7 @@ func ExampleWith() {
levelInfo, log.WithContextValue(requestID), log.KeyValue("api", "0.1.0"), log.GoVersion("go"), levelInfo, log.WithContextValue(requestID), log.KeyValue("api", "0.1.0"), log.GoVersion("go"),
) )
logger.Info(vctx, "same message") logger.Info(vctx, "same message")
// Output: msg="same message" level=info requestID=6a5fa048-7181-11ea-bc55-0242ac130003 api=0.1.0 go=go1.21.5 // Output: msg="same message" level=info requestID=6a5fa048-7181-11ea-bc55-0242ac130003 api=0.1.0 go=go1.15.2
} }
func ExampleLogger_Print() { func ExampleLogger_Print() {
@@ -259,7 +111,7 @@ func ExampleLogger_Print() {
levelInfo, log.KeyValue("client", "http"), log.KeyValue("api", "0.1.0"), log.GoVersion("go"), levelInfo, log.KeyValue("client", "http"), log.KeyValue("api", "0.1.0"), log.GoVersion("go"),
) )
logger.Print("same message") logger.Print("same message")
// Output: msg="same message" level=info client=http api=0.1.0 go=go1.21.5 // Output: msg="same message" level=info client=http api=0.1.0 go=go1.15.2
} }
func ExamplePrint() { func ExamplePrint() {
@@ -268,43 +120,22 @@ func ExamplePrint() {
// Output: msg="same message" level=info // Output: msg="same message" level=info
} }
func Example_fieldClosureFn() { func ExampleWithClosure() {
cnt := int32(0) cnt := int32(0)
closure := field.ClosureFn(func() any { closure := func() string {
d := fmt.Sprintf("additional error data: %d", cnt) d := fmt.Sprintf("additional error data: %d", cnt)
atomic.AddInt32(&cnt, 1) atomic.AddInt32(&cnt, 1)
return d return d
}) }
log := log.With(log.New(log.WithStdout()), log.WithLevel("level", level.Info)) log := log.With(log.New(log.WithStdout()), log.WithLevel("level", level.Info), log.WithClosure)
log.DebugKVs(ctx, "debug message", "data", closure) log.DebugKVs(ctx, "debug message", "data", closure)
log.ErrKVs(ctx, "error message", "err", closure) log.ErrKVs(ctx, "error message", "err", closure)
log.WarnKVs(ctx, "warn message", "warn", closure) log.WarnKVs(ctx, "warn message", "warn", closure)
// Output: // Output:
// msg="error message" err="additional error data: 0" level=error // msg="error message" err=additional error data: 0 level=error
// msg="warn message" warn="additional error data: 1" level=warning // msg="warn message" warn=additional error data: 1 level=warning
}
func Example_withGroup() {
log := log.With(log.New(log.WithStdout()), log.WithLevel(log.KeyLevel, level.Info))
log.ErrKVs(ctx, "error message",
field.Groups("grous_field",
field.Error("err", os.ErrDeadlineExceeded),
field.Bool("bool", false),
),
)
log.WarnKV(ctx, "error message", field.ValuerFn("valuer_field", func() any {
return field.Fields{
field.Int("int_value", math.MaxInt),
field.Uint8("uint8_value", math.MaxUint8),
}
}))
// Output:
// msg="error message" grous_field.err="i/o timeout" grous_field.bool=false level=error
// msg="error message" valuer_field.int_value=9223372036854775807 valuer_field.uint8_value=255 level=warning
} }

View File

@@ -1,4 +1,4 @@
package otel_test package log_test
import ( import (
"context" "context"
@@ -8,12 +8,12 @@ import (
"gitoa.ru/go-4devs/log" "gitoa.ru/go-4devs/log"
"gitoa.ru/go-4devs/log/field" "gitoa.ru/go-4devs/log/field"
"gitoa.ru/go-4devs/log/handler/otel" "gitoa.ru/go-4devs/log/handler/otel"
apitrace "go.opentelemetry.io/otel/api/trace"
"go.opentelemetry.io/otel/sdk/export/trace"
sdktrace "go.opentelemetry.io/otel/sdk/trace" sdktrace "go.opentelemetry.io/otel/sdk/trace"
"go.opentelemetry.io/otel/trace"
) )
func ExampleNew_withTrace() { func ExampleNew_withTrace() {
ctx := context.Background()
logger := log.New(log.WithStdout()).With(otel.Middleware()) logger := log.New(log.WithStdout()).With(otel.Middleware())
sctx, span := startSpan(ctx) sctx, span := startSpan(ctx)
@@ -33,7 +33,7 @@ func ExampleNew_withTrace() {
// event: log logrus kv sugar, SeverityText = ERROR, SeverityNumber = 17, err = EOF // event: log logrus kv sugar, SeverityText = ERROR, SeverityNumber = 17, err = EOF
} }
func startSpan(ctx context.Context) (context.Context, trace.Span) { func startSpan(ctx context.Context) (context.Context, apitrace.Span) {
tp := sdktrace.NewTracerProvider(sdktrace.WithSyncer(exporter{})) tp := sdktrace.NewTracerProvider(sdktrace.WithSyncer(exporter{}))
return tp.Tracer("logger").Start(ctx, "operation") return tp.Tracer("logger").Start(ctx, "operation")
@@ -45,9 +45,9 @@ func (e exporter) Shutdown(_ context.Context) error {
return nil return nil
} }
func (e exporter) ExportSpans(_ context.Context, spanData []sdktrace.ReadOnlySpan) error { func (e exporter) ExportSpans(ctx context.Context, spanData []*trace.SpanData) error {
for _, data := range spanData { for _, data := range spanData {
for _, events := range data.Events() { for _, events := range data.MessageEvents {
fmt.Print("event: ", events.Name) fmt.Print("event: ", events.Name)
for _, attr := range events.Attributes { for _, attr := range events.Attributes {

View File

@@ -1,7 +1,6 @@
package zap_test package log_test
import ( import (
"context"
"io" "io"
"gitoa.ru/go-4devs/log/field" "gitoa.ru/go-4devs/log/field"
@@ -10,7 +9,6 @@ import (
) )
func ExampleNew_zapHandler() { func ExampleNew_zapHandler() {
ctx := context.Background()
log := zap.New(uzap.NewExample()) log := zap.New(uzap.NewExample())
log.Err(ctx, "log zap") log.Err(ctx, "log zap")
log.ErrKV(ctx, "log zap kv", field.Int("int", 42)) log.ErrKV(ctx, "log zap kv", field.Int("int", 42))

View File

@@ -13,11 +13,10 @@ import (
"gitoa.ru/go-4devs/log/level" "gitoa.ru/go-4devs/log/level"
) )
//nolint:gochecknoglobals
var requestID ctxKey = "requestID" var requestID ctxKey = "requestID"
func TestFields(t *testing.T) { func TestFields(t *testing.T) {
t.Parallel()
type rObj struct { type rObj struct {
id string id string
} }
@@ -27,14 +26,14 @@ func TestFields(t *testing.T) {
ctx := context.Background() ctx := context.Background()
buf := &bytes.Buffer{} buf := &bytes.Buffer{}
log := log.New(log.WithWriter(buf)). log := log.New(log.WithWriter(buf)).
With(log.WithLevel("level", level.Info)) With(log.WithLevel("level", level.Info), log.WithClosure)
success := "msg=message err=\"file already exists\" version=0.1.0 obj={id:uid} closure=\"some closure data\" level=info\n" success := "msg=\"message\" err=file already exists version=0.1.0 obj={id:uid} closure=some closure data level=info\n"
log.InfoKVs(ctx, "message", log.InfoKVs(ctx, "message",
"err", os.ErrExist, "err", os.ErrExist,
"version", "0.1.0", "version", "0.1.0",
"obj", rObj{id: "uid"}, "obj", rObj{id: "uid"},
"closure", func() any { "closure", func() string {
atomic.AddInt32(&cnt, 1) atomic.AddInt32(&cnt, 1)
return "some closure data" return "some closure data"
@@ -42,11 +41,11 @@ func TestFields(t *testing.T) {
) )
log.DebugKVs(ctx, "debug message", log.DebugKVs(ctx, "debug message",
"closure", field.ClosureFn(func() any { "closure", func() string {
atomic.AddInt32(&cnt, 1) atomic.AddInt32(&cnt, 1)
return "some debug data" return "some debug data"
}), },
) )
if success != buf.String() { if success != buf.String() {
@@ -59,11 +58,9 @@ func TestFields(t *testing.T) {
} }
func TestWriter(t *testing.T) { func TestWriter(t *testing.T) {
t.Parallel()
ctx := context.Background() ctx := context.Background()
success := "msg=\"info message\" err=\"file already exists\" requestID=6a5fa048-7181-11ea-bc55-0242ac1311113 level=info\n" success := "msg=\"info message\" err=file already exists requestID=6a5fa048-7181-11ea-bc55-0242ac1311113 level=info\n"
buf := &bytes.Buffer{} buf := &bytes.Buffer{}
logger := log.New(log.WithWriter(buf)).With(log.WithContextValue(requestID), log.WithLevel("level", level.Info)) logger := log.New(log.WithWriter(buf)).With(log.WithContextValue(requestID), log.WithLevel("level", level.Info))
@@ -87,8 +84,6 @@ func TestWriter(t *testing.T) {
} }
func TestLogger(t *testing.T) { func TestLogger(t *testing.T) {
t.Parallel()
ctx := context.Background() ctx := context.Background()
buf := &bytes.Buffer{} buf := &bytes.Buffer{}
logger := log.New(log.WithWriter(buf)).With(log.WithContextValue(requestID), log.WithLevel("level", level.Info)) logger := log.New(log.WithWriter(buf)).With(log.WithContextValue(requestID), log.WithLevel("level", level.Info))

View File

@@ -12,6 +12,8 @@ import (
"gitoa.ru/go-4devs/log/level" "gitoa.ru/go-4devs/log/level"
) )
var _ Middleware = WithClosure
// Middleware handle. // Middleware handle.
type Middleware func(ctx context.Context, e *entry.Entry, handler Logger) (int, error) type Middleware func(ctx context.Context, e *entry.Entry, handler Logger) (int, error)
@@ -28,7 +30,7 @@ func With(logger Logger, mw ...Middleware) Logger {
lastI := len(mw) - 1 lastI := len(mw) - 1
return func(ctx context.Context, data *entry.Entry) (int, error) { return func(ctx context.Context, e *entry.Entry) (int, error) {
var ( var (
chainHandler func(context.Context, *entry.Entry) (int, error) chainHandler func(context.Context, *entry.Entry) (int, error)
curI int curI int
@@ -45,7 +47,7 @@ func With(logger Logger, mw ...Middleware) Logger {
return n, err return n, err
} }
return mw[0](ctx, data, chainHandler) return mw[0](ctx, e, chainHandler)
} }
} }
@@ -60,6 +62,18 @@ func WithLevel(key string, lvl level.Level) Middleware {
} }
} }
func WithClosure(ctx context.Context, e *entry.Entry, handler Logger) (int, error) {
for i, field := range e.Fields() {
if field.Type().IsAny() {
if f, ok := field.AsInterface().(func() string); ok {
e.Fields().Set(i, field.Key().String(f()))
}
}
}
return handler(ctx, e)
}
// KeyValue add field by const key value. // KeyValue add field by const key value.
func KeyValue(key string, value interface{}) Middleware { func KeyValue(key string, value interface{}) Middleware {
return func(ctx context.Context, e *entry.Entry, handler Logger) (int, error) { return func(ctx context.Context, e *entry.Entry, handler Logger) (int, error) {
@@ -86,7 +100,6 @@ func WithContextValue(keys ...fmt.Stringer) Middleware {
} }
// WithCaller adds called file. // WithCaller adds called file.
// Deprecated: use WithSource.
func WithCaller(key string, depth int, full bool) Middleware { func WithCaller(key string, depth int, full bool) Middleware {
const offset = 2 const offset = 2
@@ -98,7 +111,7 @@ func WithCaller(key string, depth int, full bool) Middleware {
// WithTime adds time. // WithTime adds time.
func WithTime(key, format string) Middleware { func WithTime(key, format string) Middleware {
return func(ctx context.Context, e *entry.Entry, handler Logger) (int, error) { return func(ctx context.Context, e *entry.Entry, handler Logger) (int, error) {
return handler(ctx, e.Add(field.FormatTime(key, format, time.Now()))) return handler(ctx, e.Add(field.Time(key, time.Now())))
} }
} }

View File

@@ -1,45 +0,0 @@
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
}

View File

@@ -1,25 +0,0 @@
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"}}
}

View File

@@ -1,129 +1,112 @@
package log package log
import ( import (
"bytes"
"context" "context"
"fmt" "encoding/json"
"io" "io"
"os" "os"
"strings"
"sync"
"gitoa.ru/go-4devs/log/entry" "gitoa.ru/go-4devs/log/entry"
"gitoa.ru/go-4devs/log/field"
"gitoa.ru/go-4devs/log/internal/buffer"
) )
// Keys for "built-in" attributes. // New creates standart logger.
const ( func New(opts ...Option) Logger {
// TimeKey is the key used by the built-in handlers for the time l := log{e: stringFormat(), w: os.Stderr}
// when the log method is called. The associated Value is a [time.Time].
KeyTime = "time"
// LevelKey is the key used by the built-in handlers for the level
// of the log call. The associated value is a [Level].
KeyLevel = "level"
// MessageKey is the key used by the built-in handlers for the
// message of the log call. The associated value is a string.
KeyMessage = "msg"
// SourceKey is the key used by the built-in handlers for the source file
// and line of the log call. The associated value is a string.
KeySource = "source"
)
func WithWriter(w io.Writer) func(*option) { for _, opt := range opts {
return func(o *option) { opt(&l)
o.out = w }
return func(_ context.Context, entry *entry.Entry) (int, error) {
b, err := l.e(entry)
if err != nil {
return 0, err
}
return l.w.Write(b)
} }
} }
func WithStdout() func(*option) { // Option configure log.
return func(o *option) { type Option func(*log)
o.out = os.Stdout
// Encode sets formats and encode output message.
type Encode func(*entry.Entry) ([]byte, error)
type log struct {
w io.Writer
e Encode
}
// WithWriter sets writer logger.
func WithWriter(writer io.Writer) Option {
return func(l *log) {
l.w = writer
}
}
// WithStdout sets logged to os.Stdout.
func WithStdout() Option {
return WithWriter(os.Stdout)
}
// WithEncode sets format log.
func WithEncode(e Encode) Option {
return func(l *log) {
l.e = e
} }
} }
// WithStringFormat sets format as simple string. // WithStringFormat sets format as simple string.
func WithStringFormat() func(*option) { func WithStringFormat() Option {
return func(o *option) { return WithEncode(stringFormat())
o.format = formatText()
}
} }
// WithJSONFormat sets json output format. // WithJSONFormat sets json output format.
func WithJSONFormat() func(*option) { func WithJSONFormat() Option {
return func(o *option) { return WithEncode(jsonFormat)
o.format = formatJSON()
}
} }
type option struct { func stringFormat() func(entry *entry.Entry) ([]byte, error) {
format func(io.Writer, *entry.Entry) (int, error) pool := sync.Pool{
out io.Writer New: func() interface{} {
} return &bytes.Buffer{}
},
// New creates standart logger.
func New(opts ...func(*option)) Logger {
log := option{
format: formatText(),
out: os.Stderr,
} }
for _, opt := range opts { return func(entry *entry.Entry) ([]byte, error) {
opt(&log) b := pool.Get().(*bytes.Buffer)
} b.Reset()
return func(_ context.Context, entry *entry.Entry) (int, error) {
return log.format(log.out, entry)
}
}
func formatText() func(io.Writer, *entry.Entry) (int, error) {
enc := field.NewEncoderText()
return func(w io.Writer, entry *entry.Entry) (int, error) {
buf := buffer.New()
defer func() { defer func() {
buf.Free() pool.Put(b)
}() }()
*buf = enc.AppendField(*buf, field.String(KeyMessage, entry.Message())) b.WriteString("msg=\"")
b.WriteString(strings.TrimSpace(entry.Message()))
b.WriteString("\"")
for _, field := range entry.Fields() { for _, field := range entry.Fields() {
*buf = enc.AppendField(*buf, field) b.WriteString(" ")
b.WriteString(string(field.Key()))
b.WriteString("=")
b.WriteString(field.Value().String())
} }
_, _ = buf.WriteString("\n") b.WriteString("\n")
n, err := w.Write(*buf) return b.Bytes(), nil
if err != nil {
return 0, fmt.Errorf("format text:%w", err)
}
return n, nil
} }
} }
func formatJSON() func(w io.Writer, entry *entry.Entry) (int, error) { func jsonFormat(entry *entry.Entry) ([]byte, error) {
enc := field.NewEncoderJSON() res, err := json.Marshal(entry.AddString("msg", entry.Message()).Fields().AsMap())
if err != nil {
return func(w io.Writer, entry *entry.Entry) (int, error) { return nil, err
buf := buffer.New()
defer func() {
buf.Free()
}()
_, _ = buf.WriteString("{")
*buf = enc.AppendField(*buf, field.String(KeyMessage, entry.Message()))
for _, field := range entry.Fields() {
*buf = enc.AppendField(*buf, field)
}
_, _ = buf.WriteString("}")
_, _ = buf.WriteString("\n")
n, err := w.Write(*buf)
if err != nil {
return 0, fmt.Errorf("format json:%w", err)
}
return n, nil
} }
return append(res, []byte("\n")...), nil
} }