Bluemage/go/pkg/log/log.go

117 lines
3.1 KiB
Go

package log
import (
"errors"
"log/slog"
"net/http"
"os"
"strings"
"github.com/mattn/go-colorable"
"github.com/mattn/go-isatty"
slogmulti "github.com/samber/slog-multi"
"github.com/tigorlazuardi/bluemage/go/config"
"github.com/tigorlazuardi/bluemage/go/pkg/telemetry"
"gopkg.in/natefinch/lumberjack.v2"
)
func NewHandler(cfg *config.Config) (slog.Handler, func() error) {
var handlers []slog.Handler
cleanup := func() error { return nil }
if cfg.Bool("log.enable") {
log, sync := createStandardLogger(cfg)
cleanup = sync
handlers = append(handlers, log)
}
if cfg.Bool("log.file.enable") {
log, clean := createFileLogger(cfg)
cl := cleanup
cleanup = func() error {
return errors.Join(cl(), clean())
}
handlers = append(handlers, log)
}
if cfg.Bool("telemetry.openobserve.enable") && cfg.Bool("telemetry.openobserve.log.enable") {
log, clean := createO2Logger(cfg)
cl := cleanup
handlers = append(handlers, log)
cleanup = func() error {
err := cl()
clean()
return err
}
}
if len(handlers) == 0 {
return NullHandler{}, cleanup
}
return slogmulti.Fanout(handlers...), cleanup
}
func createFileLogger(cfg *config.Config) (slog.Handler, func() error) {
output := &lumberjack.Logger{
Filename: cfg.String("log.file.path"),
MaxSize: 15,
MaxAge: 30,
MaxBackups: 10,
LocalTime: true,
}
var lvl slog.Level
_ = lvl.UnmarshalText(cfg.Bytes("log.level"))
opts := &slog.HandlerOptions{
AddSource: cfg.Bool("log.source"),
Level: lvl,
}
return slog.NewJSONHandler(Lock(AddSync(output)), opts), output.Close
}
func createStandardLogger(cfg *config.Config) (slog.Handler, func() error) {
var output WriteSyncer
var cleanup func() error
if strings.ToLower(cfg.String("log.output")) == "stdout" {
output = Lock(AddSync(colorable.NewColorableStdout()))
cleanup = output.Sync
} else {
output = Lock(AddSync(colorable.NewColorableStderr()))
cleanup = output.Sync
}
var lvl slog.Level
_ = lvl.UnmarshalText(cfg.Bytes("log.level"))
opts := &slog.HandlerOptions{
AddSource: cfg.Bool("log.source"),
Level: lvl,
}
if isatty.IsTerminal(os.Stdout.Fd()) {
return NewPrettyHandler(output, opts), cleanup
} else {
return slog.NewJSONHandler(output, opts), cleanup
}
}
func createO2Logger(cfg *config.Config) (slog.Handler, func()) {
var lvl slog.Level
_ = lvl.UnmarshalText(cfg.Bytes("telemetry.openobserve.log.level"))
opts := &slog.HandlerOptions{
AddSource: cfg.Bool("telemetry.openobserve.log.source"),
Level: lvl,
}
handler := telemetry.NewOpenObserveHandler(telemetry.OpenObserveHandlerOptions{
HandlerOptions: opts,
BufferSize: cfg.Int("telemetry.openobserve.log.buffer.size"),
BufferTimeout: cfg.Duration("telemetry.openobserve.log.buffer.timeout"),
Concurrency: cfg.Int("telemetry.openobserve.log.concurrency"),
Endpoint: cfg.String("telemetry.openobserve.log.endpoint"),
HTTPClient: http.DefaultClient,
Username: cfg.String("telemetry.openobserve.log.username"),
Password: cfg.String("telemetry.openobserve.log.password"),
})
return handler, handler.Flush
}