158 lines
3.9 KiB
Go
158 lines
3.9 KiB
Go
package main
|
|
|
|
import (
|
|
"context"
|
|
"encoding/csv"
|
|
"io"
|
|
"log/slog"
|
|
"os"
|
|
|
|
"github.com/joint-online-judge/JOJ3/cmd/joj3/conf"
|
|
"github.com/joint-online-judge/JOJ3/cmd/joj3/env"
|
|
)
|
|
|
|
var runningTest bool
|
|
|
|
type multiHandler struct {
|
|
handlers []slog.Handler
|
|
}
|
|
|
|
func (h *multiHandler) Enabled(ctx context.Context, level slog.Level) bool {
|
|
for _, handler := range h.handlers {
|
|
if handler.Enabled(ctx, level) {
|
|
return true
|
|
}
|
|
}
|
|
return false
|
|
}
|
|
|
|
func (h *multiHandler) Handle(ctx context.Context, r slog.Record) error {
|
|
for _, handler := range h.handlers {
|
|
if handler.Enabled(ctx, r.Level) {
|
|
if err := handler.Handle(ctx, r); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (h *multiHandler) WithAttrs(attrs []slog.Attr) slog.Handler {
|
|
handlers := make([]slog.Handler, len(h.handlers))
|
|
for i, handler := range h.handlers {
|
|
handlers[i] = handler.WithAttrs(attrs)
|
|
}
|
|
return &multiHandler{handlers: handlers}
|
|
}
|
|
|
|
func (h *multiHandler) WithGroup(name string) slog.Handler {
|
|
handlers := make([]slog.Handler, len(h.handlers))
|
|
for i, handler := range h.handlers {
|
|
handlers[i] = handler.WithGroup(name)
|
|
}
|
|
return &multiHandler{handlers: handlers}
|
|
}
|
|
|
|
func newSlogAttrs(csvPath string) (attrs []slog.Attr) {
|
|
attrs = []slog.Attr{
|
|
slog.String("runID", env.Attr.RunID),
|
|
slog.String("confName", env.Attr.ConfName),
|
|
slog.String("actor", env.Attr.Actor),
|
|
slog.String("actorName", env.Attr.ActorName),
|
|
slog.String("actorID", env.Attr.ActorID),
|
|
slog.String("repository", env.Attr.Repository),
|
|
slog.String("sha", env.Attr.Sha),
|
|
slog.String("ref", env.Attr.Ref),
|
|
}
|
|
// if csvPath is empty, just return
|
|
if csvPath == "" {
|
|
return attrs
|
|
}
|
|
file, err := os.Open(csvPath)
|
|
if err != nil {
|
|
slog.Error("open csv", "error", err)
|
|
return attrs
|
|
}
|
|
defer file.Close()
|
|
reader := csv.NewReader(file)
|
|
for {
|
|
row, err := reader.Read()
|
|
if err == io.EOF {
|
|
break
|
|
}
|
|
if err != nil {
|
|
slog.Error("read csv", "error", err)
|
|
return attrs
|
|
}
|
|
if len(row) < 3 {
|
|
continue
|
|
}
|
|
actor := row[2]
|
|
if actor == env.Attr.Actor {
|
|
env.Attr.ActorName = row[0]
|
|
env.Attr.ActorID = row[1]
|
|
return []slog.Attr{
|
|
slog.String("runID", env.Attr.RunID),
|
|
slog.String("confName", env.Attr.ConfName),
|
|
slog.String("actor", env.Attr.Actor),
|
|
slog.String("actorName", env.Attr.ActorName),
|
|
slog.String("actorID", env.Attr.ActorID),
|
|
slog.String("repository", env.Attr.Repository),
|
|
slog.String("sha", env.Attr.Sha),
|
|
slog.String("ref", env.Attr.Ref),
|
|
}
|
|
}
|
|
}
|
|
return attrs
|
|
}
|
|
|
|
func setupSlog(conf *conf.Conf) error {
|
|
logPath := conf.LogPath
|
|
attrs := newSlogAttrs(conf.ActorCsvPath)
|
|
handlers := []slog.Handler{}
|
|
if logPath != "" {
|
|
// Text file handler for debug logs
|
|
debugTextFile, err := os.OpenFile(logPath,
|
|
os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0o640)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
debugTextHandler := slog.NewTextHandler(debugTextFile,
|
|
&slog.HandlerOptions{Level: slog.LevelDebug})
|
|
handlers = append(handlers, debugTextHandler.WithAttrs(attrs))
|
|
// Json file handler for debug logs
|
|
debugJSONFile, err := os.OpenFile(logPath+".ndjson",
|
|
os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0o640)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
debugJSONHandler := slog.NewJSONHandler(debugJSONFile,
|
|
&slog.HandlerOptions{Level: slog.LevelDebug})
|
|
handlers = append(handlers, debugJSONHandler.WithAttrs(attrs))
|
|
}
|
|
stderrLogLevel := slog.LevelInfo
|
|
if runningTest {
|
|
stderrLogLevel = slog.LevelDebug
|
|
}
|
|
// Stderr handler for info logs and above
|
|
stderrHandler := slog.NewTextHandler(os.Stderr, &slog.HandlerOptions{
|
|
Level: stderrLogLevel,
|
|
})
|
|
handlers = append(handlers, stderrHandler)
|
|
// Create a multi-handler
|
|
multiHandler := &multiHandler{handlers: handlers}
|
|
// Set the default logger
|
|
logger := slog.New(multiHandler)
|
|
slog.SetDefault(logger)
|
|
if logPath != "" {
|
|
slog.Info("debug log", "path", logPath)
|
|
}
|
|
slog.LogAttrs(
|
|
context.Background(),
|
|
slog.LevelInfo,
|
|
"setup slog attrs",
|
|
attrs...,
|
|
)
|
|
return nil
|
|
}
|