Added logger singleton

This commit is contained in:
stratic-dev
2024-10-11 00:15:11 +01:00
parent 32dbfa7514
commit 44692e986e
12 changed files with 165 additions and 74 deletions

78
main.go
View File

@@ -14,6 +14,8 @@ import (
"erupe-ce/server/channelserver" "erupe-ce/server/channelserver"
"erupe-ce/server/discordbot" "erupe-ce/server/discordbot"
"erupe-ce/server/entranceserver" "erupe-ce/server/entranceserver"
"erupe-ce/utils/logger"
"erupe-ce/server/signserver" "erupe-ce/server/signserver"
"erupe-ce/utils/gametime" "erupe-ce/utils/gametime"
@@ -22,6 +24,8 @@ import (
"go.uber.org/zap" "go.uber.org/zap"
) )
var mainLogger logger.Logger
// Temporary DB auto clean on startup for quick development & testing. // Temporary DB auto clean on startup for quick development & testing.
func cleanDB(db *sqlx.DB) { func cleanDB(db *sqlx.DB) {
_ = db.MustExec("DELETE FROM guild_characters") _ = db.MustExec("DELETE FROM guild_characters")
@@ -41,18 +45,22 @@ var Commit = func() string {
return "unknown" 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() { func main() {
var err error var err error
var zapLogger *zap.Logger
config := _config.ErupeConfig config := _config.ErupeConfig
zapLogger, _ = zap.NewDevelopment() initLogger()
mainLogger.Info(fmt.Sprintf("Starting Erupe (9.3b-%s)", Commit()))
defer zapLogger.Sync() mainLogger.Info(fmt.Sprintf("Client Mode: %s (%d)", config.ClientMode, config.ClientID))
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))
if config.Database.Password == "" { if config.Database.Password == "" {
preventClose("Database password is blank") preventClose("Database password is blank")
@@ -76,31 +84,30 @@ func main() {
if config.Discord.Enabled { if config.Discord.Enabled {
bot, err := discordbot.NewDiscordBot(discordbot.Options{ bot, err := discordbot.NewDiscordBot(discordbot.Options{
Logger: logger,
Config: _config.ErupeConfig, Config: _config.ErupeConfig,
}) })
DiscordFailMsg := "Discord: Failed to start, %s"
if err != nil { if err != nil {
preventClose(fmt.Sprintf("Discord: Failed to start, %s", err.Error())) preventClose(fmt.Sprintf(DiscordFailMsg, err.Error()))
} }
// Discord bot // Discord bot
err = bot.Start() err = bot.Start()
if err != nil { if err != nil {
preventClose(fmt.Sprintf("Discord: Failed to start, %s", err.Error())) preventClose(fmt.Sprintf(DiscordFailMsg, err.Error()))
} }
discordBot = bot discordBot = bot
_, err = discordBot.Session.ApplicationCommandBulkOverwrite(discordBot.Session.State.User.ID, "", discordbot.Commands) _, err = discordBot.Session.ApplicationCommandBulkOverwrite(discordBot.Session.State.User.ID, "", discordbot.Commands)
if err != nil { 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 { } else {
logger.Info("Discord: Disabled") mainLogger.Info("Discord: Disabled")
} }
// Create the postgres DB pool. // Create the postgres DB pool.
@@ -123,7 +130,7 @@ func main() {
if err != nil { if err != nil {
preventClose(fmt.Sprintf("Database: Failed to ping, %s", err.Error())) preventClose(fmt.Sprintf("Database: Failed to ping, %s", err.Error()))
} }
logger.Info("Database: Started successfully") mainLogger.Info("Database: Started successfully")
// Clear stale data // Clear stale data
if config.DebugOptions.ProxyPort == 0 { if config.DebugOptions.ProxyPort == 0 {
@@ -134,22 +141,23 @@ func main() {
// Clean the DB if the option is on. // Clean the DB if the option is on.
if config.DebugOptions.CleanDB { if config.DebugOptions.CleanDB {
logger.Info("Database: Started clearing...") mainLogger.Info("Database: Started clearing...")
cleanDB(db) 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). // Now start our server(s).
// Entrance server. // Entrance server.
entranceLogger := logger.Get().Named("entrance")
var entranceServer *entranceserver.Server var entranceServer *entranceserver.Server
if config.Entrance.Enabled { if config.Entrance.Enabled {
entranceServer = entranceserver.NewServer( entranceServer = entranceserver.NewServer(
&entranceserver.Config{ &entranceserver.Config{
Logger: logger.Named("entrance"), Logger: entranceLogger,
ErupeConfig: _config.ErupeConfig, ErupeConfig: _config.ErupeConfig,
DB: db, DB: db,
}) })
@@ -157,18 +165,16 @@ func main() {
if err != nil { if err != nil {
preventClose(fmt.Sprintf("Entrance: Failed to start, %s", err.Error())) preventClose(fmt.Sprintf("Entrance: Failed to start, %s", err.Error()))
} }
logger.Info("Entrance: Started successfully") mainLogger.Info("Entrance: Started successfully")
} else { } else {
logger.Info("Entrance: Disabled") mainLogger.Info("Entrance: Disabled")
} }
// Sign server. // Sign server.
var signServer *signserver.Server var signServer *signserver.Server
if config.Sign.Enabled { if config.Sign.Enabled {
signServer = signserver.NewServer( signServer = signserver.NewServer(
&signserver.Config{ &signserver.Config{
Logger: logger.Named("sign"),
ErupeConfig: _config.ErupeConfig, ErupeConfig: _config.ErupeConfig,
DB: db, DB: db,
}) })
@@ -176,17 +182,16 @@ func main() {
if err != nil { if err != nil {
preventClose(fmt.Sprintf("Sign: Failed to start, %s", err.Error())) preventClose(fmt.Sprintf("Sign: Failed to start, %s", err.Error()))
} }
logger.Info("Sign: Started successfully") mainLogger.Info("Sign: Started successfully")
} else { } else {
logger.Info("Sign: Disabled") mainLogger.Info("Sign: Disabled")
} }
// New Sign server // Api server
var ApiServer *api.APIServer var ApiServer *api.APIServer
if config.API.Enabled { if config.API.Enabled {
ApiServer = api.NewAPIServer( ApiServer = api.NewAPIServer(
&api.Config{ &api.Config{
Logger: logger.Named("sign"),
ErupeConfig: _config.ErupeConfig, ErupeConfig: _config.ErupeConfig,
DB: db, DB: db,
}) })
@@ -194,13 +199,12 @@ func main() {
if err != nil { if err != nil {
preventClose(fmt.Sprintf("API: Failed to start, %s", err.Error())) preventClose(fmt.Sprintf("API: Failed to start, %s", err.Error()))
} }
logger.Info("API: Started successfully") mainLogger.Info("API: Started successfully")
} else { } else {
logger.Info("API: Disabled") mainLogger.Info("API: Disabled")
} }
var channelServers []*channelserver.Server var channelServers []*channelserver.Server
if config.Channel.Enabled { if config.Channel.Enabled {
channelQuery := "" channelQuery := ""
si := 0 si := 0
@@ -211,7 +215,6 @@ func main() {
sid := (4096 + si*256) + (16 + ci) sid := (4096 + si*256) + (16 + ci)
c := *channelserver.NewServer(&channelserver.Config{ c := *channelserver.NewServer(&channelserver.Config{
ID: uint16(sid), ID: uint16(sid),
Logger: logger.Named("channel-" + fmt.Sprint(count)),
ErupeConfig: _config.ErupeConfig, ErupeConfig: _config.ErupeConfig,
DB: db, DB: db,
DiscordBot: discordBot, DiscordBot: discordBot,
@@ -229,7 +232,7 @@ func main() {
} else { } 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) 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) 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++ ci++
count++ 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. // Wait for exit or interrupt with ctrl+C.
c := make(chan os.Signal, 1) c := make(chan os.Signal, 1)
@@ -259,7 +262,7 @@ func main() {
for _, channelServer := range channelServers { for _, channelServer := range channelServers {
channelServer.BroadcastChatMessage(message) channelServer.BroadcastChatMessage(message)
} }
logger.Info(message) mainLogger.Warn(message)
time.Sleep(time.Second) time.Sleep(time.Second)
} }
} }
@@ -295,9 +298,8 @@ func preventClose(text string) {
if _config.ErupeConfig.DisableSoftCrash { if _config.ErupeConfig.DisableSoftCrash {
os.Exit(0) os.Exit(0)
} }
fmt.Println("\nFailed to start Erupe:\n" + text) mainLogger.Error(fmt.Sprintf(("\nFailed to start Erupe:\n" + text)))
go wait() go wait()
fmt.Println("\nPress Enter/Return to exit...") mainLogger.Error(fmt.Sprintf(("\nPress Enter/Return to exit...")))
fmt.Scanln()
os.Exit(0) os.Exit(0)
} }

View File

@@ -9,6 +9,8 @@ import (
"sync" "sync"
"time" "time"
"erupe-ce/utils/logger"
"github.com/gorilla/handlers" "github.com/gorilla/handlers"
"github.com/gorilla/mux" "github.com/gorilla/mux"
"github.com/jmoiron/sqlx" "github.com/jmoiron/sqlx"
@@ -16,7 +18,6 @@ import (
) )
type Config struct { type Config struct {
Logger *zap.Logger
DB *sqlx.DB DB *sqlx.DB
ErupeConfig *_config.Config ErupeConfig *_config.Config
} }
@@ -24,7 +25,7 @@ type Config struct {
// APIServer is Erupes Standard API interface // APIServer is Erupes Standard API interface
type APIServer struct { type APIServer struct {
sync.Mutex sync.Mutex
logger *zap.Logger logger logger.Logger
erupeConfig *_config.Config erupeConfig *_config.Config
db *sqlx.DB db *sqlx.DB
httpServer *http.Server httpServer *http.Server
@@ -33,8 +34,9 @@ type APIServer struct {
// NewAPIServer creates a new Server type. // NewAPIServer creates a new Server type.
func NewAPIServer(config *Config) *APIServer { func NewAPIServer(config *Config) *APIServer {
s := &APIServer{ s := &APIServer{
logger: config.Logger, logger: logger.Get().Named("API"),
erupeConfig: config.ErupeConfig, erupeConfig: config.ErupeConfig,
db: config.DB, db: config.DB,
httpServer: &http.Server{}, httpServer: &http.Server{},

View File

@@ -7,9 +7,12 @@ import (
"erupe-ce/network/binpacket" "erupe-ce/network/binpacket"
"erupe-ce/network/mhfpacket" "erupe-ce/network/mhfpacket"
"erupe-ce/utils/byteframe" "erupe-ce/utils/byteframe"
"erupe-ce/utils/logger"
"erupe-ce/utils/mhfcid" "erupe-ce/utils/mhfcid"
"erupe-ce/utils/mhfcourse" "erupe-ce/utils/mhfcourse"
"erupe-ce/utils/token" "erupe-ce/utils/token"
"sync"
"fmt" "fmt"
"math" "math"
"strconv" "strconv"
@@ -39,24 +42,27 @@ const (
BroadcastTypeWorld = 0x0a 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 init() { func (server *Server) initCommands() {
commands = make(map[string]_config.Command) once.Do(func() {
zapConfig := zap.NewDevelopmentConfig() commands = make(map[string]_config.Command)
zapConfig.DisableCaller = true
zapLogger, _ := zapConfig.Build() commandLogger := logger.Get().Named("command")
defer zapLogger.Sync() cmds := _config.ErupeConfig.Commands
logger := zapLogger.Named("commands") for _, cmd := range cmds {
cmds := _config.ErupeConfig.Commands commands[cmd.Name] = cmd
for _, cmd := range cmds { if cmd.Enabled {
commands[cmd.Name] = cmd commandLogger.Info(fmt.Sprintf("%s: Enabled, prefix: %s", cmd.Name, cmd.Prefix))
if cmd.Enabled { } else {
logger.Info(fmt.Sprintf("Command %s: Enabled, prefix: %s", cmd.Name, cmd.Prefix)) commandLogger.Info(fmt.Sprintf("%s: Disabled", cmd.Name))
} else { }
logger.Info(fmt.Sprintf("Command %s: Disabled", cmd.Name))
} }
} })
} }
func sendDisabledCommandMessage(s *Session, cmd _config.Command) { func sendDisabledCommandMessage(s *Session, cmd _config.Command) {

View File

@@ -9,6 +9,7 @@ import (
_config "erupe-ce/config" _config "erupe-ce/config"
"erupe-ce/server/discordbot" "erupe-ce/server/discordbot"
"erupe-ce/utils/gametime" "erupe-ce/utils/gametime"
"erupe-ce/utils/logger"
"github.com/jmoiron/sqlx" "github.com/jmoiron/sqlx"
"go.uber.org/zap" "go.uber.org/zap"
@@ -17,7 +18,6 @@ import (
// Config struct allows configuring the server. // Config struct allows configuring the server.
type Config struct { type Config struct {
ID uint16 ID uint16
Logger *zap.Logger
DB *sqlx.DB DB *sqlx.DB
DiscordBot *discordbot.DiscordBot DiscordBot *discordbot.DiscordBot
ErupeConfig *_config.Config ErupeConfig *_config.Config
@@ -39,7 +39,7 @@ type Server struct {
GlobalID string GlobalID string
IP string IP string
Port uint16 Port uint16
logger *zap.Logger logger logger.Logger
db *sqlx.DB db *sqlx.DB
erupeConfig *_config.Config erupeConfig *_config.Config
acceptConns chan net.Conn acceptConns chan net.Conn
@@ -92,7 +92,7 @@ func NewServer(config *Config) *Server {
} }
server := &Server{ server := &Server{
ID: config.ID, ID: config.ID,
logger: config.Logger, logger: logger.Get().Named("channel-" + fmt.Sprint(config.ID)),
db: config.DB, db: config.DB,
erupeConfig: config.ErupeConfig, erupeConfig: config.ErupeConfig,
acceptConns: make(chan net.Conn), acceptConns: make(chan net.Conn),
@@ -114,9 +114,9 @@ func NewServer(config *Config) *Server {
questCacheData: make(map[int][]byte), questCacheData: make(map[int][]byte),
questCacheTime: make(map[int]time.Time), questCacheTime: make(map[int]time.Time),
} }
server.initCommands()
server.i18n = getLangStrings(server) server.i18n = getLangStrings(server)
return server return server
} }

View File

@@ -15,6 +15,7 @@ import (
"erupe-ce/network" "erupe-ce/network"
"erupe-ce/network/mhfpacket" "erupe-ce/network/mhfpacket"
"erupe-ce/utils/byteframe" "erupe-ce/utils/byteframe"
"erupe-ce/utils/logger"
"erupe-ce/utils/stringstack" "erupe-ce/utils/stringstack"
"go.uber.org/zap" "go.uber.org/zap"
@@ -23,7 +24,7 @@ import (
// Session holds state for the channel server connection. // Session holds state for the channel server connection.
type Session struct { type Session struct {
sync.Mutex sync.Mutex
logger *zap.Logger logger logger.Logger
server *Server server *Server
rawConn net.Conn rawConn net.Conn
cryptConn *network.CryptConn cryptConn *network.CryptConn

View File

@@ -2,6 +2,7 @@ package discordbot
import ( import (
_config "erupe-ce/config" _config "erupe-ce/config"
"erupe-ce/utils/logger"
"regexp" "regexp"
"github.com/bwmarrin/discordgo" "github.com/bwmarrin/discordgo"
@@ -38,21 +39,20 @@ var Commands = []*discordgo.ApplicationCommand{
type DiscordBot struct { type DiscordBot struct {
Session *discordgo.Session Session *discordgo.Session
config *_config.Config config *_config.Config
logger *zap.Logger logger logger.Logger
MainGuild *discordgo.Guild MainGuild *discordgo.Guild
RelayChannel *discordgo.Channel RelayChannel *discordgo.Channel
} }
type Options struct { type Options struct {
Config *_config.Config Config *_config.Config
Logger *zap.Logger
} }
func NewDiscordBot(options Options) (discordBot *DiscordBot, err error) { func NewDiscordBot(options Options) (discordBot *DiscordBot, err error) {
session, err := discordgo.New("Bot " + options.Config.Discord.BotToken) session, err := discordgo.New("Bot " + options.Config.Discord.BotToken)
discordLogger := logger.Get().Named("discord")
if err != nil { if err != nil {
options.Logger.Fatal("Discord failed", zap.Error(err)) discordLogger.Fatal("Discord failed", zap.Error(err))
return nil, err return nil, err
} }
@@ -63,13 +63,13 @@ func NewDiscordBot(options Options) (discordBot *DiscordBot, err error) {
} }
if err != nil { 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 return nil, err
} }
discordBot = &DiscordBot{ discordBot = &DiscordBot{
config: options.Config, config: options.Config,
logger: options.Logger, logger: discordLogger,
Session: session, Session: session,
RelayChannel: relayChannel, RelayChannel: relayChannel,
} }

View File

@@ -10,6 +10,7 @@ import (
_config "erupe-ce/config" _config "erupe-ce/config"
"erupe-ce/network" "erupe-ce/network"
"erupe-ce/utils/logger"
"github.com/jmoiron/sqlx" "github.com/jmoiron/sqlx"
"go.uber.org/zap" "go.uber.org/zap"
@@ -18,7 +19,7 @@ import (
// Server is a MHF entrance server. // Server is a MHF entrance server.
type Server struct { type Server struct {
sync.Mutex sync.Mutex
logger *zap.Logger logger logger.Logger
erupeConfig *_config.Config erupeConfig *_config.Config
db *sqlx.DB db *sqlx.DB
listener net.Listener listener net.Listener
@@ -27,7 +28,7 @@ type Server struct {
// Config struct allows configuring the server. // Config struct allows configuring the server.
type Config struct { type Config struct {
Logger *zap.Logger Logger logger.Logger
DB *sqlx.DB DB *sqlx.DB
ErupeConfig *_config.Config ErupeConfig *_config.Config
} }

View File

@@ -3,6 +3,7 @@ package signserver
import ( import (
"database/sql" "database/sql"
"encoding/hex" "encoding/hex"
"erupe-ce/utils/logger"
"erupe-ce/utils/stringsupport" "erupe-ce/utils/stringsupport"
"fmt" "fmt"
"net" "net"
@@ -28,7 +29,7 @@ const (
// Session holds state for the sign server connection. // Session holds state for the sign server connection.
type Session struct { type Session struct {
sync.Mutex sync.Mutex
logger *zap.Logger logger logger.Logger
server *Server server *Server
rawConn net.Conn rawConn net.Conn
cryptConn *network.CryptConn cryptConn *network.CryptConn

View File

@@ -8,6 +8,7 @@ import (
_config "erupe-ce/config" _config "erupe-ce/config"
"erupe-ce/network" "erupe-ce/network"
"erupe-ce/utils/logger"
"github.com/jmoiron/sqlx" "github.com/jmoiron/sqlx"
"go.uber.org/zap" "go.uber.org/zap"
@@ -15,7 +16,6 @@ import (
// Config struct allows configuring the server. // Config struct allows configuring the server.
type Config struct { type Config struct {
Logger *zap.Logger
DB *sqlx.DB DB *sqlx.DB
ErupeConfig *_config.Config ErupeConfig *_config.Config
} }
@@ -23,7 +23,7 @@ type Config struct {
// Server is a MHF sign server. // Server is a MHF sign server.
type Server struct { type Server struct {
sync.Mutex sync.Mutex
logger *zap.Logger logger logger.Logger
erupeConfig *_config.Config erupeConfig *_config.Config
sessions map[int]*Session sessions map[int]*Session
db *sqlx.DB db *sqlx.DB
@@ -34,7 +34,7 @@ type Server struct {
// NewServer creates a new Server type. // NewServer creates a new Server type.
func NewServer(config *Config) *Server { func NewServer(config *Config) *Server {
s := &Server{ s := &Server{
logger: config.Logger, logger: logger.Get().Named("sign"),
erupeConfig: config.ErupeConfig, erupeConfig: config.ErupeConfig,
db: config.DB, db: config.DB,
} }

27
utils/logger/logger.go Normal file
View File

@@ -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
}

View File

@@ -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
}

View File

@@ -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)}
}