Merge pull request 'log' (#20) from log into master
All checks were successful
Go Action / goaction (push) Successful in 31s
All checks were successful
Go Action / goaction (push) Successful in 31s
Reviewed-on: #20
This commit was merged in pull request #20.
This commit is contained in:
@@ -17,7 +17,7 @@ jobs:
|
||||
- name: Run golangci-lint
|
||||
uses: golangci/golangci-lint-action@v8 # Use the golangci-lint action
|
||||
with:
|
||||
version: v2.7.2 # Specify the linter version
|
||||
version: v2.10.1 # Specify the linter version
|
||||
# Optional: additional arguments
|
||||
args: --verbose
|
||||
|
||||
|
||||
@@ -4,6 +4,7 @@ linters:
|
||||
disable:
|
||||
- wsl
|
||||
- noinlineerr
|
||||
- revive
|
||||
settings:
|
||||
depguard:
|
||||
rules:
|
||||
@@ -21,20 +22,11 @@ linters:
|
||||
- "*.UnmarshalText"
|
||||
- "*.UnmarshalJSON"
|
||||
- "*.UnmarshalBinary"
|
||||
dupl:
|
||||
threshold: 100
|
||||
exhaustive:
|
||||
default-signifies-exhaustive: true
|
||||
funlen:
|
||||
lines: 100
|
||||
statements: 50
|
||||
goconst:
|
||||
min-len: 2
|
||||
min-occurrences: 2
|
||||
gocyclo:
|
||||
min-complexity: 15
|
||||
lll:
|
||||
line-length: 140
|
||||
misspell:
|
||||
locale: US
|
||||
tagliatelle:
|
||||
|
||||
@@ -163,18 +163,7 @@ func (e *Entry) AddString(key, value string) *Entry {
|
||||
}
|
||||
|
||||
func (e *Entry) Replace(key string, value field.Value) *Entry {
|
||||
has := false
|
||||
|
||||
e.fields.Fields(func(f field.Field) bool {
|
||||
if f.Key == key {
|
||||
f.Value = value
|
||||
has = true
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
return true
|
||||
})
|
||||
_, has := e.fields.Replace(field.Any(key, value))
|
||||
|
||||
if !has {
|
||||
e.AddAny(key, value)
|
||||
|
||||
42
entry/entry_test.go
Normal file
42
entry/entry_test.go
Normal file
@@ -0,0 +1,42 @@
|
||||
package entry_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"gitoa.ru/go-4devs/log/entry"
|
||||
"gitoa.ru/go-4devs/log/field"
|
||||
)
|
||||
|
||||
func TestEntry_Replace(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
ent := entry.New(entry.WithFields(
|
||||
field.Any("inti", "init date"),
|
||||
))
|
||||
|
||||
ent = ent.Replace("date", field.StringValue("some date"))
|
||||
ent = ent.Replace("date", field.TimeValue(time.Time{}))
|
||||
|
||||
fields := ent.Fields()
|
||||
|
||||
if len(fields) != 2 {
|
||||
t.Fatalf("count must be 2 got %v", len(fields))
|
||||
}
|
||||
|
||||
var has bool
|
||||
|
||||
fields.Fields(func(f field.Field) bool {
|
||||
if f.Key == "date" && !f.Value.AsTime().IsZero() {
|
||||
has = true
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
return true
|
||||
})
|
||||
|
||||
if !has {
|
||||
t.Fatal("failed reace value")
|
||||
}
|
||||
}
|
||||
@@ -31,7 +31,14 @@ func WithDelimeter(in byte) func(*BaseEncoder) {
|
||||
}
|
||||
}
|
||||
|
||||
// WithGropuConfig set group config.
|
||||
//
|
||||
// Deprecated: use WithGroupConfig.
|
||||
func WithGropuConfig(start, end, deli byte) func(*BaseEncoder) {
|
||||
return WithGroupConfig(start, end, deli)
|
||||
}
|
||||
|
||||
func WithGroupConfig(start, end, deli byte) func(*BaseEncoder) {
|
||||
return func(be *BaseEncoder) {
|
||||
be.group = groupConfig{
|
||||
start: start,
|
||||
@@ -243,7 +250,7 @@ func (b BaseEncoder) appendField(dst []byte, field Field, prefix string, deli by
|
||||
return b.appendValue(dst, field.Value, field.Key+".", deli)
|
||||
}
|
||||
|
||||
//nolint:mnd,gocyclo,cyclop
|
||||
//nolint:mnd,cyclop
|
||||
func (b BaseEncoder) appendValue(dst []byte, val Value, prefix string, deli byte) []byte {
|
||||
switch val.Kind {
|
||||
case KindGroup:
|
||||
@@ -269,7 +276,12 @@ func (b BaseEncoder) appendValue(dst []byte, val Value, prefix string, deli byte
|
||||
case KindUint64:
|
||||
return b.AppendUint(b.AppendDelimiter(dst, deli), val.AsUint64())
|
||||
case KindError:
|
||||
return b.AppendString(b.AppendDelimiter(dst, deli), val.AsError().Error())
|
||||
var errData string
|
||||
if err := val.AsError(); err != nil {
|
||||
errData = err.Error()
|
||||
}
|
||||
|
||||
return b.AppendString(b.AppendDelimiter(dst, deli), errData)
|
||||
case KindString:
|
||||
return b.AppendString(b.AppendDelimiter(dst, deli), val.AsString())
|
||||
case KindDuration:
|
||||
|
||||
@@ -7,7 +7,7 @@ import (
|
||||
|
||||
func NewEncoderText(opts ...func(*BaseEncoder)) BaseEncoder {
|
||||
opts = append([]func(*BaseEncoder){
|
||||
WithGropuConfig(0, 0, ' '),
|
||||
WithGroupConfig(0, 0, ' '),
|
||||
WithNullValue("<nil>"),
|
||||
WithDefaultValue(func(dst []byte, enc Encoder, val Value) []byte {
|
||||
switch value := val.Any().(type) {
|
||||
|
||||
@@ -2,4 +2,4 @@ package field
|
||||
|
||||
import "errors"
|
||||
|
||||
var ErrUndefined = errors.New("indefined")
|
||||
var ErrUndefined = errors.New("undefined")
|
||||
|
||||
@@ -6,6 +6,13 @@ import (
|
||||
"time"
|
||||
)
|
||||
|
||||
//nolint:gochecknoglobals
|
||||
var empty Field
|
||||
|
||||
func Empty() Field {
|
||||
return empty
|
||||
}
|
||||
|
||||
func Any(key string, value any) Field {
|
||||
return Field{
|
||||
Key: key,
|
||||
@@ -498,7 +505,7 @@ type Field struct {
|
||||
Value Value
|
||||
}
|
||||
|
||||
// String implent stringer.
|
||||
// String implement stringer.
|
||||
func (f Field) String() string {
|
||||
return fmt.Sprintf("%s=%+v", f.Key, f.Value)
|
||||
}
|
||||
|
||||
@@ -32,3 +32,16 @@ func (f Fields) Set(idx int, field Field) {
|
||||
func (f Fields) Len() int {
|
||||
return len(f)
|
||||
}
|
||||
|
||||
func (f Fields) Replace(field Field) (Field, bool) {
|
||||
for idx := range f {
|
||||
if f[idx].Key == field.Key {
|
||||
old := f[idx]
|
||||
f[idx] = field
|
||||
|
||||
return old, true
|
||||
}
|
||||
}
|
||||
|
||||
return Empty(), false
|
||||
}
|
||||
|
||||
@@ -16,3 +16,22 @@ func TestFields_Append(t *testing.T) {
|
||||
t.Fatalf("require 2 field got %v", len(fields))
|
||||
}
|
||||
}
|
||||
|
||||
func TestFields_Replace(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
fields := field.Fields{
|
||||
field.Any("any", "any init"),
|
||||
field.Any("replace", "replace init"),
|
||||
}
|
||||
|
||||
old, ok := fields.Replace(field.Int64("replace", 42))
|
||||
if !ok || old.Key != "replace" || old.Value != field.StringValue("replace init") {
|
||||
t.Fatalf("failed replace value:%v", old)
|
||||
}
|
||||
|
||||
o2, ok2 := fields.Replace(field.Any("new", "new data"))
|
||||
if ok2 || o2.Key != "" {
|
||||
t.Fatalf("failed set new data:%v", o2)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -37,44 +37,76 @@ func (l Kind) MarshalText() ([]byte, error) {
|
||||
return []byte(l.String()), nil
|
||||
}
|
||||
|
||||
//nolint:gocyclo,cyclop
|
||||
//nolint:cyclop,funlen
|
||||
func (l *Kind) UnmarshalText(in []byte) error {
|
||||
switch string(in) {
|
||||
case KindAny.String():
|
||||
*l = KindAny
|
||||
|
||||
return nil
|
||||
case KindArray.String():
|
||||
*l = KindArray
|
||||
|
||||
return nil
|
||||
case KindNil.String():
|
||||
*l = KindNil
|
||||
|
||||
return nil
|
||||
case KindString.String():
|
||||
*l = KindString
|
||||
|
||||
return nil
|
||||
case KindBool.String():
|
||||
*l = KindBool
|
||||
|
||||
return nil
|
||||
case KindInt64.String():
|
||||
*l = KindInt64
|
||||
|
||||
return nil
|
||||
case KindUint64.String():
|
||||
*l = KindUint64
|
||||
|
||||
return nil
|
||||
case KindFloat32.String():
|
||||
*l = KindFloat32
|
||||
|
||||
return nil
|
||||
case KindFloat64.String():
|
||||
*l = KindFloat64
|
||||
|
||||
return nil
|
||||
case KindComplex128.String():
|
||||
*l = KindComplex128
|
||||
|
||||
return nil
|
||||
case KindBinary.String():
|
||||
*l = KindBinary
|
||||
|
||||
return nil
|
||||
case KindDuration.String():
|
||||
*l = KindDuration
|
||||
|
||||
return nil
|
||||
case KindTime.String():
|
||||
*l = KindTime
|
||||
|
||||
return nil
|
||||
case KindError.String():
|
||||
*l = KindError
|
||||
|
||||
return nil
|
||||
case KindGroup.String():
|
||||
*l = KindGroup
|
||||
|
||||
return nil
|
||||
case KindClosure.String():
|
||||
*l = KindClosure
|
||||
}
|
||||
|
||||
return fmt.Errorf("%w:filed(%v)", ErrUndefined, string(in))
|
||||
return nil
|
||||
default:
|
||||
return fmt.Errorf("%w:filed(%v)", ErrUndefined, string(in))
|
||||
}
|
||||
}
|
||||
|
||||
func (l Kind) MarshalBinary() ([]byte, error) {
|
||||
|
||||
@@ -469,7 +469,7 @@ func (v Value) String() string {
|
||||
return string(v.append(buf))
|
||||
}
|
||||
|
||||
//nolint:gocyclo,cyclop
|
||||
//nolint:cyclop
|
||||
func (v Value) Any() any {
|
||||
switch v.Kind {
|
||||
case KindAny, KindBinary:
|
||||
|
||||
88
global.go
88
global.go
@@ -29,209 +29,209 @@ func Log() Logger {
|
||||
|
||||
// Emerg log by emergency level.
|
||||
func Emerg(ctx context.Context, args ...any) {
|
||||
global.Emerg(ctx, args...)
|
||||
Log().Emerg(ctx, args...)
|
||||
}
|
||||
|
||||
// Alert log by alert level.
|
||||
func Alert(ctx context.Context, args ...any) {
|
||||
global.Alert(ctx, args...)
|
||||
Log().Alert(ctx, args...)
|
||||
}
|
||||
|
||||
// Crit log by critical level.
|
||||
func Crit(ctx context.Context, args ...any) {
|
||||
global.Crit(ctx, args...)
|
||||
Log().Crit(ctx, args...)
|
||||
}
|
||||
|
||||
// Err log by error level.
|
||||
func Err(ctx context.Context, args ...any) {
|
||||
global.Err(ctx, args...)
|
||||
Log().Err(ctx, args...)
|
||||
}
|
||||
|
||||
// Warn logs by warning level.
|
||||
func Warn(ctx context.Context, args ...any) {
|
||||
global.Warn(ctx, args...)
|
||||
Log().Warn(ctx, args...)
|
||||
}
|
||||
|
||||
// Notice log by notice level.
|
||||
func Notice(ctx context.Context, args ...any) {
|
||||
global.Notice(ctx, args...)
|
||||
Log().Notice(ctx, args...)
|
||||
}
|
||||
|
||||
// Info log by info level.
|
||||
func Info(ctx context.Context, args ...any) {
|
||||
global.Info(ctx, args...)
|
||||
Log().Info(ctx, args...)
|
||||
}
|
||||
|
||||
// Debug log by debug level.
|
||||
func Debug(ctx context.Context, args ...any) {
|
||||
global.Debug(ctx, args...)
|
||||
Log().Debug(ctx, args...)
|
||||
}
|
||||
|
||||
// Print log by info level and arguments.
|
||||
func Print(args ...any) {
|
||||
global.Print(args...)
|
||||
Log().Print(args...)
|
||||
}
|
||||
|
||||
// Fatal log by alert level and arguments.
|
||||
func Fatal(args ...any) {
|
||||
global.Fatal(args...)
|
||||
Log().Fatal(args...)
|
||||
}
|
||||
|
||||
// Panic log by emergency level and arguments.
|
||||
func Panic(args ...any) {
|
||||
global.Panic(args...)
|
||||
Log().Panic(args...)
|
||||
}
|
||||
|
||||
// Println log by info level and arguments.
|
||||
func Println(args ...any) {
|
||||
global.Println(args...)
|
||||
Log().Println(args...)
|
||||
}
|
||||
|
||||
// Fatalln log by alert level and arguments.
|
||||
func Fatalln(args ...any) {
|
||||
global.Fatalln(args...)
|
||||
Log().Fatalln(args...)
|
||||
}
|
||||
|
||||
// Panicln log by emergency level and arguments.
|
||||
func Panicln(args ...any) {
|
||||
global.Panicln(args...)
|
||||
Log().Panicln(args...)
|
||||
}
|
||||
|
||||
// EmergKVs sugared log by emergency level and key-values.
|
||||
func EmergKVs(ctx context.Context, msg string, args ...any) {
|
||||
global.EmergKVs(ctx, msg, args...)
|
||||
Log().EmergKVs(ctx, msg, args...)
|
||||
}
|
||||
|
||||
// AlertKVs sugared log by alert level and key-values.
|
||||
func AlertKVs(ctx context.Context, msg string, args ...any) {
|
||||
global.AlertKVs(ctx, msg, args...)
|
||||
Log().AlertKVs(ctx, msg, args...)
|
||||
}
|
||||
|
||||
// CritKVs sugared log by critcal level and key-values.
|
||||
// CritKVs sugared log by critical level and key-values.
|
||||
func CritKVs(ctx context.Context, msg string, args ...any) {
|
||||
global.CritKVs(ctx, msg, args...)
|
||||
Log().CritKVs(ctx, msg, args...)
|
||||
}
|
||||
|
||||
// ErrKVs sugared log by error level and key-values.
|
||||
func ErrKVs(ctx context.Context, msg string, args ...any) {
|
||||
global.ErrKVs(ctx, msg, args...)
|
||||
Log().ErrKVs(ctx, msg, args...)
|
||||
}
|
||||
|
||||
// WarnKVs sugared log by warning level and key-values.
|
||||
func WarnKVs(ctx context.Context, msg string, args ...any) {
|
||||
global.WarnKVs(ctx, msg, args...)
|
||||
Log().WarnKVs(ctx, msg, args...)
|
||||
}
|
||||
|
||||
// NoticeKVs sugared log by notice level and key-values.
|
||||
func NoticeKVs(ctx context.Context, msg string, args ...any) {
|
||||
global.NoticeKVs(ctx, msg, args...)
|
||||
Log().NoticeKVs(ctx, msg, args...)
|
||||
}
|
||||
|
||||
// InfoKVs sugared log by info level and key-values.
|
||||
func InfoKVs(ctx context.Context, msg string, args ...any) {
|
||||
global.InfoKVs(ctx, msg, args...)
|
||||
Log().InfoKVs(ctx, msg, args...)
|
||||
}
|
||||
|
||||
// DebugKVs sugared log by debug level and key-values.
|
||||
func DebugKVs(ctx context.Context, msg string, args ...any) {
|
||||
global.DebugKVs(ctx, msg, args...)
|
||||
Log().DebugKVs(ctx, msg, args...)
|
||||
}
|
||||
|
||||
// EmergKV log by emergency level and key-values.
|
||||
func EmergKV(ctx context.Context, msg string, args ...field.Field) {
|
||||
global.EmergKV(ctx, msg, args...)
|
||||
Log().EmergKV(ctx, msg, args...)
|
||||
}
|
||||
|
||||
// AlertKV log by alert level and key-values.
|
||||
func AlertKV(ctx context.Context, msg string, args ...field.Field) {
|
||||
global.AlertKV(ctx, msg, args...)
|
||||
Log().AlertKV(ctx, msg, args...)
|
||||
}
|
||||
|
||||
// CritKV log by critcal level and key-values.
|
||||
// CritKV log by critical level and key-values.
|
||||
func CritKV(ctx context.Context, msg string, args ...field.Field) {
|
||||
global.CritKV(ctx, msg, args...)
|
||||
Log().CritKV(ctx, msg, args...)
|
||||
}
|
||||
|
||||
// ErrKV log by error level and key-values.
|
||||
func ErrKV(ctx context.Context, msg string, args ...field.Field) {
|
||||
global.ErrKV(ctx, msg, args...)
|
||||
Log().ErrKV(ctx, msg, args...)
|
||||
}
|
||||
|
||||
// WarnKV log by warning level and key-values.
|
||||
func WarnKV(ctx context.Context, msg string, args ...field.Field) {
|
||||
global.WarnKV(ctx, msg, args...)
|
||||
Log().WarnKV(ctx, msg, args...)
|
||||
}
|
||||
|
||||
// NoticeKV log by notice level and key-values.
|
||||
func NoticeKV(ctx context.Context, msg string, args ...field.Field) {
|
||||
global.NoticeKV(ctx, msg, args...)
|
||||
Log().NoticeKV(ctx, msg, args...)
|
||||
}
|
||||
|
||||
// InfoKV log by info level and key-values.
|
||||
func InfoKV(ctx context.Context, msg string, args ...field.Field) {
|
||||
global.InfoKV(ctx, msg, args...)
|
||||
Log().InfoKV(ctx, msg, args...)
|
||||
}
|
||||
|
||||
// DebugKV log by debug level and key-values.
|
||||
func DebugKV(ctx context.Context, msg string, args ...field.Field) {
|
||||
global.DebugKV(ctx, msg, args...)
|
||||
Log().DebugKV(ctx, msg, args...)
|
||||
}
|
||||
|
||||
// Emergf log by emergency level by format and arguments.
|
||||
func Emergf(ctx context.Context, format string, args ...any) {
|
||||
global.Emergf(ctx, format, args...)
|
||||
Log().Emergf(ctx, format, args...)
|
||||
}
|
||||
|
||||
// Alertf log by alert level by format and arguments.
|
||||
func Alertf(ctx context.Context, format string, args ...any) {
|
||||
global.Alertf(ctx, format, args...)
|
||||
Log().Alertf(ctx, format, args...)
|
||||
}
|
||||
|
||||
// Critf log by critical level by format and arguments.
|
||||
func Critf(ctx context.Context, format string, args ...any) {
|
||||
global.Critf(ctx, format, args...)
|
||||
Log().Critf(ctx, format, args...)
|
||||
}
|
||||
|
||||
// Errf log by error level by format and arguments.
|
||||
func Errf(ctx context.Context, format string, args ...any) {
|
||||
global.Errf(ctx, format, args...)
|
||||
Log().Errf(ctx, format, args...)
|
||||
}
|
||||
|
||||
// Warnf log by warning level by format and arguments.
|
||||
func Warnf(ctx context.Context, format string, args ...any) {
|
||||
global.Warnf(ctx, format, args...)
|
||||
Log().Warnf(ctx, format, args...)
|
||||
}
|
||||
|
||||
// Noticef log by notice level by format and arguments.
|
||||
func Noticef(ctx context.Context, format string, args ...any) {
|
||||
global.Noticef(ctx, format, args...)
|
||||
Log().Noticef(ctx, format, args...)
|
||||
}
|
||||
|
||||
// Infof log by info level by format and arguments.
|
||||
func Infof(ctx context.Context, format string, args ...any) {
|
||||
global.Noticef(ctx, format, args...)
|
||||
Log().Infof(ctx, format, args...)
|
||||
}
|
||||
|
||||
// Debugf log by debug level by format and arguments.
|
||||
func Debugf(ctx context.Context, format string, args ...any) {
|
||||
global.Debugf(ctx, format, args...)
|
||||
Log().Debugf(ctx, format, args...)
|
||||
}
|
||||
|
||||
// Printf log by info level by format and arguments without context.
|
||||
func Printf(format string, args ...any) {
|
||||
global.Printf(format, args...)
|
||||
Log().Printf(format, args...)
|
||||
}
|
||||
|
||||
// Fatalf log by alert level by format and arguments without context.
|
||||
func Fatalf(format string, args ...any) {
|
||||
global.Fatalf(format, args...)
|
||||
Log().Fatalf(format, args...)
|
||||
}
|
||||
|
||||
// Panicf log by emergency level and arguments without context.
|
||||
func Panicf(format string, args ...any) {
|
||||
global.Panicf(format, args...)
|
||||
Log().Panicf(format, args...)
|
||||
}
|
||||
|
||||
func Writer(ctx context.Context, level level.Level) io.Writer {
|
||||
return global.Writer(ctx, level)
|
||||
return Log().Writer(ctx, level)
|
||||
}
|
||||
|
||||
@@ -10,7 +10,7 @@ import (
|
||||
"gitoa.ru/go-4devs/log/level"
|
||||
)
|
||||
|
||||
// Standard create new standart logrus handler.
|
||||
// Standard create new standard logrus handler.
|
||||
// Deprecated: delete after 0.7.0
|
||||
func Standard() log.Logger {
|
||||
return New(logrus.StandardLogger())
|
||||
|
||||
@@ -75,19 +75,19 @@ func (l *Level) UnmarshalBinary(in []byte) error {
|
||||
|
||||
func Parse(lvl string) Level {
|
||||
switch strings.ToLower(lvl) {
|
||||
case "debug", "Debug", "DEBUG":
|
||||
case "debug":
|
||||
return Debug
|
||||
case "info", "Info", "INFO":
|
||||
case "info":
|
||||
return Info
|
||||
case "notice", "Notice", "NOTICE":
|
||||
case "notice":
|
||||
return Notice
|
||||
case "warning", "Warning", "WARNING", "warm", "Warm", "WARN":
|
||||
case "warning", "warn":
|
||||
return Warning
|
||||
case "error", "Error", "ERROR", "err", "Err", "ERR":
|
||||
case "error", "err":
|
||||
return Error
|
||||
case "critical", "Critical", "CRITICAL", "crit", "Crit", "CRIT":
|
||||
case "critical", "crit":
|
||||
return Critical
|
||||
case "alert", "Alert", "ALERT":
|
||||
case "alert":
|
||||
return Alert
|
||||
default:
|
||||
return Emergency
|
||||
|
||||
37
logger.go
37
logger.go
@@ -105,42 +105,42 @@ func (l Logger) Panicln(args ...any) {
|
||||
|
||||
// EmergKVs sugared log by emergency level and key-values.
|
||||
func (l Logger) EmergKVs(ctx context.Context, msg string, args ...any) {
|
||||
writeOutput(l.write(ctx, level.Emergency, msg, l.kv(ctx, args...)...))
|
||||
writeOutput(l.writekvs(ctx, level.Emergency, msg, args))
|
||||
}
|
||||
|
||||
// AlertKVs sugared log by alert level and key-values.
|
||||
func (l Logger) AlertKVs(ctx context.Context, msg string, args ...any) {
|
||||
writeOutput(l.write(ctx, level.Alert, msg, l.kv(ctx, args...)...))
|
||||
writeOutput(l.writekvs(ctx, level.Alert, msg, args))
|
||||
}
|
||||
|
||||
// CritKVs sugared log by critcal level and key-values.
|
||||
// CritKVs sugared log by critical level and key-values.
|
||||
func (l Logger) CritKVs(ctx context.Context, msg string, args ...any) {
|
||||
writeOutput(l.write(ctx, level.Critical, msg, l.kv(ctx, args...)...))
|
||||
writeOutput(l.writekvs(ctx, level.Critical, msg, args))
|
||||
}
|
||||
|
||||
// ErrKVs sugared log by error level and key-values.
|
||||
func (l Logger) ErrKVs(ctx context.Context, msg string, args ...any) {
|
||||
writeOutput(l.write(ctx, level.Error, msg, l.kv(ctx, args...)...))
|
||||
writeOutput(l.writekvs(ctx, level.Error, msg, args))
|
||||
}
|
||||
|
||||
// WarnKVs sugared log by warning level and key-values.
|
||||
func (l Logger) WarnKVs(ctx context.Context, msg string, args ...any) {
|
||||
writeOutput(l.write(ctx, level.Warning, msg, l.kv(ctx, args...)...))
|
||||
writeOutput(l.writekvs(ctx, level.Warning, msg, args))
|
||||
}
|
||||
|
||||
// NoticeKVs sugared log by notice level and key-values.
|
||||
func (l Logger) NoticeKVs(ctx context.Context, msg string, args ...any) {
|
||||
writeOutput(l.write(ctx, level.Notice, msg, l.kv(ctx, args...)...))
|
||||
writeOutput(l.writekvs(ctx, level.Notice, msg, args))
|
||||
}
|
||||
|
||||
// InfoKVs sugared log by info level and key-values.
|
||||
func (l Logger) InfoKVs(ctx context.Context, msg string, args ...any) {
|
||||
writeOutput(l.write(ctx, level.Info, msg, l.kv(ctx, args...)...))
|
||||
writeOutput(l.writekvs(ctx, level.Info, msg, args))
|
||||
}
|
||||
|
||||
// DebugKVs sugared log by debug level and key-values.
|
||||
func (l Logger) DebugKVs(ctx context.Context, msg string, args ...any) {
|
||||
writeOutput(l.write(ctx, level.Debug, msg, l.kv(ctx, args...)...))
|
||||
writeOutput(l.writekvs(ctx, level.Debug, msg, args))
|
||||
}
|
||||
|
||||
// EmergKV log by emergency level and key-values.
|
||||
@@ -153,7 +153,7 @@ func (l Logger) AlertKV(ctx context.Context, msg string, args ...field.Field) {
|
||||
writeOutput(l.write(ctx, level.Alert, msg, args...))
|
||||
}
|
||||
|
||||
// CritKV log by critcal level and key-values.
|
||||
// CritKV log by critical level and key-values.
|
||||
func (l Logger) CritKV(ctx context.Context, msg string, args ...field.Field) {
|
||||
writeOutput(l.write(ctx, level.Critical, msg, args...))
|
||||
}
|
||||
@@ -247,38 +247,39 @@ func (l Logger) Writer(ctx context.Context, level level.Level, fields ...field.F
|
||||
}
|
||||
}
|
||||
|
||||
func (l Logger) kv(_ context.Context, args ...any) field.Fields {
|
||||
kvEntry := entry.Get()
|
||||
func (l Logger) writekvs(ctx context.Context, lvl level.Level, mst string, args []any) (int, error) {
|
||||
data := entry.Get()
|
||||
data = data.SetMessage(mst).SetLevel(lvl)
|
||||
|
||||
defer func() {
|
||||
entry.Put(kvEntry)
|
||||
entry.Put(data)
|
||||
}()
|
||||
|
||||
for i := 0; i < len(args); i++ {
|
||||
if f, ok := args[i].(field.Field); ok {
|
||||
kvEntry = kvEntry.Add(f)
|
||||
data = data.Add(f)
|
||||
|
||||
continue
|
||||
}
|
||||
|
||||
if i == len(args)-1 {
|
||||
kvEntry = kvEntry.AddAny(badKey, args[i])
|
||||
data = data.AddAny(badKey, args[i])
|
||||
|
||||
break
|
||||
}
|
||||
|
||||
key, val := args[i], args[i+1]
|
||||
if keyStr, ok := key.(string); ok {
|
||||
kvEntry = kvEntry.AddAny(keyStr, val)
|
||||
data = data.AddAny(keyStr, val)
|
||||
i++
|
||||
|
||||
continue
|
||||
}
|
||||
|
||||
kvEntry = kvEntry.AddAny(badKey, args[i])
|
||||
data = data.AddAny(badKey, args[i])
|
||||
}
|
||||
|
||||
return kvEntry.Fields()
|
||||
return l(ctx, data)
|
||||
}
|
||||
|
||||
func (l Logger) write(ctx context.Context, level level.Level, msg string, fields ...field.Field) (int, error) {
|
||||
|
||||
@@ -28,7 +28,8 @@ func TestFields(t *testing.T) {
|
||||
buf := &bytes.Buffer{}
|
||||
log := log.New(log.WithWriter(buf)).
|
||||
With(log.WithLevel(log.KeyLevel, level.Info))
|
||||
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",
|
||||
"err", os.ErrExist,
|
||||
@@ -63,7 +64,8 @@ func TestWriter(t *testing.T) {
|
||||
|
||||
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{}
|
||||
logger := log.New(log.WithWriter(buf)).With(log.WithContextValue(requestID), log.WithLevel(log.KeyLevel, level.Info))
|
||||
|
||||
|
||||
@@ -17,7 +17,9 @@ type Middleware func(ctx context.Context, e *entry.Entry, handler Logger) (int,
|
||||
|
||||
// With add middleware to logger.
|
||||
func With(logger Logger, mw ...Middleware) Logger {
|
||||
switch len(mw) {
|
||||
num := len(mw)
|
||||
|
||||
switch num {
|
||||
case 0:
|
||||
return logger
|
||||
case 1:
|
||||
@@ -26,27 +28,17 @@ func With(logger Logger, mw ...Middleware) Logger {
|
||||
}
|
||||
}
|
||||
|
||||
lastI := len(mw) - 1
|
||||
|
||||
return func(ctx context.Context, data *entry.Entry) (int, error) {
|
||||
var (
|
||||
chainHandler func(context.Context, *entry.Entry) (int, error)
|
||||
curI int
|
||||
)
|
||||
currHandler := logger
|
||||
|
||||
chainHandler = func(currentCtx context.Context, currentEntry *entry.Entry) (int, error) {
|
||||
if curI == lastI {
|
||||
return logger(currentCtx, currentEntry)
|
||||
for i := num - 1; i > 0; i-- {
|
||||
innerHandler := currHandler
|
||||
currHandler = func(currentCtx context.Context, currentEntry *entry.Entry) (int, error) {
|
||||
return mw[i](currentCtx, currentEntry, innerHandler)
|
||||
}
|
||||
|
||||
curI++
|
||||
n, err := mw[curI](currentCtx, currentEntry, chainHandler)
|
||||
curI--
|
||||
|
||||
return n, err
|
||||
}
|
||||
|
||||
return mw[0](ctx, data, chainHandler)
|
||||
return mw[0](ctx, data, currHandler)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
15
source.go
15
source.go
@@ -11,14 +11,21 @@ import (
|
||||
"gitoa.ru/go-4devs/log/field"
|
||||
)
|
||||
|
||||
const funcName = "Logger"
|
||||
|
||||
func WithSource(items int, trimPath func(string) string) Middleware {
|
||||
const (
|
||||
skip = 4
|
||||
funcPrefix = "gitoa.ru/go-4devs/log.Logger"
|
||||
skipHelper = "gitoa.ru/go-4devs/log."
|
||||
skip = 4
|
||||
pkgName = "gitoa.ru/go-4devs/log"
|
||||
)
|
||||
|
||||
return WithCallers(items, skip, pkgName, trimPath)
|
||||
}
|
||||
|
||||
func WithCallers(items, skip int, logPkg string, trimPath func(string) string) Middleware {
|
||||
items += skip
|
||||
skipHelper := logPkg + "."
|
||||
funcPrefix := skipHelper + funcName
|
||||
|
||||
return func(ctx context.Context, data *entry.Entry, handler Logger) (int, error) {
|
||||
pc := make([]uintptr, items)
|
||||
@@ -86,7 +93,7 @@ func (l Source) MarshalText() ([]byte, error) {
|
||||
}
|
||||
|
||||
func (l Source) MarshalJSON() ([]byte, error) {
|
||||
return fmt.Appendf([]byte{}, `{"file":"%s","line":%d,"func":"%s"}`, l.File, l.Line, l.Func), nil
|
||||
return fmt.Appendf([]byte{}, `{"file":%q,"line":%d,"func":"%s"}`, l.File, l.Line, l.Func), nil
|
||||
}
|
||||
|
||||
func errSourceField(skip, mframe int) field.Field {
|
||||
|
||||
23
source_test.go
Normal file
23
source_test.go
Normal file
@@ -0,0 +1,23 @@
|
||||
package log_test
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"testing"
|
||||
|
||||
"gitoa.ru/go-4devs/log"
|
||||
)
|
||||
|
||||
func TestSource_MarshalJSON(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
src := log.Source{
|
||||
Func: "fn name",
|
||||
File: `file " \n name`,
|
||||
Line: 42,
|
||||
}
|
||||
|
||||
data, err := json.Marshal(src)
|
||||
if err != nil || len(data) == 0 || string(data) != `{"file":"file \" \\n name","line":42,"func":"fn name"}` {
|
||||
t.Fatalf("failed marshal: err=%v, data=%v", err, string(data))
|
||||
}
|
||||
}
|
||||
@@ -63,7 +63,7 @@ type option struct {
|
||||
out io.Writer
|
||||
}
|
||||
|
||||
// New creates standart logger.
|
||||
// New creates standard logger.
|
||||
func New(opts ...func(*option)) Logger {
|
||||
log := option{
|
||||
format: FormatString(field.NewEncoderText()),
|
||||
Reference in New Issue
Block a user