From 44692e986eb1adb227da406ce4736ed2987b57f6 Mon Sep 17 00:00:00 2001 From: stratic-dev Date: Fri, 11 Oct 2024 00:15:11 +0100 Subject: [PATCH] Added logger singleton --- main.go | 78 ++++++++++---------- server/api/api_server.go | 8 +- server/channelserver/handlers_cast_binary.go | 38 ++++++---- server/channelserver/sys_channel_server.go | 8 +- server/channelserver/sys_session.go | 3 +- server/discordbot/discord_bot.go | 12 +-- server/entranceserver/entrance_server.go | 5 +- server/signserver/session.go | 3 +- server/signserver/sign_server.go | 6 +- utils/logger/logger.go | 27 +++++++ utils/logger/logger_interface.go | 14 ++++ utils/logger/zap_logger.go | 37 ++++++++++ 12 files changed, 165 insertions(+), 74 deletions(-) create mode 100644 utils/logger/logger.go create mode 100644 utils/logger/logger_interface.go create mode 100644 utils/logger/zap_logger.go diff --git a/main.go b/main.go index 3a009d49a..b605dcf57 100644 --- a/main.go +++ b/main.go @@ -14,6 +14,8 @@ import ( "erupe-ce/server/channelserver" "erupe-ce/server/discordbot" "erupe-ce/server/entranceserver" + "erupe-ce/utils/logger" + "erupe-ce/server/signserver" "erupe-ce/utils/gametime" @@ -22,6 +24,8 @@ import ( "go.uber.org/zap" ) +var mainLogger logger.Logger + // Temporary DB auto clean on startup for quick development & testing. func cleanDB(db *sqlx.DB) { _ = db.MustExec("DELETE FROM guild_characters") @@ -41,18 +45,22 @@ var Commit = func() string { return "unknown" } +func initLogger() { + var zapLogger *zap.Logger + zapLogger, _ = zap.NewDevelopment(zap.WithCaller(false)) + defer zapLogger.Sync() + // Initialize the global logger + logger.Init(zapLogger) + mainLogger = logger.Get().Named("main") + +} func main() { var err error - var zapLogger *zap.Logger config := _config.ErupeConfig - zapLogger, _ = zap.NewDevelopment() - - defer zapLogger.Sync() - logger := zapLogger.Named("main") - - logger.Info(fmt.Sprintf("Starting Erupe (9.3b-%s)", Commit())) - logger.Info(fmt.Sprintf("Client Mode: %s (%d)", config.ClientMode, config.ClientID)) + initLogger() + mainLogger.Info(fmt.Sprintf("Starting Erupe (9.3b-%s)", Commit())) + mainLogger.Info(fmt.Sprintf("Client Mode: %s (%d)", config.ClientMode, config.ClientID)) if config.Database.Password == "" { preventClose("Database password is blank") @@ -76,31 +84,30 @@ func main() { if config.Discord.Enabled { bot, err := discordbot.NewDiscordBot(discordbot.Options{ - Logger: logger, Config: _config.ErupeConfig, }) - + DiscordFailMsg := "Discord: Failed to start, %s" if err != nil { - preventClose(fmt.Sprintf("Discord: Failed to start, %s", err.Error())) + preventClose(fmt.Sprintf(DiscordFailMsg, err.Error())) } // Discord bot err = bot.Start() if err != nil { - preventClose(fmt.Sprintf("Discord: Failed to start, %s", err.Error())) + preventClose(fmt.Sprintf(DiscordFailMsg, err.Error())) } discordBot = bot _, err = discordBot.Session.ApplicationCommandBulkOverwrite(discordBot.Session.State.User.ID, "", discordbot.Commands) if err != nil { - preventClose(fmt.Sprintf("Discord: Failed to start, %s", err.Error())) + preventClose(fmt.Sprintf(DiscordFailMsg, err.Error())) } - logger.Info("Discord: Started successfully") + mainLogger.Info("Discord: Started successfully") } else { - logger.Info("Discord: Disabled") + mainLogger.Info("Discord: Disabled") } // Create the postgres DB pool. @@ -123,7 +130,7 @@ func main() { if err != nil { preventClose(fmt.Sprintf("Database: Failed to ping, %s", err.Error())) } - logger.Info("Database: Started successfully") + mainLogger.Info("Database: Started successfully") // Clear stale data if config.DebugOptions.ProxyPort == 0 { @@ -134,22 +141,23 @@ func main() { // Clean the DB if the option is on. if config.DebugOptions.CleanDB { - logger.Info("Database: Started clearing...") + mainLogger.Info("Database: Started clearing...") cleanDB(db) - logger.Info("Database: Finished clearing") + mainLogger.Info("Database: Finished clearing") } - logger.Info(fmt.Sprintf("Server Time: %s", gametime.TimeAdjusted().String())) + mainLogger.Info(fmt.Sprintf("Server Time: %s", gametime.TimeAdjusted().String())) // Now start our server(s). // Entrance server. + entranceLogger := logger.Get().Named("entrance") var entranceServer *entranceserver.Server if config.Entrance.Enabled { entranceServer = entranceserver.NewServer( &entranceserver.Config{ - Logger: logger.Named("entrance"), + Logger: entranceLogger, ErupeConfig: _config.ErupeConfig, DB: db, }) @@ -157,18 +165,16 @@ func main() { if err != nil { preventClose(fmt.Sprintf("Entrance: Failed to start, %s", err.Error())) } - logger.Info("Entrance: Started successfully") + mainLogger.Info("Entrance: Started successfully") } else { - logger.Info("Entrance: Disabled") + mainLogger.Info("Entrance: Disabled") } // Sign server. - var signServer *signserver.Server if config.Sign.Enabled { signServer = signserver.NewServer( &signserver.Config{ - Logger: logger.Named("sign"), ErupeConfig: _config.ErupeConfig, DB: db, }) @@ -176,17 +182,16 @@ func main() { if err != nil { preventClose(fmt.Sprintf("Sign: Failed to start, %s", err.Error())) } - logger.Info("Sign: Started successfully") + mainLogger.Info("Sign: Started successfully") } else { - logger.Info("Sign: Disabled") + mainLogger.Info("Sign: Disabled") } - // New Sign server + // Api server var ApiServer *api.APIServer if config.API.Enabled { ApiServer = api.NewAPIServer( &api.Config{ - Logger: logger.Named("sign"), ErupeConfig: _config.ErupeConfig, DB: db, }) @@ -194,13 +199,12 @@ func main() { if err != nil { preventClose(fmt.Sprintf("API: Failed to start, %s", err.Error())) } - logger.Info("API: Started successfully") + mainLogger.Info("API: Started successfully") } else { - logger.Info("API: Disabled") + mainLogger.Info("API: Disabled") } var channelServers []*channelserver.Server - if config.Channel.Enabled { channelQuery := "" si := 0 @@ -211,7 +215,6 @@ func main() { sid := (4096 + si*256) + (16 + ci) c := *channelserver.NewServer(&channelserver.Config{ ID: uint16(sid), - Logger: logger.Named("channel-" + fmt.Sprint(count)), ErupeConfig: _config.ErupeConfig, DB: db, DiscordBot: discordBot, @@ -229,7 +232,7 @@ func main() { } else { channelQuery += fmt.Sprintf(`INSERT INTO servers (server_id, current_players, world_name, world_description, land) VALUES (%d, 0, '%s', '%s', %d);`, sid, ee.Name, ee.Description, i+1) channelServers = append(channelServers, &c) - logger.Info(fmt.Sprintf("Channel %d (%d): Started successfully", count, ce.Port)) + mainLogger.Info(fmt.Sprintf("Channel %d (%d): Started successfully", count, ce.Port)) ci++ count++ } @@ -246,7 +249,7 @@ func main() { } } - logger.Info("Finished starting Erupe") + mainLogger.Info("Finished starting Erupe") // Wait for exit or interrupt with ctrl+C. c := make(chan os.Signal, 1) @@ -259,7 +262,7 @@ func main() { for _, channelServer := range channelServers { channelServer.BroadcastChatMessage(message) } - logger.Info(message) + mainLogger.Warn(message) time.Sleep(time.Second) } } @@ -295,9 +298,8 @@ func preventClose(text string) { if _config.ErupeConfig.DisableSoftCrash { os.Exit(0) } - fmt.Println("\nFailed to start Erupe:\n" + text) + mainLogger.Error(fmt.Sprintf(("\nFailed to start Erupe:\n" + text))) go wait() - fmt.Println("\nPress Enter/Return to exit...") - fmt.Scanln() + mainLogger.Error(fmt.Sprintf(("\nPress Enter/Return to exit..."))) os.Exit(0) } diff --git a/server/api/api_server.go b/server/api/api_server.go index 3774f3fb8..19798837e 100644 --- a/server/api/api_server.go +++ b/server/api/api_server.go @@ -9,6 +9,8 @@ import ( "sync" "time" + "erupe-ce/utils/logger" + "github.com/gorilla/handlers" "github.com/gorilla/mux" "github.com/jmoiron/sqlx" @@ -16,7 +18,6 @@ import ( ) type Config struct { - Logger *zap.Logger DB *sqlx.DB ErupeConfig *_config.Config } @@ -24,7 +25,7 @@ type Config struct { // APIServer is Erupes Standard API interface type APIServer struct { sync.Mutex - logger *zap.Logger + logger logger.Logger erupeConfig *_config.Config db *sqlx.DB httpServer *http.Server @@ -33,8 +34,9 @@ type APIServer struct { // NewAPIServer creates a new Server type. func NewAPIServer(config *Config) *APIServer { + s := &APIServer{ - logger: config.Logger, + logger: logger.Get().Named("API"), erupeConfig: config.ErupeConfig, db: config.DB, httpServer: &http.Server{}, diff --git a/server/channelserver/handlers_cast_binary.go b/server/channelserver/handlers_cast_binary.go index cf51b6188..07643f787 100644 --- a/server/channelserver/handlers_cast_binary.go +++ b/server/channelserver/handlers_cast_binary.go @@ -7,9 +7,12 @@ import ( "erupe-ce/network/binpacket" "erupe-ce/network/mhfpacket" "erupe-ce/utils/byteframe" + "erupe-ce/utils/logger" "erupe-ce/utils/mhfcid" "erupe-ce/utils/mhfcourse" "erupe-ce/utils/token" + "sync" + "fmt" "math" "strconv" @@ -39,24 +42,27 @@ const ( BroadcastTypeWorld = 0x0a ) -var commands map[string]_config.Command +var ( + commands map[string]_config.Command + once sync.Once // Ensures that initialization happens only once + commandsMu sync.Mutex // Mutex to ensure thread safety for commands map +) + +func (server *Server) initCommands() { + once.Do(func() { + commands = make(map[string]_config.Command) -func init() { - commands = make(map[string]_config.Command) - zapConfig := zap.NewDevelopmentConfig() - zapConfig.DisableCaller = true - zapLogger, _ := zapConfig.Build() - defer zapLogger.Sync() - logger := zapLogger.Named("commands") - cmds := _config.ErupeConfig.Commands - for _, cmd := range cmds { - commands[cmd.Name] = cmd - if cmd.Enabled { - logger.Info(fmt.Sprintf("Command %s: Enabled, prefix: %s", cmd.Name, cmd.Prefix)) - } else { - logger.Info(fmt.Sprintf("Command %s: Disabled", cmd.Name)) + commandLogger := logger.Get().Named("command") + cmds := _config.ErupeConfig.Commands + for _, cmd := range cmds { + commands[cmd.Name] = cmd + if cmd.Enabled { + commandLogger.Info(fmt.Sprintf("%s: Enabled, prefix: %s", cmd.Name, cmd.Prefix)) + } else { + commandLogger.Info(fmt.Sprintf("%s: Disabled", cmd.Name)) + } } - } + }) } func sendDisabledCommandMessage(s *Session, cmd _config.Command) { diff --git a/server/channelserver/sys_channel_server.go b/server/channelserver/sys_channel_server.go index 14e2b074f..fae6c3244 100644 --- a/server/channelserver/sys_channel_server.go +++ b/server/channelserver/sys_channel_server.go @@ -9,6 +9,7 @@ import ( _config "erupe-ce/config" "erupe-ce/server/discordbot" "erupe-ce/utils/gametime" + "erupe-ce/utils/logger" "github.com/jmoiron/sqlx" "go.uber.org/zap" @@ -17,7 +18,6 @@ import ( // Config struct allows configuring the server. type Config struct { ID uint16 - Logger *zap.Logger DB *sqlx.DB DiscordBot *discordbot.DiscordBot ErupeConfig *_config.Config @@ -39,7 +39,7 @@ type Server struct { GlobalID string IP string Port uint16 - logger *zap.Logger + logger logger.Logger db *sqlx.DB erupeConfig *_config.Config acceptConns chan net.Conn @@ -92,7 +92,7 @@ func NewServer(config *Config) *Server { } server := &Server{ ID: config.ID, - logger: config.Logger, + logger: logger.Get().Named("channel-" + fmt.Sprint(config.ID)), db: config.DB, erupeConfig: config.ErupeConfig, acceptConns: make(chan net.Conn), @@ -114,9 +114,9 @@ func NewServer(config *Config) *Server { questCacheData: make(map[int][]byte), questCacheTime: make(map[int]time.Time), } + server.initCommands() server.i18n = getLangStrings(server) - return server } diff --git a/server/channelserver/sys_session.go b/server/channelserver/sys_session.go index aefd5f864..fe6c10ba4 100644 --- a/server/channelserver/sys_session.go +++ b/server/channelserver/sys_session.go @@ -15,6 +15,7 @@ import ( "erupe-ce/network" "erupe-ce/network/mhfpacket" "erupe-ce/utils/byteframe" + "erupe-ce/utils/logger" "erupe-ce/utils/stringstack" "go.uber.org/zap" @@ -23,7 +24,7 @@ import ( // Session holds state for the channel server connection. type Session struct { sync.Mutex - logger *zap.Logger + logger logger.Logger server *Server rawConn net.Conn cryptConn *network.CryptConn diff --git a/server/discordbot/discord_bot.go b/server/discordbot/discord_bot.go index 303cbc630..6cdd39afa 100644 --- a/server/discordbot/discord_bot.go +++ b/server/discordbot/discord_bot.go @@ -2,6 +2,7 @@ package discordbot import ( _config "erupe-ce/config" + "erupe-ce/utils/logger" "regexp" "github.com/bwmarrin/discordgo" @@ -38,21 +39,20 @@ var Commands = []*discordgo.ApplicationCommand{ type DiscordBot struct { Session *discordgo.Session config *_config.Config - logger *zap.Logger + logger logger.Logger MainGuild *discordgo.Guild RelayChannel *discordgo.Channel } type Options struct { Config *_config.Config - Logger *zap.Logger } func NewDiscordBot(options Options) (discordBot *DiscordBot, err error) { session, err := discordgo.New("Bot " + options.Config.Discord.BotToken) - + discordLogger := logger.Get().Named("discord") if err != nil { - options.Logger.Fatal("Discord failed", zap.Error(err)) + discordLogger.Fatal("Discord failed", zap.Error(err)) return nil, err } @@ -63,13 +63,13 @@ func NewDiscordBot(options Options) (discordBot *DiscordBot, err error) { } if err != nil { - options.Logger.Fatal("Discord failed to create relayChannel", zap.Error(err)) + discordLogger.Fatal("Discord failed to create relayChannel", zap.Error(err)) return nil, err } discordBot = &DiscordBot{ config: options.Config, - logger: options.Logger, + logger: discordLogger, Session: session, RelayChannel: relayChannel, } diff --git a/server/entranceserver/entrance_server.go b/server/entranceserver/entrance_server.go index 1deb92365..b9374f562 100644 --- a/server/entranceserver/entrance_server.go +++ b/server/entranceserver/entrance_server.go @@ -10,6 +10,7 @@ import ( _config "erupe-ce/config" "erupe-ce/network" + "erupe-ce/utils/logger" "github.com/jmoiron/sqlx" "go.uber.org/zap" @@ -18,7 +19,7 @@ import ( // Server is a MHF entrance server. type Server struct { sync.Mutex - logger *zap.Logger + logger logger.Logger erupeConfig *_config.Config db *sqlx.DB listener net.Listener @@ -27,7 +28,7 @@ type Server struct { // Config struct allows configuring the server. type Config struct { - Logger *zap.Logger + Logger logger.Logger DB *sqlx.DB ErupeConfig *_config.Config } diff --git a/server/signserver/session.go b/server/signserver/session.go index 68fc1e95b..fa3b0f99c 100644 --- a/server/signserver/session.go +++ b/server/signserver/session.go @@ -3,6 +3,7 @@ package signserver import ( "database/sql" "encoding/hex" + "erupe-ce/utils/logger" "erupe-ce/utils/stringsupport" "fmt" "net" @@ -28,7 +29,7 @@ const ( // Session holds state for the sign server connection. type Session struct { sync.Mutex - logger *zap.Logger + logger logger.Logger server *Server rawConn net.Conn cryptConn *network.CryptConn diff --git a/server/signserver/sign_server.go b/server/signserver/sign_server.go index 975cc1112..0aaac5d80 100644 --- a/server/signserver/sign_server.go +++ b/server/signserver/sign_server.go @@ -8,6 +8,7 @@ import ( _config "erupe-ce/config" "erupe-ce/network" + "erupe-ce/utils/logger" "github.com/jmoiron/sqlx" "go.uber.org/zap" @@ -15,7 +16,6 @@ import ( // Config struct allows configuring the server. type Config struct { - Logger *zap.Logger DB *sqlx.DB ErupeConfig *_config.Config } @@ -23,7 +23,7 @@ type Config struct { // Server is a MHF sign server. type Server struct { sync.Mutex - logger *zap.Logger + logger logger.Logger erupeConfig *_config.Config sessions map[int]*Session db *sqlx.DB @@ -34,7 +34,7 @@ type Server struct { // NewServer creates a new Server type. func NewServer(config *Config) *Server { s := &Server{ - logger: config.Logger, + logger: logger.Get().Named("sign"), erupeConfig: config.ErupeConfig, db: config.DB, } diff --git a/utils/logger/logger.go b/utils/logger/logger.go new file mode 100644 index 000000000..30cf803cf --- /dev/null +++ b/utils/logger/logger.go @@ -0,0 +1,27 @@ +package logger + +import ( + "sync" + + "go.uber.org/zap" +) + +var ( + instance Logger // Global instance of Logger interface + once sync.Once // Ensures logger is initialized only once +) + +// Init initializes the global logger. This function should be called once, ideally during the app startup. +func Init(zapLogger *zap.Logger) { + once.Do(func() { + instance = NewZapLogger(zapLogger) // Assign the zapLogger as the global logger + }) +} + +// Get returns the global logger instance. +func Get() Logger { + if instance == nil { + panic("Logger is not initialized. Call logger.Init() before using the logger.") + } + return instance +} diff --git a/utils/logger/logger_interface.go b/utils/logger/logger_interface.go new file mode 100644 index 000000000..598a956a2 --- /dev/null +++ b/utils/logger/logger_interface.go @@ -0,0 +1,14 @@ +package logger + +import "go.uber.org/zap" + +// Logger interface to abstract logging +type Logger interface { + Info(msg string, fields ...zap.Field) + Warn(msg string, fields ...zap.Field) + Error(msg string, fields ...zap.Field) + Debug(msg string, fields ...zap.Field) + Fatal(msg string, fields ...zap.Field) + + Named(name string) Logger +} diff --git a/utils/logger/zap_logger.go b/utils/logger/zap_logger.go new file mode 100644 index 000000000..c48a8ae42 --- /dev/null +++ b/utils/logger/zap_logger.go @@ -0,0 +1,37 @@ +package logger + +import ( + "go.uber.org/zap" +) + +type ZapLogger struct { + logger *zap.Logger +} + +// NewZapLogger creates a new ZapLogger instance +func NewZapLogger(zapLogger *zap.Logger) *ZapLogger { + return &ZapLogger{logger: zapLogger} +} + +// Implement the Logger interface methods +func (z *ZapLogger) Info(msg string, fields ...zap.Field) { + z.logger.Info(msg, fields...) +} + +func (z *ZapLogger) Warn(msg string, fields ...zap.Field) { + z.logger.Warn(msg, fields...) +} + +func (z *ZapLogger) Error(msg string, fields ...zap.Field) { + z.logger.Error(msg, fields...) +} +func (z *ZapLogger) Fatal(msg string, fields ...zap.Field) { + z.logger.Fatal(msg, fields...) +} + +func (z *ZapLogger) Debug(msg string, fields ...zap.Field) { + z.logger.Debug(msg, fields...) +} +func (z *ZapLogger) Named(name string) Logger { + return &ZapLogger{logger: z.logger.Named(name)} +}