all: slog logger

This commit is contained in:
Dimitry Kolyshev 2024-07-05 11:05:14 +03:00
parent 9a74d5d98b
commit 3d7f734ac9
6 changed files with 102 additions and 33 deletions

View File

@ -1,6 +1,8 @@
package aghos package aghos
// ConfigureSyslog reroutes standard logger output to syslog. import "io"
func ConfigureSyslog(serviceName string) error {
// ConfigureSyslog returns an output rerouted to syslog.
func ConfigureSyslog(serviceName string) (w io.Writer, err error) {
return configureSyslog(serviceName) return configureSyslog(serviceName)
} }

View File

@ -3,16 +3,15 @@
package aghos package aghos
import ( import (
"io"
"log/syslog" "log/syslog"
"github.com/AdguardTeam/golibs/log"
) )
func configureSyslog(serviceName string) error { func configureSyslog(serviceName string) (w io.Writer, err error) {
w, err := syslog.New(syslog.LOG_NOTICE|syslog.LOG_USER, serviceName) w, err = syslog.New(syslog.LOG_NOTICE|syslog.LOG_USER, serviceName)
if err != nil { if err != nil {
return err return nil, err
} }
log.SetOutput(w)
return nil return w, nil
} }

View File

@ -3,9 +3,9 @@
package aghos package aghos
import ( import (
"io"
"strings" "strings"
"github.com/AdguardTeam/golibs/log"
"golang.org/x/sys/windows" "golang.org/x/sys/windows"
"golang.org/x/sys/windows/svc/eventlog" "golang.org/x/sys/windows/svc/eventlog"
) )
@ -19,23 +19,26 @@ func (w *eventLogWriter) Write(b []byte) (int, error) {
return len(b), w.el.Info(1, string(b)) return len(b), w.el.Info(1, string(b))
} }
func configureSyslog(serviceName string) error { func configureSyslog(serviceName string) (w io.Writer, err error) {
// Note that the eventlog src is the same as the service name // Note that the eventlog src is the same as the service name. Otherwise,
// Otherwise, we will get "the description for event id cannot be found" warning in every log record // we will get "the description for event id cannot be found" warning in
// every log record.
// Continue if we receive "registry key already exists" or if we get // Continue if we receive "registry key already exists" or if we get
// ERROR_ACCESS_DENIED so that we can log without administrative permissions // ERROR_ACCESS_DENIED so that we can log without administrative permissions
// for pre-existing eventlog sources. // for pre-existing eventlog sources.
if err := eventlog.InstallAsEventCreate(serviceName, eventlog.Info|eventlog.Warning|eventlog.Error); err != nil { err = eventlog.InstallAsEventCreate(serviceName, eventlog.Info|eventlog.Warning|eventlog.Error)
if !strings.Contains(err.Error(), "registry key already exists") && err != windows.ERROR_ACCESS_DENIED {
return err
}
}
el, err := eventlog.Open(serviceName)
if err != nil { if err != nil {
return err if !strings.Contains(err.Error(), "registry key already exists") &&
err != windows.ERROR_ACCESS_DENIED {
return nil, err
}
} }
log.SetOutput(&eventLogWriter{el: el}) el, err := eventlog.Open(serviceName)
return nil if err != nil {
return nil, err
}
return &eventLogWriter{el: el}, nil
} }

View File

