restore v 0.2.0
This commit is contained in:
50
.drone.yml
Normal file
50
.drone.yml
Normal file
@@ -0,0 +1,50 @@
|
||||
kind: pipeline
|
||||
name: default
|
||||
|
||||
steps:
|
||||
- name: test
|
||||
image: golang:1.14.2
|
||||
volumes:
|
||||
- name: deps
|
||||
path: /go/src/mod
|
||||
commands:
|
||||
- go test
|
||||
|
||||
- name: golangci-lint
|
||||
image: golangci/golangci-lint:v1.29
|
||||
commands:
|
||||
- golangci-lint run
|
||||
|
||||
- name: logrus golangci-lint
|
||||
image: golangci/golangci-lint:v1.29
|
||||
commands:
|
||||
- cd logrus
|
||||
- golangci-lint run
|
||||
|
||||
- name: logrus test
|
||||
image: golang:1.14.2
|
||||
volumes:
|
||||
- name: deps
|
||||
path: /go/src/mod
|
||||
commands:
|
||||
- cd logrus
|
||||
- go test
|
||||
|
||||
- name: zap golangci-lint
|
||||
image: golangci/golangci-lint:v1.29
|
||||
commands:
|
||||
- cd zap
|
||||
- golangci-lint run
|
||||
|
||||
- name: zap test
|
||||
image: golang:1.14.2
|
||||
volumes:
|
||||
- name: deps
|
||||
path: /go/src/mod
|
||||
commands:
|
||||
- cd zap
|
||||
- go test
|
||||
|
||||
volumes:
|
||||
- name: deps
|
||||
temp: {}
|
||||
17
.gitignore
vendored
Normal file
17
.gitignore
vendored
Normal file
@@ -0,0 +1,17 @@
|
||||
# ---> Go
|
||||
# Binaries for programs and plugins
|
||||
*.exe
|
||||
*.exe~
|
||||
*.dll
|
||||
*.so
|
||||
*.dylib
|
||||
|
||||
# Test binary, built with `go test -c`
|
||||
*.test
|
||||
|
||||
# Output of the go coverage tool, specifically when used with LiteIDE
|
||||
*.out
|
||||
|
||||
# Dependency directories (remove the comment below to include it)
|
||||
# vendor/
|
||||
|
||||
33
.golangci.yml
Normal file
33
.golangci.yml
Normal file
@@ -0,0 +1,33 @@
|
||||
linters-settings:
|
||||
dupl:
|
||||
threshold: 100
|
||||
funlen:
|
||||
lines: 100
|
||||
statements: 50
|
||||
goconst:
|
||||
min-len: 2
|
||||
min-occurrences: 2
|
||||
gocyclo:
|
||||
min-complexity: 15
|
||||
golint:
|
||||
min-confidence: 0
|
||||
govet:
|
||||
check-shadowing: true
|
||||
lll:
|
||||
line-length: 140
|
||||
maligned:
|
||||
suggest-new: true
|
||||
misspell:
|
||||
locale: US
|
||||
exhaustive:
|
||||
default-signifies-exhaustive: true
|
||||
|
||||
linters:
|
||||
enable-all: true
|
||||
|
||||
issues:
|
||||
# Excluding configuration per-path, per-linter, per-text and per-source
|
||||
exclude-rules:
|
||||
- path: _test\.go
|
||||
linters:
|
||||
- gomnd
|
||||
19
LICENSE
Normal file
19
LICENSE
Normal file
@@ -0,0 +1,19 @@
|
||||
MIT License Copyright (c) 2020 go-4devs
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is furnished
|
||||
to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice (including the next
|
||||
paragraph) shall be included in all copies or substantial portions of the
|
||||
Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS
|
||||
OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
|
||||
OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
5
README.md
Normal file
5
README.md
Normal file
@@ -0,0 +1,5 @@
|
||||
# log
|
||||
|
||||
[](https://drone.gitoa.ru/go-4devs/log)
|
||||
[](https://goreportcard.com/report/gitoa.ru/go-4devs/log)
|
||||
[](http://godoc.org/gitoa.ru/go-4devs/log)
|
||||
4
doc.go
Normal file
4
doc.go
Normal file
@@ -0,0 +1,4 @@
|
||||
/*
|
||||
Package log logged data by handler and use processor, exposes eight methods to write logs to the eight RFC 5424 levels.
|
||||
*/
|
||||
package log
|
||||
40
field.go
Normal file
40
field.go
Normal file
@@ -0,0 +1,40 @@
|
||||
package log
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// Fields slice field.
|
||||
type Fields []Field
|
||||
|
||||
// String implement stringer.
|
||||
func (f Fields) String() string {
|
||||
str := make([]string, len(f))
|
||||
for i, field := range f {
|
||||
str[i] = field.String()
|
||||
}
|
||||
|
||||
return strings.Join(str, " ")
|
||||
}
|
||||
|
||||
// NewField create field.
|
||||
func NewField(key string, value interface{}) Field {
|
||||
return Field{Key: key, Value: value}
|
||||
}
|
||||
|
||||
// Field struct.
|
||||
type Field struct {
|
||||
Key string
|
||||
Value interface{}
|
||||
}
|
||||
|
||||
// String implent stringer.
|
||||
func (f Field) String() string {
|
||||
return fmt.Sprintf("%s=%+v", f.Key, f.Value)
|
||||
}
|
||||
|
||||
// FieldError new errors field with key error.
|
||||
func FieldError(err error) Field {
|
||||
return NewField("error", err)
|
||||
}
|
||||
183
global.go
Normal file
183
global.go
Normal file
@@ -0,0 +1,183 @@
|
||||
package log
|
||||
|
||||
import (
|
||||
"context"
|
||||
)
|
||||
|
||||
//nolint:gochecknoglobals
|
||||
var global = With(New(), WithLevel(LevelDebug))
|
||||
|
||||
// SetLogger sets global used logger. This function is not thread-safe.
|
||||
func SetLogger(l Logger) {
|
||||
global = l
|
||||
}
|
||||
|
||||
// GetLogger return global logger.
|
||||
func GetLogger() Logger {
|
||||
return global
|
||||
}
|
||||
|
||||
// Emerg log by emergency level.
|
||||
func Emerg(ctx context.Context, args ...interface{}) {
|
||||
global.Emerg(ctx, args...)
|
||||
}
|
||||
|
||||
// Alert log by alert level.
|
||||
func Alert(ctx context.Context, args ...interface{}) {
|
||||
global.Alert(ctx, args...)
|
||||
}
|
||||
|
||||
// Crit log by critical level.
|
||||
func Crit(ctx context.Context, args ...interface{}) {
|
||||
global.Crit(ctx, args...)
|
||||
}
|
||||
|
||||
// Err log by error level.
|
||||
func Err(ctx context.Context, args ...interface{}) {
|
||||
global.Err(ctx, args...)
|
||||
}
|
||||
|
||||
// Warn logs by warning level.
|
||||
func Warn(ctx context.Context, args ...interface{}) {
|
||||
global.Warn(ctx, args...)
|
||||
}
|
||||
|
||||
// Notice log by notice level.
|
||||
func Notice(ctx context.Context, args ...interface{}) {
|
||||
global.Notice(ctx, args...)
|
||||
}
|
||||
|
||||
// Info log by info level.
|
||||
func Info(ctx context.Context, args ...interface{}) {
|
||||
global.Info(ctx, args...)
|
||||
}
|
||||
|
||||
// Debug log by debug level.
|
||||
func Debug(ctx context.Context, args ...interface{}) {
|
||||
global.Debug(ctx, args...)
|
||||
}
|
||||
|
||||
// Print log by info level and arguments.
|
||||
func Print(args ...interface{}) {
|
||||
global.Print(args...)
|
||||
}
|
||||
|
||||
// Fatal log by alert level and arguments.
|
||||
func Fatal(args ...interface{}) {
|
||||
global.Fatal(args...)
|
||||
}
|
||||
|
||||
// Panic log by emergency level and arguments.
|
||||
func Panic(args ...interface{}) {
|
||||
global.Panic(args...)
|
||||
}
|
||||
|
||||
// Println log by info level and arguments.
|
||||
func Println(args ...interface{}) {
|
||||
global.Println(args...)
|
||||
}
|
||||
|
||||
// Fatalln log by alert level and arguments.
|
||||
func Fatalln(args ...interface{}) {
|
||||
global.Fatalln(args...)
|
||||
}
|
||||
|
||||
// Panicln log by emergency level and arguments.
|
||||
func Panicln(args ...interface{}) {
|
||||
global.Panicln(args...)
|
||||
}
|
||||
|
||||
// EmergKV log by emergency level and key-values.
|
||||
func EmergKV(ctx context.Context, msg string, args ...interface{}) {
|
||||
global.EmergKV(ctx, msg, args...)
|
||||
}
|
||||
|
||||
// AlertKV log by alert level and key-values.
|
||||
func AlertKV(ctx context.Context, msg string, args ...interface{}) {
|
||||
global.AlertKV(ctx, msg, args...)
|
||||
}
|
||||
|
||||
// CritKV log by critcal level and key-values.
|
||||
func CritKV(ctx context.Context, msg string, args ...interface{}) {
|
||||
global.CritKV(ctx, msg, args...)
|
||||
}
|
||||
|
||||
// ErrKV log by error level and key-values.
|
||||
func ErrKV(ctx context.Context, msg string, args ...interface{}) {
|
||||
global.ErrKV(ctx, msg, args...)
|
||||
}
|
||||
|
||||
// WarnKV log by warning level and key-values.
|
||||
func WarnKV(ctx context.Context, msg string, args ...interface{}) {
|
||||
global.WarnKV(ctx, msg, args...)
|
||||
}
|
||||
|
||||
// NoticeKV log by notice level and key-values.
|
||||
func NoticeKV(ctx context.Context, msg string, args ...interface{}) {
|
||||
global.NoticeKV(ctx, msg, args...)
|
||||
}
|
||||
|
||||
// InfoKV log by info level and key-values.
|
||||
func InfoKV(ctx context.Context, msg string, args ...interface{}) {
|
||||
global.InfoKV(ctx, msg, args...)
|
||||
}
|
||||
|
||||
// DebugKV log by debug level and key-values.
|
||||
func DebugKV(ctx context.Context, msg string, args ...interface{}) {
|
||||
global.DebugKV(ctx, msg, args...)
|
||||
}
|
||||
|
||||
// Emergf log by emergency level by format and arguments.
|
||||
func Emergf(ctx context.Context, format string, args ...interface{}) {
|
||||
global.Emergf(ctx, format, args...)
|
||||
}
|
||||
|
||||
// Alertf log by alert level by format and arguments.
|
||||
func Alertf(ctx context.Context, format string, args ...interface{}) {
|
||||
global.Alertf(ctx, format, args...)
|
||||
}
|
||||
|
||||
// Critf log by critical level by format and arguments.
|
||||
func Critf(ctx context.Context, format string, args ...interface{}) {
|
||||
global.Critf(ctx, format, args...)
|
||||
}
|
||||
|
||||
// Errf log by error level by format and arguments.
|
||||
func Errf(ctx context.Context, format string, args ...interface{}) {
|
||||
global.Errf(ctx, format, args...)
|
||||
}
|
||||
|
||||
// Warnf log by warning level by format and arguments.
|
||||
func Warnf(ctx context.Context, format string, args ...interface{}) {
|
||||
global.Warnf(ctx, format, args...)
|
||||
}
|
||||
|
||||
// Noticef log by notice level by format and arguments.
|
||||
func Noticef(ctx context.Context, format string, args ...interface{}) {
|
||||
global.Noticef(ctx, format, args...)
|
||||
}
|
||||
|
||||
// Infof log by info level by format and arguments.
|
||||
func Infof(ctx context.Context, format string, args ...interface{}) {
|
||||
global.Noticef(ctx, format, args...)
|
||||
}
|
||||
|
||||
// Debugf log by debug level by format and arguments.
|
||||
func Debugf(ctx context.Context, format string, args ...interface{}) {
|
||||
global.Debugf(ctx, format, args...)
|
||||
}
|
||||
|
||||
// Printf log by info level by format and arguments without context.
|
||||
func Printf(format string, args ...interface{}) {
|
||||
global.Printf(format, args...)
|
||||
}
|
||||
|
||||
// Fatalf log by alert level by format and arguments without context.
|
||||
func Fatalf(format string, args ...interface{}) {
|
||||
global.Fatalf(format, args...)
|
||||
}
|
||||
|
||||
// Panicf log by emergency level and arguments without context.
|
||||
func Panicf(format string, args ...interface{}) {
|
||||
global.Panicf(format, args...)
|
||||
}
|
||||
22
level.go
Normal file
22
level.go
Normal file
@@ -0,0 +1,22 @@
|
||||
package log
|
||||
|
||||
//go:generate stringer -type=Level -linecomment
|
||||
|
||||
// Level log.
|
||||
type Level uint8
|
||||
|
||||
// awailable log levels.
|
||||
const (
|
||||
LevelEmergency Level = iota // emergency
|
||||
LevelAlert // alert
|
||||
LevelCritical // critical
|
||||
LevelError // error
|
||||
LevelWarning // warning
|
||||
LevelNotice // notice
|
||||
LevelInfo // info
|
||||
LevelDebug // debug
|
||||
)
|
||||
|
||||
func (l Level) MarshalJSON() ([]byte, error) {
|
||||
return []byte("\"" + l.String() + "\""), nil
|
||||
}
|
||||
30
level_string.go
Normal file
30
level_string.go
Normal file
@@ -0,0 +1,30 @@
|
||||
// Code generated by "stringer -type=Level -linecomment"; DO NOT EDIT.
|
||||
|
||||
package log
|
||||
|
||||
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[LevelEmergency-0]
|
||||
_ = x[LevelAlert-1]
|
||||
_ = x[LevelCritical-2]
|
||||
_ = x[LevelError-3]
|
||||
_ = x[LevelWarning-4]
|
||||
_ = x[LevelNotice-5]
|
||||
_ = x[LevelInfo-6]
|
||||
_ = x[LevelDebug-7]
|
||||
}
|
||||
|
||||
const _Level_name = "emergencyalertcriticalerrorwarningnoticeinfodebug"
|
||||
|
||||
var _Level_index = [...]uint8{0, 9, 14, 22, 27, 34, 40, 44, 49}
|
||||
|
||||
func (i Level) String() string {
|
||||
if i >= Level(len(_Level_index)-1) {
|
||||
return "Level(" + strconv.FormatInt(int64(i), 10) + ")"
|
||||
}
|
||||
return _Level_name[_Level_index[i]:_Level_index[i+1]]
|
||||
}
|
||||
223
logger.go
Normal file
223
logger.go
Normal file
@@ -0,0 +1,223 @@
|
||||
package log
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
// Logger logged message.
|
||||
type Logger func(ctx context.Context, level Level, msg string, fields Fields)
|
||||
|
||||
func (l Logger) log(ctx context.Context, level Level, args ...interface{}) {
|
||||
l(ctx, level, fmt.Sprint(args...), nil)
|
||||
}
|
||||
|
||||
func (l Logger) logKV(ctx context.Context, level Level, msg string, args ...interface{}) {
|
||||
l(ctx, level, msg, l.kv(ctx, args...))
|
||||
}
|
||||
|
||||
func (l Logger) logf(ctx context.Context, level Level, format string, args ...interface{}) {
|
||||
l(ctx, level, fmt.Sprintf(format, args...), nil)
|
||||
}
|
||||
|
||||
func (l Logger) logln(ctx context.Context, level Level, args ...interface{}) {
|
||||
l(ctx, level, fmt.Sprintln(args...), nil)
|
||||
}
|
||||
|
||||
func (l Logger) kv(ctx context.Context, args ...interface{}) []Field {
|
||||
fields := make([]Field, 0, len(args))
|
||||
|
||||
for i := 0; i < len(args); i++ {
|
||||
if f, ok := args[i].(Field); ok {
|
||||
fields = append(fields, f)
|
||||
continue
|
||||
}
|
||||
|
||||
if i == len(args)-1 {
|
||||
l(ctx, LevelCritical, fmt.Sprint("Ignored key without a value.", args[i]), fields)
|
||||
break
|
||||
}
|
||||
|
||||
i++
|
||||
|
||||
key, val := args[i-1], args[i]
|
||||
if keyStr, ok := key.(string); ok {
|
||||
fields = append(fields, Field{Key: keyStr, Value: val})
|
||||
continue
|
||||
}
|
||||
|
||||
l(ctx, LevelCritical, fmt.Sprint("Ignored key-value pairs with non-string keys.", key, val), fields)
|
||||
}
|
||||
|
||||
return fields
|
||||
}
|
||||
|
||||
// With adds middlewares to logger.
|
||||
func (l Logger) With(mw ...Middleware) Logger {
|
||||
return With(l, mw...)
|
||||
}
|
||||
|
||||
// Emerg log by emergency level.
|
||||
func (l Logger) Emerg(ctx context.Context, args ...interface{}) {
|
||||
l.log(ctx, LevelEmergency, args...)
|
||||
}
|
||||
|
||||
// Alert log by alert level.
|
||||
func (l Logger) Alert(ctx context.Context, args ...interface{}) {
|
||||
l.log(ctx, LevelAlert, args...)
|
||||
}
|
||||
|
||||
// Crit log by critical level.
|
||||
func (l Logger) Crit(ctx context.Context, args ...interface{}) {
|
||||
l.log(ctx, LevelCritical, args...)
|
||||
}
|
||||
|
||||
// Err log by error level.
|
||||
func (l Logger) Err(ctx context.Context, args ...interface{}) {
|
||||
l.log(ctx, LevelError, args...)
|
||||
}
|
||||
|
||||
// Warn log by warning level.
|
||||
func (l Logger) Warn(ctx context.Context, args ...interface{}) {
|
||||
l.log(ctx, LevelWarning, args...)
|
||||
}
|
||||
|
||||
// Notice log by notice level.
|
||||
func (l Logger) Notice(ctx context.Context, args ...interface{}) {
|
||||
l.log(ctx, LevelNotice, args...)
|
||||
}
|
||||
|
||||
// Info log by info level.
|
||||
func (l Logger) Info(ctx context.Context, args ...interface{}) {
|
||||
l.log(ctx, LevelInfo, args...)
|
||||
}
|
||||
|
||||
// Debug log by debug level.
|
||||
func (l Logger) Debug(ctx context.Context, args ...interface{}) {
|
||||
l.log(ctx, LevelDebug, args...)
|
||||
}
|
||||
|
||||
// Print log by info level and arguments.
|
||||
func (l Logger) Print(args ...interface{}) {
|
||||
l.log(context.Background(), LevelInfo, args...)
|
||||
}
|
||||
|
||||
// Fatal log by alert level and arguments.
|
||||
func (l Logger) Fatal(args ...interface{}) {
|
||||
l.log(context.Background(), LevelAlert, args...)
|
||||
}
|
||||
|
||||
// Panic log by emergency level and arguments.
|
||||
func (l Logger) Panic(args ...interface{}) {
|
||||
l.log(context.Background(), LevelEmergency, args...)
|
||||
}
|
||||
|
||||
// Println log by info level and arguments.
|
||||
func (l Logger) Println(args ...interface{}) {
|
||||
l.logln(context.Background(), LevelInfo, args...)
|
||||
}
|
||||
|
||||
// Fatalln log by alert level and arguments.
|
||||
func (l Logger) Fatalln(args ...interface{}) {
|
||||
l.logln(context.Background(), LevelAlert, args...)
|
||||
}
|
||||
|
||||
// Panicln log by emergency level and arguments.
|
||||
func (l Logger) Panicln(args ...interface{}) {
|
||||
l.logln(context.Background(), LevelEmergency, args...)
|
||||
}
|
||||
|
||||
// EmergKV log by emergency level and key-values.
|
||||
func (l Logger) EmergKV(ctx context.Context, msg string, args ...interface{}) {
|
||||
l.logKV(ctx, LevelEmergency, msg, args...)
|
||||
}
|
||||
|
||||
// AlertKV log by alert level and key-values.
|
||||
func (l Logger) AlertKV(ctx context.Context, msg string, args ...interface{}) {
|
||||
l.logKV(ctx, LevelAlert, msg, args...)
|
||||
}
|
||||
|
||||
// CritKV log by critcal level and key-values.
|
||||
func (l Logger) CritKV(ctx context.Context, msg string, args ...interface{}) {
|
||||
l.logKV(ctx, LevelCritical, msg, args...)
|
||||
}
|
||||
|
||||
// ErrKV log by error level and key-values.
|
||||
func (l Logger) ErrKV(ctx context.Context, msg string, args ...interface{}) {
|
||||
l.logKV(ctx, LevelError, msg, args...)
|
||||
}
|
||||
|
||||
// WarnKV log by warning level and key-values.
|
||||
func (l Logger) WarnKV(ctx context.Context, msg string, args ...interface{}) {
|
||||
l.logKV(ctx, LevelWarning, msg, args...)
|
||||
}
|
||||
|
||||
// NoticeKV log by notice level and key-values.
|
||||
func (l Logger) NoticeKV(ctx context.Context, msg string, args ...interface{}) {
|
||||
l.logKV(ctx, LevelNotice, msg, args...)
|
||||
}
|
||||
|
||||
// InfoKV log by info level and key-values.
|
||||
func (l Logger) InfoKV(ctx context.Context, msg string, args ...interface{}) {
|
||||
l.logKV(ctx, LevelInfo, msg, args...)
|
||||
}
|
||||
|
||||
// DebugKV log by debug level and key-values.
|
||||
func (l Logger) DebugKV(ctx context.Context, msg string, args ...interface{}) {
|
||||
l.logKV(ctx, LevelDebug, msg, args...)
|
||||
}
|
||||
|
||||
// Emergf log by emergency level by format and arguments.
|
||||
func (l Logger) Emergf(ctx context.Context, format string, args ...interface{}) {
|
||||
l.logf(ctx, LevelEmergency, format, args...)
|
||||
}
|
||||
|
||||
// Alertf log by alert level by format and arguments.
|
||||
func (l Logger) Alertf(ctx context.Context, format string, args ...interface{}) {
|
||||
l.logf(ctx, LevelAlert, format, args...)
|
||||
}
|
||||
|
||||
// Critf log by critical level by format and arguments.
|
||||
func (l Logger) Critf(ctx context.Context, format string, args ...interface{}) {
|
||||
l.logf(ctx, LevelCritical, format, args...)
|
||||
}
|
||||
|
||||
// Errf log by error level by format and arguments.
|
||||
func (l Logger) Errf(ctx context.Context, format string, args ...interface{}) {
|
||||
l.logf(ctx, LevelError, format, args...)
|
||||
}
|
||||
|
||||
// Warnf log by warning level by format and arguments.
|
||||
func (l Logger) Warnf(ctx context.Context, format string, args ...interface{}) {
|
||||
l.logf(ctx, LevelWarning, format, args...)
|
||||
}
|
||||
|
||||
// Noticef log by notice level by format and arguments.
|
||||
func (l Logger) Noticef(ctx context.Context, format string, args ...interface{}) {
|
||||
l.logf(ctx, LevelNotice, format, args...)
|
||||
}
|
||||
|
||||
// Infof log by info level by format and arguments.
|
||||
func (l Logger) Infof(ctx context.Context, format string, args ...interface{}) {
|
||||
l.logf(ctx, LevelInfo, format, args...)
|
||||
}
|
||||
|
||||
// Debugf log by debug level by format and arguments.
|
||||
func (l Logger) Debugf(ctx context.Context, format string, args ...interface{}) {
|
||||
l.logf(ctx, LevelDebug, format, args...)
|
||||
}
|
||||
|
||||
// Printf log by info level by format and arguments without context.
|
||||
func (l Logger) Printf(format string, args ...interface{}) {
|
||||
l.logf(context.Background(), LevelInfo, format, args...)
|
||||
}
|
||||
|
||||
// Fatalf log by alert level by format and arguments without context.
|
||||
func (l Logger) Fatalf(format string, args ...interface{}) {
|
||||
l.logf(context.Background(), LevelAlert, format, args...)
|
||||
}
|
||||
|
||||
// Panicf log by emergency level and arguments without context.
|
||||
func (l Logger) Panicf(format string, args ...interface{}) {
|
||||
l.logf(context.Background(), LevelEmergency, format, args...)
|
||||
}
|
||||
126
logger_example_test.go
Normal file
126
logger_example_test.go
Normal file
@@ -0,0 +1,126 @@
|
||||
package log_test
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
std "log"
|
||||
"os"
|
||||
|
||||
"gitoa.ru/go-4devs/log"
|
||||
)
|
||||
|
||||
//nolint:gochecknoglobals
|
||||
var ctx = context.Background()
|
||||
|
||||
func ExampleNew() {
|
||||
logger := log.New(log.WithStdout())
|
||||
logger.Info(ctx, "same message")
|
||||
// Output: msg="same message"
|
||||
}
|
||||
|
||||
func ExampleInfo() {
|
||||
std.SetOutput(os.Stdout)
|
||||
std.SetFlags(0)
|
||||
log.Info(ctx, "same message")
|
||||
// Output: msg="same message" level=info
|
||||
}
|
||||
|
||||
func ExampleErrKV() {
|
||||
std.SetOutput(os.Stdout)
|
||||
std.SetFlags(0)
|
||||
log.ErrKV(ctx, "same message", "key", "addition value")
|
||||
// Output: msg="same message" key=addition value level=error
|
||||
}
|
||||
|
||||
func ExampleNew_errf() {
|
||||
logger := log.New(log.WithStdout())
|
||||
logger.Errf(ctx, "same message %d", 1)
|
||||
// Output: msg="same message 1"
|
||||
}
|
||||
|
||||
func ExampleNew_debugKV() {
|
||||
logger := log.New(log.WithStdout()).With(log.WithLevel(log.LevelDebug))
|
||||
logger.DebugKV(ctx, "same message", "error", os.ErrNotExist)
|
||||
// Output: msg="same message" error=file does not exist level=debug
|
||||
}
|
||||
|
||||
func ExampleNew_level() {
|
||||
logger := log.New(log.WithStdout()).With(log.WithLevel(log.LevelError))
|
||||
logger.Info(ctx, "same message")
|
||||
// Output:
|
||||
|
||||
logger.Err(ctx, "same error message")
|
||||
// Output: msg="same error message" level=error
|
||||
}
|
||||
|
||||
func ExampleNew_jsonFormat() {
|
||||
logger := log.New(log.WithStdout(), log.WithJSONFormat()).
|
||||
With(
|
||||
log.WithCaller(4, true),
|
||||
log.WithLevel(log.LevelDebug),
|
||||
log.GoVersion("go-version"),
|
||||
)
|
||||
logger.Err(ctx, "same error message")
|
||||
// Output: {"caller":"logger_example_test.go:63","go-version":"go1.14.2","level":"error","msg":"same error message"}
|
||||
}
|
||||
|
||||
func ExampleNew_withLogger() {
|
||||
stdlogger := std.New(os.Stdout, "same prefix ", std.Lshortfile)
|
||||
logger := log.With(
|
||||
log.New(
|
||||
log.WithLogger(
|
||||
stdlogger,
|
||||
func(msg string, fields log.Fields) string {
|
||||
return fmt.Sprint("msg=\"", msg, "\" ", fields)
|
||||
},
|
||||
),
|
||||
log.WithCalldepth(9),
|
||||
),
|
||||
log.WithLevel(log.LevelDebug),
|
||||
log.GoVersion("go-version"),
|
||||
)
|
||||
logger.Err(ctx, "same error message")
|
||||
logger.InfoKV(ctx, "same info message", "api-version", 0.1)
|
||||
|
||||
// Output:
|
||||
// same prefix logger_example_test.go:82: msg="same error message" level=error go-version=go1.14.2
|
||||
// same prefix logger_example_test.go:83: msg="same info message" api-version=0.1 level=info go-version=go1.14.2
|
||||
}
|
||||
|
||||
type ctxKey string
|
||||
|
||||
func (c ctxKey) String() string {
|
||||
return string(c)
|
||||
}
|
||||
|
||||
func levelInfo(ctx context.Context, level log.Level, msg string, fields log.Fields, handler log.Logger) {
|
||||
handler(ctx, level, msg, append(fields, log.Field{Key: "level", Value: level}))
|
||||
}
|
||||
|
||||
func ExampleWith() {
|
||||
var requestID ctxKey = "requestID"
|
||||
vctx := context.WithValue(ctx, requestID, "6a5fa048-7181-11ea-bc55-0242ac130003")
|
||||
|
||||
logger := log.With(
|
||||
log.New(log.WithStdout()),
|
||||
levelInfo, log.WithContextValue(requestID), log.KeyValue("api", "0.1.0"), log.GoVersion("go"),
|
||||
)
|
||||
logger.Info(vctx, "same message")
|
||||
// Output: msg="same message" level=info requestID=6a5fa048-7181-11ea-bc55-0242ac130003 api=0.1.0 go=go1.14.2
|
||||
}
|
||||
|
||||
func ExampleLogger_Print() {
|
||||
logger := log.With(
|
||||
log.New(log.WithStdout()),
|
||||
levelInfo, log.KeyValue("client", "http"), log.KeyValue("api", "0.1.0"), log.GoVersion("go"),
|
||||
)
|
||||
logger.Print("same message")
|
||||
// Output: msg="same message" level=info client=http api=0.1.0 go=go1.14.2
|
||||
}
|
||||
|
||||
func ExamplePrint() {
|
||||
std.SetOutput(os.Stdout)
|
||||
std.SetFlags(0)
|
||||
log.Print("same message")
|
||||
// Output: msg="same message" level=info
|
||||
}
|
||||
31
logger_test.go
Normal file
31
logger_test.go
Normal file
@@ -0,0 +1,31 @@
|
||||
package log_test
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"os"
|
||||
"testing"
|
||||
|
||||
"gitoa.ru/go-4devs/log"
|
||||
)
|
||||
|
||||
func TestFields(t *testing.T) {
|
||||
type rObj struct {
|
||||
id string
|
||||
}
|
||||
|
||||
ctx := context.Background()
|
||||
buf := &bytes.Buffer{}
|
||||
log := log.New(log.WithWriter(buf))
|
||||
success := "msg=\"message\" err=file already exists version=0.1.0 obj={id:uid}\n"
|
||||
|
||||
log.InfoKV(ctx, "message",
|
||||
"err", os.ErrExist,
|
||||
"version", "0.1.0",
|
||||
"obj", rObj{id: "uid"},
|
||||
)
|
||||
|
||||
if success != buf.String() {
|
||||
t.Errorf("invalid value\n got:%s\n exp:%s", buf, success)
|
||||
}
|
||||
}
|
||||
111
middleware.go
Normal file
111
middleware.go
Normal file
@@ -0,0 +1,111 @@
|
||||
package log
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"time"
|
||||
)
|
||||
|
||||
// Middleware handle.
|
||||
type Middleware func(ctx context.Context, level Level, msg string, fields Fields, handler Logger)
|
||||
|
||||
// With add middleware to logger.
|
||||
func With(logger Logger, mw ...Middleware) Logger {
|
||||
switch len(mw) {
|
||||
case 0:
|
||||
return logger
|
||||
case 1:
|
||||
return func(ctx context.Context, level Level, msg string, fields Fields) {
|
||||
mw[0](ctx, level, msg, fields, logger)
|
||||
}
|
||||
}
|
||||
|
||||
lastI := len(mw) - 1
|
||||
|
||||
return func(ctx context.Context, level Level, msg string, fields Fields) {
|
||||
var (
|
||||
chainHandler func(ctx context.Context, level Level, msg string, fields Fields)
|
||||
curI int
|
||||
)
|
||||
|
||||
chainHandler = func(currentCtx context.Context, currentLevel Level, currentMsg string, currentFields Fields) {
|
||||
if curI == lastI {
|
||||
logger(currentCtx, currentLevel, currentMsg, currentFields)
|
||||
return
|
||||
}
|
||||
curI++
|
||||
mw[curI](currentCtx, currentLevel, currentMsg, currentFields, chainHandler)
|
||||
curI--
|
||||
}
|
||||
|
||||
mw[0](ctx, level, msg, fields, chainHandler)
|
||||
}
|
||||
}
|
||||
|
||||
// WithLevel sets log level.
|
||||
func WithLevel(lvl Level) Middleware {
|
||||
return func(ctx context.Context, level Level, msg string, fields Fields, handler Logger) {
|
||||
if level <= lvl {
|
||||
handler(ctx, level, msg, append(fields, Field{Key: "level", Value: level}))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// KeyValue add field by const key value.
|
||||
func KeyValue(key string, value interface{}) Middleware {
|
||||
return func(ctx context.Context, level Level, msg string, fields Fields, handler Logger) {
|
||||
handler(ctx, level, msg, append(fields, Field{Key: key, Value: value}))
|
||||
}
|
||||
}
|
||||
|
||||
// GoVersion add field by go version.
|
||||
func GoVersion(key string) Middleware {
|
||||
return func(ctx context.Context, level Level, msg string, fields Fields, handler Logger) {
|
||||
handler(ctx, level, msg, append(fields, Field{Key: key, Value: runtime.Version()}))
|
||||
}
|
||||
}
|
||||
|
||||
// WithContext add field by context key.
|
||||
func WithContextValue(keys ...fmt.Stringer) Middleware {
|
||||
return func(ctx context.Context, level Level, msg string, fields Fields, handler Logger) {
|
||||
ctxFields := make(Fields, len(keys))
|
||||
for i, key := range keys {
|
||||
ctxFields[i] = Field{Key: key.String(), Value: ctx.Value(key)}
|
||||
}
|
||||
|
||||
handler(ctx, level, msg, append(fields, ctxFields...))
|
||||
}
|
||||
}
|
||||
|
||||
// WithCaller adds called file.
|
||||
func WithCaller(calldepth int, short bool) Middleware {
|
||||
return func(ctx context.Context, level Level, msg string, fields Fields, handler Logger) {
|
||||
_, file, line, ok := runtime.Caller(calldepth)
|
||||
if !ok {
|
||||
file, line = "???", 0
|
||||
}
|
||||
|
||||
if short && ok {
|
||||
file = filepath.Base(file)
|
||||
}
|
||||
|
||||
handler(ctx, level, msg, append(fields, NewField("caller", fmt.Sprint(file, ":", line))))
|
||||
}
|
||||
}
|
||||
|
||||
// WithTime adds time.
|
||||
func WithTime(format string) Middleware {
|
||||
return func(ctx context.Context, level Level, msg string, fields Fields, handler Logger) {
|
||||
handler(ctx, level, msg, append(fields, NewField("time", time.Now().Format(format))))
|
||||
}
|
||||
}
|
||||
|
||||
// WithMetrics adds handle metrics.
|
||||
func WithMetrics(metrics func(level Level)) Middleware {
|
||||
return func(ctx context.Context, level Level, msg string, fields Fields, handler Logger) {
|
||||
go metrics(level)
|
||||
handler(ctx, level, msg, fields)
|
||||
}
|
||||
}
|
||||
121
std.go
Normal file
121
std.go
Normal file
@@ -0,0 +1,121 @@
|
||||
package log
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"log"
|
||||
"os"
|
||||
)
|
||||
|
||||
const (
|
||||
calldepth = 3
|
||||
)
|
||||
|
||||
// New creates standart logger.
|
||||
func New(opts ...Option) Logger {
|
||||
logger := logger{
|
||||
format: stringFormat,
|
||||
output: log.Output,
|
||||
calldepth: calldepth,
|
||||
}
|
||||
|
||||
for _, opt := range opts {
|
||||
opt(&logger)
|
||||
}
|
||||
|
||||
return func(ctx context.Context, level Level, msg string, fields Fields) {
|
||||
_ = logger.output(logger.calldepth, logger.format(msg, fields))
|
||||
|
||||
switch level {
|
||||
case LevelEmergency:
|
||||
panic(msg)
|
||||
case LevelAlert:
|
||||
os.Exit(1)
|
||||
default:
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Option configure log.
|
||||
type Option func(*logger)
|
||||
|
||||
// Format sets formats output message.
|
||||
type Format func(msg string, fields Fields) string
|
||||
|
||||
type logger struct {
|
||||
output func(calldepth int, s string) error
|
||||
format Format
|
||||
calldepth int
|
||||
}
|
||||
|
||||
// WithWriter sets writer logger.
|
||||
func WithWriter(writer io.Writer) Option {
|
||||
return func(l *logger) {
|
||||
l.output = log.New(writer, "", 0).Output
|
||||
}
|
||||
}
|
||||
|
||||
// WithStdout sets logged to os.Stdout.
|
||||
func WithStdout() Option {
|
||||
return func(l *logger) {
|
||||
l.output = log.New(os.Stdout, "", 0).Output
|
||||
}
|
||||
}
|
||||
|
||||
// WithFormat sets format log.
|
||||
func WithFormat(format Format) Option {
|
||||
return func(l *logger) {
|
||||
l.format = format
|
||||
}
|
||||
}
|
||||
|
||||
// WithStringFormat sets format as simple string.
|
||||
func WithStringFormat() Option {
|
||||
return func(l *logger) {
|
||||
l.format = stringFormat
|
||||
}
|
||||
}
|
||||
|
||||
// WithJSONFormat sets json output format.
|
||||
func WithJSONFormat() Option {
|
||||
return func(l *logger) {
|
||||
l.format = jsonFormat
|
||||
}
|
||||
}
|
||||
|
||||
// WithCalldepth sets depth filename.
|
||||
func WithCalldepth(calldepth int) Option {
|
||||
return func(l *logger) {
|
||||
l.calldepth = calldepth
|
||||
}
|
||||
}
|
||||
|
||||
// WithLogger sets logger anf format.
|
||||
func WithLogger(std *log.Logger, format Format) Option {
|
||||
return func(l *logger) {
|
||||
l.output = std.Output
|
||||
l.format = format
|
||||
}
|
||||
}
|
||||
|
||||
func stringFormat(msg string, fields Fields) string {
|
||||
return fmt.Sprint("msg=\"", msg, "\" ", fields)
|
||||
}
|
||||
|
||||
func jsonFormat(msg string, fields Fields) string {
|
||||
data := make(map[string]interface{}, len(fields)+1)
|
||||
data["msg"] = msg
|
||||
|
||||
for _, field := range fields {
|
||||
data[field.Key] = field.Value
|
||||
}
|
||||
|
||||
res, err := json.Marshal(data)
|
||||
if err != nil {
|
||||
return stringFormat(msg, append(fields, FieldError(err)))
|
||||
}
|
||||
|
||||
return string(res)
|
||||
}
|
||||
Reference in New Issue
Block a user