You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
141 lines
3.3 KiB
141 lines
3.3 KiB
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
|
|
}
|
|
|