andrey1s
3 years ago
commit
f9ae79614a
16 changed files with 1018 additions and 0 deletions
@ -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: {} |
@ -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/ |
||||
|
|
@ -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 |
@ -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. |
@ -0,0 +1,5 @@ |
|||||
|
# log |
||||
|
|
||||
|
[![Build Status](https://drone.gitoa.ru/api/badges/go-4devs/log/status.svg)](https://drone.gitoa.ru/go-4devs/log) |
||||
|
[![Go Report Card](https://goreportcard.com/badge/gitoa.ru/go-4devs/log)](https://goreportcard.com/report/gitoa.ru/go-4devs/log) |
||||
|
[![GoDoc](https://godoc.org/gitoa.ru/go-4devs/log?status.svg)](http://godoc.org/gitoa.ru/go-4devs/log) |
@ -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 |
@ -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) |
||||
|
} |
@ -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...) |
||||
|
} |
@ -0,0 +1,3 @@ |
|||||
|
module gitoa.ru/go-4devs/log |
||||
|
|
||||
|
go 1.14 |
@ -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 |
||||
|
} |
@ -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]] |
||||
|
} |
@ -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...) |
||||
|
} |
@ -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
|
||||
|
} |
@ -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) |
||||
|
} |
||||
|
} |
@ -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) |
||||
|
} |
||||
|
} |
@ -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) |
||||
|
} |
Loading…
Reference in new issue