diff --git a/README.md b/README.md index cc6862f7..e258a863 100644 --- a/README.md +++ b/README.md @@ -225,3 +225,21 @@ alpamon.service - alpamon agent for Alpacon Loaded: loaded (/lib/systemd/system/alpamon.service; enabled; vendor preset: enabled) Active: active (running) since Thu 2023-09-28 23:48:55 KST; 4 days ago ``` + +### Logs + +Alpamon logs are managed by systemd's journald. Use the following commands to view logs: + +```bash +# View all logs +journalctl -u alpamon + +# Follow logs in real-time +journalctl -u alpamon -f + +# View logs since today +journalctl -u alpamon --since today + +# View recent logs (last 100 lines) +journalctl -u alpamon -n 100 +``` diff --git a/cmd/alpamon/command/root.go b/cmd/alpamon/command/root.go index dd237e73..136fdac3 100644 --- a/cmd/alpamon/command/root.go +++ b/cmd/alpamon/command/root.go @@ -20,7 +20,6 @@ import ( "github.com/alpacax/alpamon/pkg/version" "github.com/rs/zerolog/log" "github.com/spf13/cobra" - "gopkg.in/natefinch/lumberjack.v2" ) const ( @@ -54,7 +53,7 @@ func runAgent() { }() // Logger - logRotate := logger.InitLogger() + logger.InitLogger() // platform utils.InitPlatform() @@ -114,17 +113,17 @@ func runAgent() { select { case <-ctx.Done(): log.Info().Msg("Received termination signal. Shutting down...") - gracefulShutdown(metricCollector, wsClient, controlClient, authManager, logRotate, logServer, pidFilePath) + gracefulShutdown(metricCollector, wsClient, controlClient, authManager, logServer, pidFilePath) return case <-wsClient.ShutDownChan: log.Info().Msg("Shutdown command received. Shutting down...") cancel() - gracefulShutdown(metricCollector, wsClient, controlClient, authManager, logRotate, logServer, pidFilePath) + gracefulShutdown(metricCollector, wsClient, controlClient, authManager, logServer, pidFilePath) return case <-wsClient.RestartChan: log.Info().Msg("Restart command received. Restarting...") cancel() - gracefulShutdown(metricCollector, wsClient, controlClient, authManager, logRotate, logServer, pidFilePath) + gracefulShutdown(metricCollector, wsClient, controlClient, authManager, logServer, pidFilePath) restartAgent() return case <-wsClient.CollectorRestartChan: @@ -149,7 +148,7 @@ func restartAgent() { } } -func gracefulShutdown(collector *collector.Collector, wsClient *runner.WebsocketClient, controlClient *runner.ControlClient, authManager *runner.AuthManager, logRotate *lumberjack.Logger, logServer *logger.LogServer, pidPath string) { +func gracefulShutdown(collector *collector.Collector, wsClient *runner.WebsocketClient, controlClient *runner.ControlClient, authManager *runner.AuthManager, logServer *logger.LogServer, pidPath string) { if collector != nil { collector.Stop() } @@ -168,8 +167,5 @@ func gracefulShutdown(collector *collector.Collector, wsClient *runner.Websocket log.Debug().Msg("Bye.") - if logRotate != nil { - _ = logRotate.Close() - } _ = os.Remove(pidPath) } diff --git a/configs/alpamon.service b/configs/alpamon.service index 5d7b8ed9..d010307d 100644 --- a/configs/alpamon.service +++ b/configs/alpamon.service @@ -9,8 +9,9 @@ WorkingDirectory=/var/lib/alpamon SELinuxContext=-unconfined_u:unconfined_r:unconfined_t:s0 AppArmorProfile=-unconfined Restart=on-failure -StandardOutput=null -StandardError=null +StandardOutput=journal +StandardError=journal +SyslogIdentifier=alpamon [Install] WantedBy=multi-user.target \ No newline at end of file diff --git a/go.mod b/go.mod index 08180210..196bd590 100644 --- a/go.mod +++ b/go.mod @@ -22,7 +22,6 @@ require ( golang.org/x/term v0.30.0 gopkg.in/go-playground/validator.v9 v9.31.0 gopkg.in/ini.v1 v1.67.0 - gopkg.in/natefinch/lumberjack.v2 v2.2.1 ) require ( diff --git a/go.sum b/go.sum index 64b14d47..8b98fdc7 100644 --- a/go.sum +++ b/go.sum @@ -150,8 +150,6 @@ gopkg.in/go-playground/validator.v9 v9.31.0 h1:bmXmP2RSNtFES+bn4uYuHT7iJFJv7Vj+a gopkg.in/go-playground/validator.v9 v9.31.0/go.mod h1:+c9/zcJMFNgbLvly1L1V+PpxWdVbfP1avr/N00E2vyQ= gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA= gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= -gopkg.in/natefinch/lumberjack.v2 v2.2.1 h1:bBRl1b0OH9s/DuPhuXpNl+VtCaJXFZ5/uEFST95x9zc= -gopkg.in/natefinch/lumberjack.v2 v2.2.1/go.mod h1:YD8tP3GAjkrDg1eZH7EGmyESg/lsYskCTPBJVb9jqSc= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= modernc.org/cc/v4 v4.21.4 h1:3Be/Rdo1fpr8GrQ7IVw9OHtplU4gWbb+wNgeoBMmGLQ= diff --git a/pkg/logger/logger.go b/pkg/logger/logger.go index ac603c7b..3f4df8ab 100644 --- a/pkg/logger/logger.go +++ b/pkg/logger/logger.go @@ -14,13 +14,10 @@ import ( "github.com/alpacax/alpamon/pkg/version" "github.com/rs/zerolog" "github.com/rs/zerolog/log" - "gopkg.in/natefinch/lumberjack.v2" ) const ( - logDir = "/var/log/alpamon" - logFileName = "alpamon.log" - recordURL = "/api/history/logs/" + recordURL = "/api/history/logs/" ) type LogRecord struct { @@ -54,35 +51,19 @@ var logRecordFileHandlers = map[string]int{ "server.go": 40, // logger/server.go } -func InitLogger() *lumberjack.Logger { - fileName := fmt.Sprintf("%s/%s", logDir, logFileName) - if _, err := os.Stat(logDir); os.IsNotExist(err) { - fileName = logFileName - } - - // Set up lumberjack logger for log rotation - logRotate := &lumberjack.Logger{ - Filename: fileName, - MaxSize: 50, // Max size in MB before rotation - MaxBackups: 5, // Max number of backup files - MaxAge: 30, // Max age in days - Compress: true, - } - +func InitLogger() { recordWriter := &logRecordWriter{} var output io.Writer if version.Version == "dev" { - // In development, log to console with caller info + // In development, log to stderr with caller info output = zerolog.MultiLevelWriter(PrettyWriter(os.Stderr, true), recordWriter) } else { - // In production, log to file without caller info in PrettyWriter - output = zerolog.MultiLevelWriter(PrettyWriter(logRotate, false), recordWriter) + // In production, log to stderr without caller info (systemd/journald will capture) + output = zerolog.MultiLevelWriter(PrettyWriter(os.Stderr, false), recordWriter) } // Always include .Caller() so entry.Caller is set for logRecordWriter log.Logger = zerolog.New(output).With().Timestamp().Caller().Logger() - - return logRotate } // PrettyWriter returns a zerolog.ConsoleWriter with or without caller info