Вынес логер в отдельный пакет
This commit is contained in:
parent
7d08058df6
commit
99a53ac87c
26
conf.go
Normal file
26
conf.go
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
package logger
|
||||||
|
|
||||||
|
import (
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Configuration struct {
|
||||||
|
Stdout struct {
|
||||||
|
Level string `yaml:"level"`
|
||||||
|
} `yaml:"console"`
|
||||||
|
File struct {
|
||||||
|
Enabled bool `yaml:"enabled"`
|
||||||
|
Level string `yaml:"level"`
|
||||||
|
Filename string `yaml:"filename"`
|
||||||
|
MaxSize int `yaml:"maxsize"`
|
||||||
|
MaxAge int `yaml:"maxage"`
|
||||||
|
MaxBackups int `yaml:"maxbackups"`
|
||||||
|
LocalTime bool `yaml:"localtime"`
|
||||||
|
Compress bool `yaml:"compress"`
|
||||||
|
}
|
||||||
|
Sentry struct {
|
||||||
|
Level string `yaml:"level"`
|
||||||
|
DSN string `yaml:"dsn"`
|
||||||
|
Timeout time.Duration `yaml:"timeout"`
|
||||||
|
} `yaml:"sentry"`
|
||||||
|
}
|
24
conf_test.go
Normal file
24
conf_test.go
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
package logger
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func Test_buildErrorsFilename(t *testing.T) {
|
||||||
|
testCases := []struct {
|
||||||
|
logFileName string
|
||||||
|
expectedFileName string
|
||||||
|
}{
|
||||||
|
{"logs/logs.log", "logs/logs-errors.log"},
|
||||||
|
{"logs/advisor.log", "logs/advisor-errors.log"},
|
||||||
|
{"logs/country.log", "logs/country-errors.log"},
|
||||||
|
{"logs/country.old.log", "logs/country.old-errors.log"},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, test := range testCases {
|
||||||
|
t.Run(test.logFileName, func(t *testing.T) {
|
||||||
|
assert.Equal(t, test.expectedFileName, buildErrorsFilename(test.logFileName), "result")
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
20
go.mod
Normal file
20
go.mod
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
module go-logger
|
||||||
|
|
||||||
|
go 1.23
|
||||||
|
|
||||||
|
require (
|
||||||
|
github.com/tchap/zapext v1.0.0
|
||||||
|
go.uber.org/zap v1.27.0
|
||||||
|
)
|
||||||
|
|
||||||
|
require (
|
||||||
|
github.com/certifi/gocertifi v0.0.0-20210507211836-431795d63e8d // indirect
|
||||||
|
github.com/davecgh/go-spew v1.1.1 // indirect
|
||||||
|
github.com/getsentry/raven-go v0.2.0 // indirect
|
||||||
|
github.com/pkg/errors v0.9.1 // indirect
|
||||||
|
github.com/pmezard/go-difflib v1.0.0 // indirect
|
||||||
|
github.com/stretchr/testify v1.9.0 // indirect
|
||||||
|
go.uber.org/multierr v1.10.0 // indirect
|
||||||
|
gopkg.in/natefinch/lumberjack.v2 v2.2.1 // indirect
|
||||||
|
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||||
|
)
|
23
go.sum
Normal file
23
go.sum
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
github.com/certifi/gocertifi v0.0.0-20210507211836-431795d63e8d h1:S2NE3iHSwP0XV47EEXL8mWmRdEfGscSJ+7EgePNgt0s=
|
||||||
|
github.com/certifi/gocertifi v0.0.0-20210507211836-431795d63e8d/go.mod h1:sGbDF6GwGcLpkNXPUTkMRoywsNa/ol15pxFe6ERfguA=
|
||||||
|
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||||
|
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
|
github.com/getsentry/raven-go v0.2.0 h1:no+xWJRb5ZI7eE8TWgIq1jLulQiIoLG0IfYxv5JYMGs=
|
||||||
|
github.com/getsentry/raven-go v0.2.0/go.mod h1:KungGk8q33+aIAZUIVWZDr2OfAEBsO49PX4NzFV5kcQ=
|
||||||
|
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
||||||
|
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||||
|
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||||
|
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||||
|
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
|
||||||
|
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
|
||||||
|
github.com/tchap/zapext v1.0.0 h1:qPxfRLzqYzemT+Pgs5VoH8NGU5YS7cgCnhcqRGkmrXc=
|
||||||
|
github.com/tchap/zapext v1.0.0/go.mod h1:0VgDSQ0xHJRqkxrwu3G2i2762jSnAJMz7rYxiZGpW1U=
|
||||||
|
go.uber.org/multierr v1.10.0 h1:S0h4aNzvfcFsC3dRF1jLoaov7oRaKqRGC/pUEJ2yvPQ=
|
||||||
|
go.uber.org/multierr v1.10.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y=
|
||||||
|
go.uber.org/zap v1.27.0 h1:aJMhYGrd5QSmlpLMr2MftRKl7t8J8PTZPA732ud/XR8=
|
||||||
|
go.uber.org/zap v1.27.0/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E=
|
||||||
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
|
gopkg.in/natefinch/lumberjack.v2 v2.2.1 h1:bBRl1b0OH9s/DuPhuXpNl+VtCaJXFZ5/uEFST95x9zc=
|
||||||
|
gopkg.in/natefinch/lumberjack.v2 v2.2.1/go.mod h1:YD8tP3GAjkrDg1eZH7EGmyESg/lsYskCTPBJVb9jqSc=
|
||||||
|
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||||
|
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
141
logger.go
Normal file
141
logger.go
Normal file
@ -0,0 +1,141 @@
|
|||||||
|
package logger
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"log"
|
||||||
|
"os"
|
||||||
|
"path"
|
||||||
|
"path/filepath"
|
||||||
|
"runtime"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/getsentry/raven-go"
|
||||||
|
"github.com/tchap/zapext/zapsentry"
|
||||||
|
"go.uber.org/zap"
|
||||||
|
"go.uber.org/zap/zapcore"
|
||||||
|
"gopkg.in/natefinch/lumberjack.v2"
|
||||||
|
)
|
||||||
|
|
||||||
|
var zapLogger *zap.Logger
|
||||||
|
|
||||||
|
func Named(name string) *zap.Logger {
|
||||||
|
return zapLogger.Named(name)
|
||||||
|
}
|
||||||
|
|
||||||
|
func With(fields ...zap.Field) *zap.Logger {
|
||||||
|
return zapLogger.With(fields...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func LogPanic(msg string) {
|
||||||
|
if r := recover(); r != nil {
|
||||||
|
buf := make([]byte, 10240)
|
||||||
|
n := runtime.Stack(buf, false)
|
||||||
|
err := fmt.Sprintf("%v\n\n%s", r, buf[:n])
|
||||||
|
Error(msg, zap.String("error", err))
|
||||||
|
time.Sleep(5 * time.Second) // wait to write logs and sent to sentry
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func Fatal(msg string, fields ...zap.Field) {
|
||||||
|
zapLogger.Fatal(msg, fields...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func Error(msg string, fields ...zap.Field) {
|
||||||
|
zapLogger.Error(msg, fields...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func Warn(msg string, fields ...zap.Field) {
|
||||||
|
zapLogger.Warn(msg, fields...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func Info(msg string, fields ...zap.Field) {
|
||||||
|
zapLogger.Info(msg, fields...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func Debug(msg string, fields ...zap.Field) {
|
||||||
|
zapLogger.Debug(msg, fields...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func Sync() error {
|
||||||
|
return zapLogger.Sync()
|
||||||
|
}
|
||||||
|
|
||||||
|
func buildErrorsFilename(logFileName string) string {
|
||||||
|
ext := path.Ext(logFileName)
|
||||||
|
errFileName := strings.TrimSuffix(path.Base(logFileName), ext)
|
||||||
|
errFileName += "-errors" + ext
|
||||||
|
return filepath.Join(path.Dir(logFileName), errFileName)
|
||||||
|
}
|
||||||
|
|
||||||
|
func Init(conf *Configuration) {
|
||||||
|
cfg := zap.NewProductionEncoderConfig()
|
||||||
|
cfg.EncodeTime = zapcore.RFC3339NanoTimeEncoder
|
||||||
|
|
||||||
|
cores := []zapcore.Core{
|
||||||
|
zapcore.NewCore(zapcore.NewJSONEncoder(cfg), zapcore.Lock(os.Stdout), loggingLevelGTE(conf.Stdout.Level)),
|
||||||
|
}
|
||||||
|
|
||||||
|
// file logger
|
||||||
|
if conf.File.Enabled {
|
||||||
|
loggerConf := conf.File
|
||||||
|
fileLevelEnabler := loggingLevelGTE(loggerConf.Level)
|
||||||
|
writer := zapcore.AddSync(
|
||||||
|
&lumberjack.Logger{
|
||||||
|
Filename: loggerConf.Filename,
|
||||||
|
LocalTime: loggerConf.LocalTime,
|
||||||
|
MaxSize: loggerConf.MaxSize,
|
||||||
|
MaxBackups: loggerConf.MaxBackups,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
cores = append(cores, zapcore.NewCore(zapcore.NewJSONEncoder(cfg), writer, fileLevelEnabler))
|
||||||
|
|
||||||
|
redirectStderrToFile(conf)
|
||||||
|
}
|
||||||
|
|
||||||
|
// sentry
|
||||||
|
if conf.Sentry.DSN != "" {
|
||||||
|
loggerConf := conf.Sentry
|
||||||
|
tags := map[string]string{
|
||||||
|
"env": os.Getenv("ENVIRONMENT"),
|
||||||
|
}
|
||||||
|
client, err := raven.NewWithTags(loggerConf.DSN, tags)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal("failed to get a Sentry client", err)
|
||||||
|
}
|
||||||
|
sentryLevelEnabler := loggingLevelGTE(loggerConf.Level)
|
||||||
|
cores = append(cores, zapsentry.NewCore(sentryLevelEnabler, client))
|
||||||
|
}
|
||||||
|
|
||||||
|
core := zapcore.NewTee(cores...)
|
||||||
|
|
||||||
|
logger := zap.New(core)
|
||||||
|
defer func() {
|
||||||
|
_ = logger.Sync()
|
||||||
|
}()
|
||||||
|
SetLogger(logger)
|
||||||
|
}
|
||||||
|
|
||||||
|
type levelComparator func(msgLevel zapcore.Level, loggingLevel zapcore.Level) bool
|
||||||
|
|
||||||
|
func loggingLevelGTE(level string) zap.LevelEnablerFunc {
|
||||||
|
return loggingLevelEnabledFunc(
|
||||||
|
level, func(msgLevel zapcore.Level, loggingLevel zapcore.Level) bool {
|
||||||
|
return msgLevel >= loggingLevel
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
func loggingLevelEnabledFunc(level string, comparator levelComparator) zap.LevelEnablerFunc {
|
||||||
|
var loggingLevel zapcore.Level
|
||||||
|
if err := loggingLevel.UnmarshalText([]byte(level)); err != nil {
|
||||||
|
log.Fatal("Fail parse console log level", err)
|
||||||
|
}
|
||||||
|
return func(msgLevel zapcore.Level) bool {
|
||||||
|
return comparator(msgLevel, loggingLevel)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func SetLogger(logger *zap.Logger) {
|
||||||
|
zapLogger = logger
|
||||||
|
}
|
20
stderrtofile.go
Normal file
20
stderrtofile.go
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
//go:build !windows
|
||||||
|
|
||||||
|
package logger
|
||||||
|
|
||||||
|
import (
|
||||||
|
"log"
|
||||||
|
"os"
|
||||||
|
"syscall"
|
||||||
|
)
|
||||||
|
|
||||||
|
func redirectStderrToFile(conf *Configuration) {
|
||||||
|
fileName := buildErrorsFilename(conf.File.Filename)
|
||||||
|
f, err := os.OpenFile(fileName, os.O_RDWR|os.O_CREATE|os.O_APPEND, 0666)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("open %s: %s", fileName, err)
|
||||||
|
}
|
||||||
|
if err = syscall.Dup2(int(f.Fd()), int(os.Stderr.Fd())); err != nil {
|
||||||
|
log.Fatalf("Failed to redirect stderr to file: %s", err)
|
||||||
|
}
|
||||||
|
}
|
6
stderrtofile_windows.go
Normal file
6
stderrtofile_windows.go
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
//go:build windows
|
||||||
|
|
||||||
|
package logger
|
||||||
|
|
||||||
|
func redirectStderrToFile(conf *Configuration) {
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user