@ -38,6 +38,7 @@ import (
"github.com/AdguardTeam/golibs/errors" "github.com/AdguardTeam/golibs/errors"
"github.com/AdguardTeam/golibs/hostsfile" "github.com/AdguardTeam/golibs/hostsfile"
"github.com/AdguardTeam/golibs/log" "github.com/AdguardTeam/golibs/log"
"github.com/AdguardTeam/golibs/logutil/slogutil"
"github.com/AdguardTeam/golibs/netutil" "github.com/AdguardTeam/golibs/netutil"
"github.com/AdguardTeam/golibs/osutil" "github.com/AdguardTeam/golibs/osutil"
) )
@ -547,15 +548,21 @@ func run(opts options, clientBuildFS fs.FS, done chan struct{}) {
// Configure config filename. // Configure config filename.
initConfigFilename(opts) initConfigFilename(opts)
ls := getLogSettings(opts)
// Configure log level and output. // Configure log level and output.
err = configureLogger(opts) err = configureLogger(ls)
fatalOnError(err)
// Configure slog logger.
l, err := initLogger(ls)
fatalOnError(err) fatalOnError(err)
// Print the first message after logger is configured. // Print the first message after logger is configured.
log.Info(version.Full()) l.Info(version.Full())
log.Debug("current working directory is %s", Context.workDir) l.Debug("current working directory is set", "work_dir", Context.workDir)
if opts.runningAsService { if opts.runningAsService {
log.Info("AdGuard Home is running as a service") l.Info("AdGuard Home is running as a service")
} }
err = setupContext(opts) err = setupContext(opts)
@ -586,7 +593,7 @@ func run(opts options, clientBuildFS fs.FS, done chan struct{}) {
} }
confPath := configFilePath() confPath := configFilePath()
log.Debug("using config path %q for updater", confPath) l.Debug("using config path for updater", "path", confPath)
upd := updater.NewUpdater(&updater.Config{ upd := updater.NewUpdater(&updater.Config{
Client: config.Filtering.HTTPClient, Client: config.Filtering.HTTPClient,
@ -628,7 +635,7 @@ func run(opts options, clientBuildFS fs.FS, done chan struct{}) {
Context.tls, err = newTLSManager(config.TLS, config.DNS.ServePlainDNS) Context.tls, err = newTLSManager(config.TLS, config.DNS.ServePlainDNS)
if err != nil { if err != nil {
log.Error("initializing tls: %s", err) l.Error("initializing tls", slogutil.KeyError, err)
onConfigModified() onConfigModified()
} }
@ -652,7 +659,7 @@ func run(opts options, clientBuildFS fs.FS, done chan struct{}) {
if Context.dhcpServer != nil { if Context.dhcpServer != nil {
err = Context.dhcpServer.Start() err = Context.dhcpServer.Start()
if err != nil { if err != nil {
log.Error("starting dhcp server: %s", err) l.Error("starting dhcp server", slogutil.KeyError, err)
} }
} }
} }

View File

@ -3,11 +3,14 @@ package home
import ( import (
"cmp" "cmp"
"fmt" "fmt"
"io"
"log/slog"
"path/filepath" "path/filepath"
"runtime" "runtime"
"github.com/AdguardTeam/AdGuardHome/internal/aghos" "github.com/AdguardTeam/AdGuardHome/internal/aghos"
"github.com/AdguardTeam/golibs/log" "github.com/AdguardTeam/golibs/log"
"github.com/AdguardTeam/golibs/logutil/slogutil"
"gopkg.in/natefinch/lumberjack.v2" "gopkg.in/natefinch/lumberjack.v2"
"gopkg.in/yaml.v3" "gopkg.in/yaml.v3"
) )
@ -16,10 +19,58 @@ import (
// for logger output. // for logger output.
const configSyslog = "syslog" const configSyslog = "syslog"
// configureLogger configures logger level and output. // initLogger returns new [*slog.Logger] configured with the given settings.
func configureLogger(opts options) (err error) { func initLogger(ls *logSettings) (l *slog.Logger, err error) {
ls := getLogSettings(opts) if !ls.Enabled {
return slogutil.NewDiscardLogger(), nil
}
w, err := logOutput(ls)
if err != nil {
return nil, fmt.Errorf("cannot initialize log output: %w", err)
}
return slogutil.New(&slogutil.Config{
Output: w,
Format: slogutil.FormatDefault,
AddTimestamp: true,
Verbose: ls.Verbose,
}), nil
}
// logOutput returns a log output [io.Writer] configured with the settings.
func logOutput(ls *logSettings) (w io.Writer, err error) {
if ls.File == "" {
return nil, nil
}
if ls.File == configSyslog {
// Use syslog where it is possible and eventlog on Windows.
w, err = aghos.ConfigureSyslog(serviceName)
if err != nil {
return nil, fmt.Errorf("cannot initialize syslog: %w", err)
}
return w, nil
}
logFilePath := ls.File
if !filepath.IsAbs(logFilePath) {
logFilePath = filepath.Join(Context.workDir, logFilePath)
}
return &lumberjack.Logger{
Filename: logFilePath,
Compress: ls.Compress,
LocalTime: ls.LocalTime,
MaxBackups: ls.MaxBackups,
MaxSize: ls.MaxSize,
MaxAge: ls.MaxAge,
}, nil
}
// configureLogger configures logger level and output.
func configureLogger(ls *logSettings) (err error) {
// Configure logger level. // Configure logger level.
if !ls.Enabled { if !ls.Enabled {
log.SetLevel(log.OFF) log.SetLevel(log.OFF)
@ -33,16 +84,19 @@ func configureLogger(opts options) (err error) {
// Write logs to stdout by default. // Write logs to stdout by default.
if ls.File == "" { if ls.File == "" {
return nil return err
} }
if ls.File == configSyslog { if ls.File == configSyslog {
// Use syslog where it is possible and eventlog on Windows. // Use syslog where it is possible and eventlog on Windows.
err = aghos.ConfigureSyslog(serviceName) var w io.Writer
w, err = aghos.ConfigureSyslog(serviceName)
if err != nil { if err != nil {
return fmt.Errorf("cannot initialize syslog: %w", err) return fmt.Errorf("cannot initialize syslog: %w", err)
} }
log.SetOutput(w)
return nil return nil
} }
@ -60,7 +114,7 @@ func configureLogger(opts options) (err error) {
MaxAge: ls.MaxAge, MaxAge: ls.MaxAge,
}) })
return nil return err
} }
// getLogSettings returns a log settings object properly initialized from opts. // getLogSettings returns a log settings object properly initialized from opts.

View File

@ -2,6 +2,7 @@ package cmd
import ( import (
"fmt" "fmt"
"io"
"os" "os"
"github.com/AdguardTeam/AdGuardHome/internal/aghos" "github.com/AdguardTeam/AdGuardHome/internal/aghos"
@ -22,10 +23,13 @@ func setLog(opts *options) (err error) {
case "stderr": case "stderr":
log.SetOutput(os.Stderr) log.SetOutput(os.Stderr)
case "syslog": case "syslog":
err = aghos.ConfigureSyslog(syslogServiceName) var w io.Writer
w, err = aghos.ConfigureSyslog(syslogServiceName)
if err != nil { if err != nil {
return fmt.Errorf("initializing syslog: %w", err) return fmt.Errorf("initializing syslog: %w", err)
} }
log.SetOutput(w)
default: default:
// TODO(a.garipov): Use the path. // TODO(a.garipov): Use the path.
} }