aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJeff Halter <868228+jhalter@users.noreply.github.com>2026-06-01 09:26:50 -0700
committerJeff Halter <868228+jhalter@users.noreply.github.com>2026-06-01 09:26:50 -0700
commitc42c103ddb66028a085fb452102f73f8b27dcdcb (patch)
treeb7fe404a3a46916e082c80dce089d2258c4bc307
parent123d1a305bc68474034f5989362148508bdbf7f5 (diff)
Improve startup logging and logging consistency
Startup log: - Add interface, port, and fileTransferPort fields to the "Hotline server started" line so operators can see what the server bound to. - Resolve an empty -interface flag to 0.0.0.0 for display. Levels: - Demote the two Redis startup messages (ban management, cleared online users) from Info to Debug. Consistency: - Standardize the error field key to "err" (was "Err" in a few account handlers) and lowercase "Account" -> "account". - Standardize the remote-address key to "remoteAddr" (was "RemoteAddr"). - Replace fmt.Sprintf in the tracker-registration message and string concatenation in the config-dir-init and ban-disconnect messages with structured fields; use the standard "err" key. - Give the two bare rLogger.Error(err.Error()) file-transfer calls a descriptive message and an "err" field. logger.go: - Only attach the rotating lumberjack file writer when --log-file is set. An empty Filename made lumberjack write to a temp file by default.
-rw-r--r--cmd/mobius-hotline-server/main.go10
-rw-r--r--hotline/client_conn.go2
-rw-r--r--hotline/file_transfer.go4
-rw-r--r--hotline/server.go8
-rw-r--r--internal/mobius/api.go2
-rw-r--r--internal/mobius/logger.go19
-rw-r--r--internal/mobius/transaction_handlers.go12
7 files changed, 34 insertions, 23 deletions
diff --git a/cmd/mobius-hotline-server/main.go b/cmd/mobius-hotline-server/main.go
index 8b9d54c..dced2c5 100644
--- a/cmd/mobius-hotline-server/main.go
+++ b/cmd/mobius-hotline-server/main.go
@@ -71,7 +71,7 @@ func main() {
slogger.Error("Error copying config dir", "err", err)
os.Exit(1)
}
- slogger.Info("Config dir initialized at " + *configDir)
+ slogger.Info("Config dir initialized", "config", *configDir)
} else {
slogger.Info("Existing config dir found. Skipping initialization.")
}
@@ -131,7 +131,7 @@ func main() {
srv.Redis = redisClient
srv.BanList = mobius.NewRedisBanMgr(redisClient, slogger)
- slogger.Info("Using Redis for ban management", "addr", *redisAddr)
+ slogger.Debug("Using Redis for ban management", "addr", *redisAddr)
} else {
srv.BanList, err = mobius.NewBanFile(path.Join(*configDir, "Banlist.yaml"))
if err != nil {
@@ -215,7 +215,11 @@ func main() {
}
}()
- slogger.Info("Hotline server started", "version", version, "config", *configDir)
+ boundInterface := *netInterface
+ if boundInterface == "" {
+ boundInterface = "0.0.0.0"
+ }
+ slogger.Info("Hotline server started", "version", version, "config", *configDir, "interface", boundInterface, "port", *basePort, "fileTransferPort", *basePort+1)
if tlsConfig != nil {
slogger.Info("TLS enabled", "port", *tlsPort, "fileTransferPort", *tlsPort+1)
}
diff --git a/hotline/client_conn.go b/hotline/client_conn.go
index 9ca93a7..c17ef35 100644
--- a/hotline/client_conn.go
+++ b/hotline/client_conn.go
@@ -176,7 +176,7 @@ func (cc *ClientConn) Disconnect() {
}
if err := cc.Connection.Close(); err != nil {
- cc.Server.Logger.Debug("error closing client connection", "RemoteAddr", cc.RemoteAddr)
+ cc.Server.Logger.Debug("error closing client connection", "remoteAddr", cc.RemoteAddr)
}
}
diff --git a/hotline/file_transfer.go b/hotline/file_transfer.go
index 98999f1..86e10eb 100644
--- a/hotline/file_transfer.go
+++ b/hotline/file_transfer.go
@@ -477,7 +477,7 @@ func DownloadFolderHandler(rwc io.ReadWriter, fullPath string, fileTransfer *Fil
// Send file size to client
if _, err := rwc.Write(hlFile.Ffo.TransferSize(dataOffset)); err != nil {
- rLogger.Error(err.Error())
+ rLogger.Error("Error sending file size", "err", err)
return fmt.Errorf("error sending file size: %w", err)
}
@@ -625,7 +625,7 @@ func UploadFolderHandler(rwc io.ReadWriter, fullPath string, fileTransfer *FileT
}
if err := receiveFile(rwc, file, io.Discard, io.Discard, fileTransfer.bytesSentCounter); err != nil {
- rLogger.Error(err.Error())
+ rLogger.Error("Error receiving file", "err", err)
}
err = os.Rename(fullPath+"/"+fu.FormattedPath()+".incomplete", fullPath+"/"+fu.FormattedPath())
diff --git a/hotline/server.go b/hotline/server.go
index 7bc6a4a..6ac68d8 100644
--- a/hotline/server.go
+++ b/hotline/server.go
@@ -309,16 +309,16 @@ func (s *Server) Serve(ctx context.Context, ln net.Listener) error {
// Check if the rate limit is exceeded and close the connection if so.
if !rl.Allow() {
- s.Logger.Info("Rate limit exceeded", "RemoteAddr", conn.RemoteAddr())
+ s.Logger.Info("Rate limit exceeded", "remoteAddr", conn.RemoteAddr())
_ = conn.Close()
return
}
if err := s.handleNewConnection(connCtx, conn, conn.RemoteAddr().String()); err != nil {
if err == io.EOF {
- s.Logger.Info("Client disconnected", "RemoteAddr", conn.RemoteAddr())
+ s.Logger.Info("Client disconnected", "remoteAddr", conn.RemoteAddr())
} else {
- s.Logger.Error("Error serving request", "RemoteAddr", conn.RemoteAddr(), "err", err)
+ s.Logger.Error("Error serving request", "remoteAddr", conn.RemoteAddr(), "err", err)
}
}
}()
@@ -380,7 +380,7 @@ func (s *Server) registerWithAllTrackers() {
tr.Password = parseTrackerPassword(t)
if err := s.TrackerRegistrar.Register(t, tr); err != nil {
- s.Logger.Error(fmt.Sprintf("Unable to register with tracker %v", t), "error", err)
+ s.Logger.Error("Unable to register with tracker", "tracker", t, "err", err)
}
}
}
diff --git a/internal/mobius/api.go b/internal/mobius/api.go
index adc9072..a574bf8 100644
--- a/internal/mobius/api.go
+++ b/internal/mobius/api.go
@@ -85,7 +85,7 @@ func NewAPIServer(hlServer *hotline.Server, reloadFunc func(), logger *slog.Logg
if err := hlServer.Redis.Del(context.Background(), hotline.RedisKeyOnline).Err(); err != nil {
srv.logger.Warn("Failed to clear online users in Redis", "err", err)
} else {
- srv.logger.Info("Cleared online users in Redis on startup")
+ srv.logger.Debug("Cleared online users in Redis on startup")
}
}
diff --git a/internal/mobius/logger.go b/internal/mobius/logger.go
index 60d4f0d..2f67a71 100644
--- a/internal/mobius/logger.go
+++ b/internal/mobius/logger.go
@@ -22,14 +22,21 @@ var logLevels = map[string]slog.Level{
}
func NewLogger(logLevel, logFile *string) *slog.Logger {
+ // Always log to stdout. Only add the rotating file writer when a log file path
+ // is configured; an empty Filename makes lumberjack write to a temp file.
+ var out io.Writer = os.Stdout
+ if *logFile != "" {
+ out = io.MultiWriter(os.Stdout, &lumberjack.Logger{
+ Filename: *logFile,
+ MaxSize: logMaxSize,
+ MaxBackups: logMaxBackups,
+ MaxAge: logMaxAge,
+ })
+ }
+
return slog.New(
slog.NewTextHandler(
- io.MultiWriter(os.Stdout, &lumberjack.Logger{
- Filename: *logFile,
- MaxSize: logMaxSize,
- MaxBackups: logMaxBackups,
- MaxAge: logMaxAge,
- }),
+ out,
&slog.HandlerOptions{
Level: logLevels[*logLevel],
ReplaceAttr: func(groups []string, a slog.Attr) slog.Attr {
diff --git a/internal/mobius/transaction_handlers.go b/internal/mobius/transaction_handlers.go
index b629be8..96b4f69 100644
--- a/internal/mobius/transaction_handlers.go
+++ b/internal/mobius/transaction_handlers.go
@@ -685,7 +685,7 @@ func HandleSetUser(cc *hotline.ClientConn, t *hotline.Transaction) (res []hotlin
err := cc.Server.AccountManager.Update(*account, account.Login)
if err != nil {
- cc.Logger.Error("Error updating account", "Err", err)
+ cc.Logger.Error("Error updating account", "err", err)
return cc.NewErrReply(t, ErrMsgUpdateAccount)
}
@@ -760,7 +760,7 @@ func HandleListUsers(cc *hotline.ClientConn, t *hotline.Transaction) (res []hotl
for _, acc := range cc.Server.AccountManager.List() {
b, err := io.ReadAll(&acc)
if err != nil {
- cc.Logger.Error("Error reading account", "Account", acc.Login, "Err", err)
+ cc.Logger.Error("Error reading account", "account", acc.Login, "err", err)
continue
}
@@ -831,7 +831,7 @@ func HandleUpdateUser(cc *hotline.ClientConn, t *hotline.Transaction) (res []hot
cc.Logger.Info("DeleteUser", "login", login)
if err := cc.Server.AccountManager.Delete(login); err != nil {
- cc.Logger.Error("Error deleting account", "Err", err)
+ cc.Logger.Error("Error deleting account", "err", err)
return cc.NewErrReply(t, ErrMsgDeleteAccount)
}
@@ -1005,7 +1005,7 @@ func HandleDeleteUser(cc *hotline.ClientConn, t *hotline.Transaction) (res []hot
login := t.GetField(hotline.FieldUserLogin).DecodeObfuscatedString()
if err := cc.Server.AccountManager.Delete(login); err != nil {
- cc.Logger.Error("Error deleting account", "Err", err)
+ cc.Logger.Error("Error deleting account", "err", err)
return cc.NewErrReply(t, ErrMsgDeleteAccount)
}
@@ -1269,7 +1269,7 @@ func HandleDisconnectUser(cc *hotline.ClientConn, t *hotline.Transaction) (res [
switch options[1] {
case 1:
// send message: "You are temporarily banned on this server"
- cc.Logger.Info("Disconnect & temporarily ban " + string(clientConn.UserName))
+ cc.Logger.Info("Disconnect & temporarily ban user", "username", string(clientConn.UserName))
res = append(res, hotline.NewTransaction(
hotline.TranServerMsg,
@@ -1288,7 +1288,7 @@ func HandleDisconnectUser(cc *hotline.ClientConn, t *hotline.Transaction) (res [
}
case 2:
// send message: "You are permanently banned on this server"
- cc.Logger.Info("Disconnect & ban " + string(clientConn.UserName))
+ cc.Logger.Info("Disconnect & ban user", "username", string(clientConn.UserName))
res = append(res, hotline.NewTransaction(
hotline.TranServerMsg,