0

[WIP] Replace logrus with slog

This commit is contained in:
eleksir
2025-10-31 18:49:25 +03:00
parent a21d7216ab
commit 985bb7d5d3
7 changed files with 206 additions and 42 deletions

View File

@@ -5,8 +5,9 @@ import (
"fmt"
"os"
"aleesa-telegram-go/internal/log"
"github.com/hjson/hjson-go"
log "github.com/sirupsen/logrus"
)
// parseConfig разбирает и валидирует даденный конфиг.

176
internal/log/log.go Normal file
View File

@@ -0,0 +1,176 @@
package log
import (
"bufio"
"context"
"errors"
"fmt"
"io"
"log/slog"
"os"
"time"
)
// Handler exposes slog handler struct.
var Handler slog.Handler
// Ctx log context. For now it is just sits here and do nothing.
var Ctx = context.Background()
// Writer go-writer eported for capturing other types of logs, even for std log go facility.
var Writer io.Writer
// reader is required for Writer to work properly. It is connected via io.Pipe() to Writer.
var reader io.Reader
// Init setup logger stuff.
// level can be error, warn, info, debug if something other supplied info level selected.
// fileDescriptor should be opened before supplying it to Init().
func Init(level string, fileDescriptor *os.File) {
var loglevel slog.Level
// no panic, no trace.
switch level {
case "debug":
loglevel = slog.LevelDebug
case "info":
loglevel = slog.LevelInfo
case "warn":
loglevel = slog.LevelWarn
case "error":
loglevel = slog.LevelError
default:
loglevel = slog.LevelInfo
}
opts := &slog.HandlerOptions{ //nolint: exhaustruct
// Use the ReplaceAttr function on the handler options
// to be able to replace any single attribute in the log output
ReplaceAttr: func(groups []string, a slog.Attr) slog.Attr { //nolint: revive
// check that we are handling the time key
if a.Key != slog.TimeKey {
return a
}
t := a.Value.Time()
// change the value from a time.Time to a String
// where the string has the correct time format.
a.Value = slog.StringValue(t.Format(time.DateTime))
return a
},
Level: loglevel,
}
Handler = slog.NewTextHandler(fileDescriptor, opts)
slog.SetDefault(
slog.New(Handler),
)
reader, Writer = io.Pipe()
go readIoPipe()
}
// readIoPipe reads pipe and writes it to slog.
func readIoPipe() {
scanner := bufio.NewScanner(reader)
for {
for scanner.Scan() {
line := scanner.Text() // Get the current line as a string
slog.Debug(line)
}
if err := scanner.Err(); err != nil {
// io.EOF is expected when done reading, e.g. on exit.
if errors.Is(err, io.EOF) {
return
}
// something weird happen, we should it log to guess later what it was.
Errorf("Error during scanning log writer pipe: %v\n", err)
}
}
}
// GetLevel returns current loglevel.
func GetLevel() string {
switch {
case Handler.Enabled(Ctx, slog.LevelDebug):
return "debug"
case Handler.Enabled(Ctx, slog.LevelInfo):
return "info"
case Handler.Enabled(Ctx, slog.LevelWarn):
return "warn"
case Handler.Enabled(Ctx, slog.LevelError):
return "error"
default:
return "unknown"
}
}
// Fatal passes message directly to slog.Error() and exits with error code 1.
func Fatal(message string) {
slog.Error(message)
os.Exit(1)
}
// Fatalf logs message on error log level and exits with error code 1. It allows to supply arguments in printf() style .
func Fatalf(format string, a ...any) {
slog.Error(fmt.Sprintf(format, a...))
os.Exit(1)
}
// Error passes message directly to slog.Error().
func Error(message string) {
slog.Error(message)
}
// Errorf logs message on error log level and allows to supply arguments in printf() style.
func Errorf(format string, a ...any) {
slog.Error(fmt.Sprintf(format, a...))
}
// Warn passes message directly to slog.Warn().
func Warn(message string) {
slog.Warn(message)
}
// Warnf logs message on warn log level and allows to supply arguments in printf() style.
func Warnf(format string, a ...any) {
slog.Warn(fmt.Sprintf(format, a...))
}
// Info passes message directly to slog.Info().
func Info(message string) {
slog.Info(message)
}
// Infof logs message on info log level and allows to supply arguments in printf() style.
func Infof(format string, a ...any) {
slog.Info(fmt.Sprintf(format, a...))
}
// Debug passes message directly to slog.Debug().
func Debug(message string) {
slog.Debug(message)
}
// Debugf logs message on debug log level and allows to supply arguments in printf() style.
func Debugf(format string, a ...any) {
slog.Debug(fmt.Sprintf(format, a...))
}
/* vim: set ft=go noet ai ts=4 sw=4 sts=4: */

