6 Commits

Author SHA1 Message Date
859a8d88f7 Merge pull request 'update ling and go version' (#17) from format into master
All checks were successful
continuous-integration/drone/push Build is passing
continuous-integration/drone/tag Build is passing
Reviewed-on: #17
2024-04-04 12:19:45 +03:00
4baf4b36e7 set golang version
All checks were successful
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
2024-04-04 12:17:02 +03:00
andrey
2fd0c1f9ec update ling and go version
Some checks failed
continuous-integration/drone/push Build is failing
continuous-integration/drone/pr Build is failing
2024-04-04 12:12:09 +03:00
c7090b5067 Merge pull request 'use dependency format log' (#16) from format into master
Some checks failed
continuous-integration/drone/push Build is failing
Reviewed-on: #16
2024-04-04 12:08:06 +03:00
andrey
16d3e04fd9 use dependency format log 2024-04-04 12:04:45 +03:00
57a908f894 add bracket format (#15)
All checks were successful
continuous-integration/drone/tag Build is passing
continuous-integration/drone/push Build is passing
Reviewed-on: #15
Co-authored-by: andrey <andrey@4devs.io>
Co-committed-by: andrey <andrey@4devs.io>
2024-01-03 21:35:21 +03:00
15 changed files with 143 additions and 95 deletions

View File

@@ -5,7 +5,7 @@ name: logger
steps: steps:
- name: test - name: test
image: golang:1.21.5 image: golang:1.22.2
volumes: volumes:
- name: deps - name: deps
path: /go/src/mod path: /go/src/mod
@@ -13,85 +13,10 @@ steps:
- go test - go test
- name: golangci-lint - name: golangci-lint
image: golangci/golangci-lint:v1.55 image: golangci/golangci-lint:v1.57
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

@@ -73,3 +73,4 @@ issues:
- path: example/* - path: example/*
linters: linters:
- gomnd - gomnd
- lll

View File

@@ -166,7 +166,9 @@ func BenchmarkDisabledAccumulatedContext(b *testing.B) {
b.Run("4devs/log.Context", func(b *testing.B) { b.Run("4devs/log.Context", func(b *testing.B) {
b.ResetTimer() b.ResetTimer()
logger := NewLogger().With(log.GoVersion("goversion")) logger := NewLogger().With(log.GoVersion("goversion"))
b.RunParallel(func(pb *testing.PB) { b.RunParallel(func(pb *testing.PB) {
for pb.Next() { for pb.Next() {
logger.InfoKV(ctx, getMessage(0), fakeFields()...) logger.InfoKV(ctx, getMessage(0), fakeFields()...)

View File

@@ -2,6 +2,7 @@ package main
import ( import (
"context" "context"
"time"
"gitoa.ru/go-4devs/log" "gitoa.ru/go-4devs/log"
"gitoa.ru/go-4devs/log/field" "gitoa.ru/go-4devs/log/field"
@@ -16,9 +17,13 @@ func main() {
log.Err(ctx, "error message", 42) log.Err(ctx, "error message", 42)
service(ctx, log.Log()) service(ctx, log.Log())
logger := log.New(log.WithJSONFormat()).With(log.WithSource(10, log.TrimPath)) logger := log.New(log.WithJSONFormat()).With(log.WithSource(10, log.TrimPath), log.WithTime(log.KeyTime, time.RFC3339))
logger.AlertKV(ctx, "alert message new logger", field.String("string", "value")) logger.AlertKV(ctx, "alert message new logger", field.String("string", "value"))
service(ctx, logger) service(ctx, logger)
strLogger := log.New(log.WithFormat(log.FormatWithBracket(field.NewEncoderText()))).With(log.WithSource(10, log.TrimPath), log.WithTime(log.KeyTime, time.RFC3339))
strLogger.AlertKV(ctx, "alert message new txt logger", field.String("string", "value"))
service(ctx, strLogger)
} }
func service(ctx context.Context, logger log.Logger) { func service(ctx context.Context, logger log.Logger) {

View File

@@ -174,6 +174,7 @@ func needsQuoting(in string) bool {
if char != '\\' && (char == ' ' || char == '=' || !safeSet[char]) { if char != '\\' && (char == ' ' || char == '=' || !safeSet[char]) {
return true return true
} }
i++ i++
continue continue

View File

@@ -501,3 +501,14 @@ type Field struct {
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)
} }
// String implent stringer.
func (f Field) IsKey(keys ...string) bool {
for _, key := range keys {
if key == f.Key {
return true
}
}
return false
}

View File

@@ -3,6 +3,7 @@ package log
import ( import (
"context" "context"
"io" "io"
"time"
"gitoa.ru/go-4devs/log/field" "gitoa.ru/go-4devs/log/field"
"gitoa.ru/go-4devs/log/level" "gitoa.ru/go-4devs/log/level"
@@ -10,7 +11,7 @@ import (
//nolint:gochecknoglobals,gomnd //nolint:gochecknoglobals,gomnd
var global = With(New(), var global = With(New(),
WithSource(2, TrimPath), WithTime(KeyTime, time.RFC3339),
WithLevel(KeyLevel, level.Debug), WithLevel(KeyLevel, level.Debug),
WithExit(level.Alert), WithExit(level.Alert),
WithPanic(level.Emergency), WithPanic(level.Emergency),

View File

@@ -11,11 +11,13 @@ import (
) )
// Standard create new standart logrus handler. // Standard create new standart logrus handler.
// Deprecated: delete after 0.7.0
func Standard() log.Logger { func Standard() log.Logger {
return New(logrus.StandardLogger()) return New(logrus.StandardLogger())
} }
// New create new logrus handler. // New create new logrus handler.
// Deprecated: delete after 0.7.0
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, data *entry.Entry) (int, error) {
lrgFields := make(logrus.Fields, data.Fields().Len()) lrgFields := make(logrus.Fields, data.Fields().Len())

View File

@@ -7,6 +7,7 @@ import (
"gitoa.ru/go-4devs/log/entry" "gitoa.ru/go-4devs/log/entry"
) )
// Deprecated: delete after 0.7.0
func New() log.Logger { func New() log.Logger {
return func(ctx context.Context, e *entry.Entry) (int, error) { return func(ctx context.Context, e *entry.Entry) (int, error) {
addEvent(ctx, e) addEvent(ctx, e)

View File

@@ -7,6 +7,7 @@ import (
"gitoa.ru/go-4devs/log/entry" "gitoa.ru/go-4devs/log/entry"
) )
// Deprecated: delete after 0.7.0
func Middleware() log.Middleware { func Middleware() log.Middleware {
return func(ctx context.Context, e *entry.Entry, handler log.Logger) (int, error) { return func(ctx context.Context, e *entry.Entry, handler log.Logger) (int, error) {
addEvent(ctx, e) addEvent(ctx, e)

View File

@@ -10,14 +10,17 @@ import (
"go.uber.org/zap" "go.uber.org/zap"
) )
// Deprecated: delete after 0.7.0
func Nop() log.Logger { func Nop() log.Logger {
return New(zap.NewNop()) return New(zap.NewNop())
} }
// Deprecated: delete after 0.7.0
func Example(options ...zap.Option) log.Logger { func Example(options ...zap.Option) log.Logger {
return New(zap.NewExample(options...)) return New(zap.NewExample(options...))
} }
// Deprecated: delete after 0.7.0
func Production(options ...zap.Option) log.Logger { func Production(options ...zap.Option) log.Logger {
z, err := zap.NewProduction(options...) z, err := zap.NewProduction(options...)
if err != nil { if err != nil {
@@ -27,6 +30,7 @@ func Production(options ...zap.Option) log.Logger {
return New(z) return New(z)
} }
// Deprecated: delete after 0.7.0
func Development(options ...zap.Option) log.Logger { func Development(options ...zap.Option) log.Logger {
z, err := zap.NewDevelopment(options...) z, err := zap.NewDevelopment(options...)
if err != nil { if err != nil {

View File

@@ -213,8 +213,8 @@ func ExampleNew_jsonFormat() {
logger.Err(ctx, "same error message") logger.Err(ctx, "same error message")
logger.WarnKVs(ctx, "same warn message", "obj", Obj{Name: "obj name"}) logger.WarnKVs(ctx, "same warn message", "obj", Obj{Name: "obj name"})
// Output: // Output:
// {"msg":"same error message","level":"error","go-version":"go1.21.5"} // {"msg":"same error message","level":"error","go-version":"go1.22.2"}
// {"msg":"same warn message","obj":{"Name":"obj name","IsEnable":false},"level":"warning","go-version":"go1.21.5"} // {"msg":"same warn message","obj":{"Name":"obj name","IsEnable":false},"level":"warning","go-version":"go1.22.2"}
} }
func ExampleNew_textEncoding() { func ExampleNew_textEncoding() {
@@ -227,8 +227,8 @@ func ExampleNew_textEncoding() {
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, "obj", Obj{Name: "text value", IsEnable: true})
// Output: // Output:
// msg="same error message" level=error go-version=go1.21.5 // msg="same error message" level=error go-version=go1.22.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 obj={Name:text value IsEnable:true} level=info go-version=go1.22.2
} }
type ctxKey string type ctxKey string
@@ -252,7 +252,7 @@ func ExampleWith() {
log.GoVersion("go"), 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.22.2
} }
func ExampleLogger_Print() { func ExampleLogger_Print() {
@@ -263,7 +263,7 @@ func ExampleLogger_Print() {
log.GoVersion("go"), 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.22.2
} }
func ExamplePrint() { func ExamplePrint() {

View File

@@ -38,6 +38,7 @@ func With(logger Logger, mw ...Middleware) Logger {
if curI == lastI { if curI == lastI {
return logger(currentCtx, currentEntry) return logger(currentCtx, currentEntry)
} }
curI++ curI++
n, err := mw[curI](currentCtx, currentEntry, chainHandler) n, err := mw[curI](currentCtx, currentEntry, chainHandler)
curI-- curI--

37
writer_example_test.go Normal file
View File

@@ -0,0 +1,37 @@
package log_test
import (
"context"
"math"
"path/filepath"
"time"
"gitoa.ru/go-4devs/log"
"gitoa.ru/go-4devs/log/entry"
"gitoa.ru/go-4devs/log/field"
"gitoa.ru/go-4devs/log/level"
)
func exampleWithTime(key, format string) log.Middleware {
return func(ctx context.Context, e *entry.Entry, handler log.Logger) (int, error) {
return handler(ctx, e.Add(field.FormatTime(key, format, time.Unix(math.MaxInt32, 0).In(time.UTC))))
}
}
func ExampleFormatWithBracket() {
ctx := context.Background()
logger := log.New(log.WithFormat(log.FormatWithBracket(field.NewEncoderText())), log.WithStdout()).With(
log.WithSource(10, filepath.Base),
// log.WithTime(log.KeyTime, time.RFC3339),
exampleWithTime(log.KeyTime, time.RFC3339),
log.WithLevel(log.KeyLevel, level.Info),
)
logger.InfoKV(ctx, "imfo message", field.Int64("num", 42))
serviceLogger := logger.With(log.WithName("service_name"))
serviceLogger.Err(ctx, "error message")
// Output:
// 2038-01-19T03:14:07Z [info] writer_example_test.go:30 "imfo message" num=42
// 2038-01-19T03:14:07Z [error][service_name] writer_example_test.go:33 "error message"
}

View File

@@ -43,15 +43,18 @@ func WithStdout() func(*option) {
// WithStringFormat sets format as simple string. // WithStringFormat sets format as simple string.
func WithStringFormat() func(*option) { func WithStringFormat() func(*option) {
return func(o *option) { return WithFormat(FormatString(field.NewEncoderText()))
o.format = formatText()
}
} }
// WithJSONFormat sets json output format. // WithJSONFormat sets json output format.
func WithJSONFormat() func(*option) { func WithJSONFormat() func(*option) {
return WithFormat(FormatJSON(field.NewEncoderJSON()))
}
// WithFormat sets custom output format.
func WithFormat(format func(io.Writer, *entry.Entry) (int, error)) func(*option) {
return func(o *option) { return func(o *option) {
o.format = formatJSON() o.format = format
} }
} }
@@ -63,7 +66,7 @@ type option struct {
// New creates standart logger. // New creates standart logger.
func New(opts ...func(*option)) Logger { func New(opts ...func(*option)) Logger {
log := option{ log := option{
format: formatText(), format: FormatString(field.NewEncoderText()),
out: os.Stderr, out: os.Stderr,
} }
@@ -76,9 +79,64 @@ func New(opts ...func(*option)) Logger {
} }
} }
func formatText() func(io.Writer, *entry.Entry) (int, error) { type Encoder interface {
enc := field.NewEncoderText() AppendValue(dst []byte, val field.Value) []byte
AppendField(dst []byte, val field.Field) []byte
}
func FormatWithBracket(enc Encoder) func(io.Writer, *entry.Entry) (int, error) {
appendValue := func(buf *buffer.Buffer, data field.Fields, key, prefix, suffix string) *buffer.Buffer {
data.Fields(
func(f field.Field) bool {
if f.IsKey(key) {
_, _ = buf.WriteString(prefix)
*buf = enc.AppendValue(*buf, f.Value)
_, _ = buf.WriteString(suffix)
return false
}
return true
})
return buf
}
return func(w io.Writer, data *entry.Entry) (int, error) {
buf := buffer.New()
defer func() {
buf.Free()
}()
fields := data.Fields()
buf = appendValue(buf, fields, KeyTime, "", " ")
_, _ = buf.WriteString("[")
*buf = enc.AppendValue(*buf, field.StringValue(data.Level().String()))
_, _ = buf.WriteString("]")
buf = appendValue(buf, fields, KeyName, "[", "]")
buf = appendValue(buf, fields, KeySource, " ", " ")
*buf = enc.AppendValue(*buf, field.StringValue(data.Message()))
fields.Fields(func(f field.Field) bool {
if !f.IsKey(KeyTime, KeySource, KeyName, KeyLevel) {
*buf = enc.AppendField(*buf, f)
}
return true
})
_, _ = buf.WriteString("\n")
n, err := w.Write(*buf)
if err != nil {
return 0, fmt.Errorf("format text:%w", err)
}
return n, nil
}
}
func FormatString(enc Encoder) func(io.Writer, *entry.Entry) (int, error) {
return func(w io.Writer, entry *entry.Entry) (int, error) { return func(w io.Writer, entry *entry.Entry) (int, error) {
buf := buffer.New() buf := buffer.New()
defer func() { defer func() {
@@ -102,9 +160,7 @@ func formatText() func(io.Writer, *entry.Entry) (int, error) {
} }
} }
func formatJSON() func(w io.Writer, entry *entry.Entry) (int, error) { func FormatJSON(enc Encoder) func(w io.Writer, entry *entry.Entry) (int, error) {
enc := field.NewEncoderJSON()
return func(w io.Writer, entry *entry.Entry) (int, error) { return func(w io.Writer, entry *entry.Entry) (int, error) {
buf := buffer.New() buf := buffer.New()
defer func() { defer func() {