skeleton added
This commit is contained in:
136
pkg/logger/logger.go
Executable file
136
pkg/logger/logger.go
Executable file
@@ -0,0 +1,136 @@
|
||||
package logger
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"io"
|
||||
"log"
|
||||
"log/slog"
|
||||
"os"
|
||||
"runtime"
|
||||
"strconv"
|
||||
"tgVideoCall/pkg/config"
|
||||
|
||||
"go.uber.org/zap"
|
||||
"go.uber.org/zap/zapcore"
|
||||
)
|
||||
|
||||
const (
|
||||
envLocal = "local"
|
||||
envDev = "dev"
|
||||
envProd = "prod"
|
||||
)
|
||||
|
||||
func MustInitLogger(cfg config.Config) slog.Logger {
|
||||
var logFile *os.File
|
||||
var err error
|
||||
|
||||
if cfg.Log.FilePath != "" { //Если строка в конфиге пустая, это будет означать что нам не нужно сохранение логов в файл
|
||||
logFile, err = os.OpenFile(cfg.Log.FilePath, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644)
|
||||
if err != nil {
|
||||
log.Fatal("error opening file:", err)
|
||||
}
|
||||
}
|
||||
|
||||
var log *slog.Logger
|
||||
|
||||
switch cfg.Env {
|
||||
case envLocal:
|
||||
if cfg.Log.FilePath == "" {
|
||||
log = slog.New(slog.NewTextHandler(os.Stdout, &slog.HandlerOptions{Level: slog.LevelDebug}))
|
||||
return *log
|
||||
}
|
||||
log = slog.New(slog.NewTextHandler(io.MultiWriter(os.Stdout, logFile), &slog.HandlerOptions{Level: slog.LevelDebug}))
|
||||
case envProd:
|
||||
if cfg.Log.FilePath == "" {
|
||||
log = slog.New(slog.NewTextHandler(os.Stdout, &slog.HandlerOptions{Level: slog.LevelInfo}))
|
||||
return *log
|
||||
}
|
||||
log = slog.New(slog.NewJSONHandler(io.MultiWriter(os.Stdout, logFile), &slog.HandlerOptions{Level: slog.LevelInfo}))
|
||||
}
|
||||
if cfg.Log.FilePath != "" {
|
||||
log.Info(fmt.Sprintf("Logs are saving to: %s", cfg.Log.FilePath))
|
||||
}
|
||||
|
||||
return *log
|
||||
}
|
||||
|
||||
// ZapSlogHandler реализует slog.Handler для zap.Logger
|
||||
type ZapSlogHandler struct {
|
||||
zapLogger *zap.Logger
|
||||
}
|
||||
|
||||
func NewZapSlogHandler(zapLogger *zap.Logger) *ZapSlogHandler {
|
||||
return &ZapSlogHandler{zapLogger: zapLogger}
|
||||
}
|
||||
|
||||
func (h *ZapSlogHandler) Enabled(ctx context.Context, level slog.Level) bool {
|
||||
// Преобразуем slog.Level в zapcore.Level
|
||||
var zapLevel zapcore.Level
|
||||
switch {
|
||||
case level < slog.LevelDebug:
|
||||
zapLevel = zapcore.DebugLevel
|
||||
case level < slog.LevelInfo:
|
||||
zapLevel = zapcore.InfoLevel
|
||||
case level < slog.LevelWarn:
|
||||
zapLevel = zapcore.WarnLevel
|
||||
case level < slog.LevelError:
|
||||
zapLevel = zapcore.ErrorLevel
|
||||
default:
|
||||
zapLevel = zapcore.DPanicLevel
|
||||
}
|
||||
return h.zapLogger.Core().Enabled(zapLevel)
|
||||
}
|
||||
|
||||
func (h *ZapSlogHandler) Handle(ctx context.Context, r slog.Record) error {
|
||||
// Преобразуем slog.Record в поля zap
|
||||
fields := make([]zap.Field, 0, r.NumAttrs()+1)
|
||||
fields = append(fields, zap.String("message", r.Message))
|
||||
|
||||
// Добавляем атрибуты
|
||||
r.Attrs(func(attr slog.Attr) bool {
|
||||
fields = append(fields, zap.Any(attr.Key, attr.Value.Any()))
|
||||
return true
|
||||
})
|
||||
|
||||
// Добавляем источник (source), если есть
|
||||
if r.PC != 0 {
|
||||
fs := runtime.CallersFrames([]uintptr{r.PC})
|
||||
f, _ := fs.Next()
|
||||
fields = append(fields, zap.String("source", f.File+":"+strconv.FormatUint(uint64(r.PC), 10)))
|
||||
}
|
||||
|
||||
// Логируем с соответствующим уровнем
|
||||
switch r.Level {
|
||||
case slog.LevelDebug:
|
||||
h.zapLogger.Debug(r.Message, fields...)
|
||||
case slog.LevelInfo:
|
||||
h.zapLogger.Info(r.Message, fields...)
|
||||
case slog.LevelWarn:
|
||||
h.zapLogger.Warn(r.Message, fields...)
|
||||
case slog.LevelError:
|
||||
h.zapLogger.Error(r.Message, fields...)
|
||||
default:
|
||||
h.zapLogger.DPanic(r.Message, fields...)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (h *ZapSlogHandler) WithAttrs(attrs []slog.Attr) slog.Handler {
|
||||
fields := make([]zap.Field, len(attrs))
|
||||
for i, attr := range attrs {
|
||||
fields[i] = zap.Any(attr.Key, attr.Value.Any())
|
||||
}
|
||||
return &ZapSlogHandler{zapLogger: h.zapLogger.With(fields...)}
|
||||
}
|
||||
|
||||
func (h *ZapSlogHandler) WithGroup(name string) slog.Handler {
|
||||
// Для простоты игнорируем группы, но в production нужно реализовать
|
||||
return h
|
||||
}
|
||||
|
||||
// WrapZapToSlog оборачивает zap.Logger в slog.Logger
|
||||
func WrapZapToSlog(zapLogger *zap.Logger) *slog.Logger {
|
||||
return slog.New(NewZapSlogHandler(zapLogger))
|
||||
}
|
||||
Reference in New Issue
Block a user