52
main.go
View File

@@ -8,43 +8,21 @@ import (
"path/filepath"
"syscall"
"aleesa-telegram-go/internal/log"
"github.com/go-redis/redis/v8"
log "github.com/sirupsen/logrus"
)
// init производит некоторую инициализацию перед запуском main().
func init() {
log.SetFormatter(&log.TextFormatter{
DisableQuote: true,
DisableLevelTruncation: false,
DisableColors: true,
FullTimestamp: true,
TimestampFormat: "2006-01-02 15:04:05",
})
// no panic, no trace
switch config.Loglevel {
case "fatal":
log.SetLevel(log.FatalLevel)
case "error":
log.SetLevel(log.ErrorLevel)
case "warn":
log.SetLevel(log.WarnLevel)
case "info":
log.SetLevel(log.InfoLevel)
case "debug":
log.SetLevel(log.DebugLevel)
default:
log.SetLevel(log.InfoLevel)
}
var err error
var (
err error
)
executablePath, err := os.Executable()
if err != nil {
log.Errorf("Unable to get current executable path: %s", err)
os.Exit(1)
log.Fatalf("Unable to get current executable path: %s", err)
}
configJSONPath := fmt.Sprintf("%s/data/config.json", filepath.Dir(executablePath))
@@ -72,20 +50,26 @@ func init() {
}
func main() {
// Main context
var ctx = context.Background()
var (
logfile *os.File
err error
)
// Откроем лог и скормим его логгеру.
if config.Log != "" {
logfile, err := os.OpenFile(config.Log, os.O_WRONLY|os.O_APPEND|os.O_CREATE, 0644)
logfile, err = os.OpenFile(config.Log, os.O_WRONLY|os.O_APPEND|os.O_CREATE, 0644)
if err != nil {
log.Fatalf("Unable to open log file %s: %s", config.Log, err)
log.Errorf("Unable to open log file %s: %s", config.Log, err)
os.Exit(1)
}
log.SetOutput(logfile)
}
log.Init(config.Loglevel, logfile)
// Main context
var ctx = context.Background()
// Инициализируем redis-клиента.
redisClient = redis.NewClient(&redis.Options{
Addr: fmt.Sprintf("%s:%d", config.Redis.Server, config.Redis.Port),

View File

@@ -8,9 +8,10 @@ import (
"strconv"
"strings"
"aleesa-telegram-go/internal/log"
"github.com/NicoNex/echotron/v3"
"github.com/davecgh/go-spew/spew"
log "github.com/sirupsen/logrus"
)
// telego msg parser

View File

@@ -6,9 +6,10 @@ import (
"fmt"
"io/fs"
"aleesa-telegram-go/internal/log"
"github.com/cockroachdb/errors/oserror"
"github.com/cockroachdb/pebble"
log "github.com/sirupsen/logrus"
)
// StoreKV сохраняет в указанной бд ключ и значение.

View File

@@ -3,8 +3,9 @@ package main
import (
"fmt"
"aleesa-telegram-go/internal/log"
"github.com/NicoNex/echotron/v3"
log "github.com/sirupsen/logrus"
)
// telega основная горутинка, реализующая бота.

View File

@@ -4,7 +4,7 @@ import (
"os"
"syscall"
log "github.com/sirupsen/logrus"
"aleesa-telegram-go/internal/log"
)
// sigHandler хэндлер сигналов закрывает все бд, все сетевые соединения и сваливает из приложения.
@@ -15,11 +15,11 @@ func sigHandler() {
var s = <-sigChan
switch s {
case syscall.SIGINT:
log.Infoln("Got SIGINT, quitting")
log.Info("Got SIGINT, quitting")
case syscall.SIGTERM:
log.Infoln("Got SIGTERM, quitting")
log.Info("Got SIGTERM, quitting")
case syscall.SIGQUIT:
log.Infoln("Got SIGQUIT, quitting")
log.Info("Got SIGQUIT, quitting")
// Заходим на новую итерацию, если у нас "неинтересный" сигнал.
default: