From c0c6100c17b05ae9e5b176b86a56990adce93091 Mon Sep 17 00:00:00 2001 From: Sky Johnson Date: Sat, 31 May 2025 15:26:06 -0500 Subject: [PATCH] rewrite logger and main --- http/server.go | 12 +- main.go | 400 ---------------------------------------- moonshark.go | 334 ++++++++++++++++++++++++++++++++++ runner/embed.go | 14 +- runner/env.go | 10 +- runner/fs.go | 4 +- runner/http.go | 2 +- runner/moduleLoader.go | 2 +- runner/runner.go | 36 ++-- runner/sandbox.go | 14 +- runner/sqlite.go | 8 +- utils/config/config.go | 5 +- utils/logger/logger.go | 403 +++++++++++++---------------------------- watchers/api.go | 4 +- watchers/dir.go | 4 +- watchers/manager.go | 8 +- 16 files changed, 515 insertions(+), 745 deletions(-) delete mode 100644 main.go create mode 100644 moonshark.go diff --git a/http/server.go b/http/server.go index 49aa185..b6e55fc 100644 --- a/http/server.go +++ b/http/server.go @@ -121,7 +121,7 @@ func New(luaRouter *router.LuaRouter, runner *runner.Runner, cfg *config.Config, } func (s *Server) ListenAndServe(addr string) error { - logger.Info("Catch the swell at %s", color.Cyan("http://localhost"+addr)) + logger.Infof("Catch the swell at %s", color.Cyan("http://localhost"+addr)) return s.fasthttpServer.ListenAndServe(addr) } @@ -137,7 +137,7 @@ func (s *Server) handleRequest(ctx *fasthttp.RequestCtx) { if s.debugMode && bytes.Equal(pathBytes, debugPath) { s.handleDebugStats(ctx) if s.cfg.Server.HTTPLogging { - logger.LogRequest(ctx.Response.StatusCode(), string(methodBytes), string(pathBytes), time.Since(start)) + logger.Request(ctx.Response.StatusCode(), string(methodBytes), string(pathBytes), time.Since(start)) } return } @@ -145,7 +145,7 @@ func (s *Server) handleRequest(ctx *fasthttp.RequestCtx) { if s.staticHandler != nil && bytes.HasPrefix(pathBytes, s.staticPrefixBytes) { s.staticHandler(ctx) if s.cfg.Server.HTTPLogging { - logger.LogRequest(ctx.Response.StatusCode(), string(methodBytes), string(pathBytes), time.Since(start)) + logger.Request(ctx.Response.StatusCode(), string(methodBytes), string(pathBytes), time.Since(start)) } return } @@ -163,7 +163,7 @@ func (s *Server) handleRequest(ctx *fasthttp.RequestCtx) { } if s.cfg.Server.HTTPLogging { - logger.LogRequest(ctx.Response.StatusCode(), string(methodBytes), string(pathBytes), time.Since(start)) + logger.Request(ctx.Response.StatusCode(), string(methodBytes), string(pathBytes), time.Since(start)) } } @@ -233,7 +233,7 @@ func (s *Server) handleLuaRoute(ctx *fasthttp.RequestCtx, bytecode []byte, scrip luaCtx.Set("form", formData) } else { if s.debugMode { - logger.Warning("Error parsing form: %v", err) + logger.Warnf("Error parsing form: %v", err) } luaCtx.Set("form", emptyMap) } @@ -243,7 +243,7 @@ func (s *Server) handleLuaRoute(ctx *fasthttp.RequestCtx, bytecode []byte, scrip response, err := s.luaRunner.Run(bytecode, luaCtx, scriptPath) if err != nil { - logger.Error("Lua execution error: %v", err) + logger.Errorf("Lua execution error: %v", err) s.sendError(ctx, fasthttp.StatusInternalServerError, pathBytes, err) return } diff --git a/main.go b/main.go deleted file mode 100644 index e92efe9..0000000 --- a/main.go +++ /dev/null @@ -1,400 +0,0 @@ -package main - -import ( - "context" - "errors" - "flag" - "fmt" - "os" - "os/signal" - "path/filepath" - "strconv" - "syscall" - "time" - - "Moonshark/http" - "Moonshark/router" - "Moonshark/runner" - "Moonshark/sessions" - "Moonshark/utils/color" - "Moonshark/utils/config" - "Moonshark/utils/logger" - "Moonshark/utils/metadata" - "Moonshark/watchers" - - fin "git.sharkk.net/Sharkk/Fin" -) - -// Moonshark represents the server and all its dependencies -type Moonshark struct { - Config *config.Config - LuaRouter *router.LuaRouter - LuaRunner *runner.Runner - HTTPServer *http.Server - cleanupFuncs []func() error - scriptMode bool -} - -func main() { - configPath := flag.String("config", "config", "Path to configuration file") - debugFlag := flag.Bool("debug", false, "Enable debug mode") - scriptPath := flag.String("script", "", "Path to Lua script to execute once") - flag.Parse() - scriptMode := *scriptPath != "" - - color.SetColors(color.DetectShellColors()) - banner(scriptMode) - cfg := config.New(readConfig(*configPath)) - - if *debugFlag || cfg.Server.Debug { - logger.EnableDebug() - logger.Debug("Debug logging enabled") - } - - var moonshark *Moonshark - var err error - - if scriptMode { - moonshark, err = initScriptMode(cfg) - } else { - moonshark, err = initServerMode(cfg, *debugFlag || cfg.Server.Debug) - } - - if err != nil { - logger.Fatal("Initialization failed: %v", err) - } - - defer func() { - if err := moonshark.Shutdown(); err != nil { - logger.Error("Error during shutdown: %v", err) - os.Exit(1) - } - }() - - if scriptMode { - // Run the script and exit - if err := moonshark.RunScript(*scriptPath); err != nil { - logger.Fatal("Script execution failed: %v", err) - } - return - } - - // Start the server - if err := moonshark.Start(); err != nil { - logger.Fatal("Failed to start server: %v", err) - } - - // Wait for shutdown signal - stop := make(chan os.Signal, 1) - signal.Notify(stop, os.Interrupt, syscall.SIGTERM) - <-stop - - fmt.Print("\n") - logger.Info("Shutdown signal received") -} - -// initScriptMode initializes minimal components needed for script execution -func initScriptMode(cfg *config.Config) (*Moonshark, error) { - moonshark := &Moonshark{ - Config: cfg, - scriptMode: true, - } - - // Only initialize the Lua runner with required paths - runnerOpts := []runner.RunnerOption{ - runner.WithPoolSize(1), // Only need one state for script mode - runner.WithLibDirs(cfg.Dirs.Libs...), - runner.WithFsDir(cfg.Dirs.FS), - runner.WithDataDir(cfg.Dirs.Data), - } - - var err error - moonshark.LuaRunner, err = runner.NewRunner(runnerOpts...) - if err != nil { - return nil, fmt.Errorf("failed to initialize Lua runner: %v", err) - } - - logger.Debug("Script mode initialized with minimized components") - return moonshark, nil -} - -// initServerMode initializes all components needed for server operation -func initServerMode(cfg *config.Config, debug bool) (*Moonshark, error) { - moonshark := &Moonshark{ - Config: cfg, - scriptMode: false, - } - - if debug { - cfg.Server.Debug = true - } - - if err := initLuaRouter(moonshark); err != nil { - return nil, err - } - - if err := initRunner(moonshark); err != nil { - return nil, err - } - - if err := setupWatchers(moonshark); err != nil { - logger.Warning("Watcher setup failed: %v", err) - } - - // Get static directory - empty string if it doesn't exist - staticDir := "" - if dirExists(cfg.Dirs.Static) { - staticDir = cfg.Dirs.Static - logger.Info("Static files enabled: %s", color.Yellow(staticDir)) - } else { - logger.Warning("Static directory not found: %s", color.Yellow(cfg.Dirs.Static)) - } - - moonshark.HTTPServer = http.New( - moonshark.LuaRouter, - moonshark.LuaRunner, - cfg, - debug, - ) - - // For development, disable caching. For production, enable it - if cfg.Server.Debug { - moonshark.HTTPServer.SetStaticCaching(0) // No caching in debug mode - } else { - moonshark.HTTPServer.SetStaticCaching(1 * time.Hour) // Cache for 1 hour in production - } - - return moonshark, nil -} - -// RunScript executes a Lua script in the sandbox environment -func (s *Moonshark) RunScript(scriptPath string) error { - scriptPath, err := filepath.Abs(scriptPath) - if err != nil { - return fmt.Errorf("failed to resolve script path: %v", err) - } - - if _, err := os.Stat(scriptPath); os.IsNotExist(err) { - return fmt.Errorf("script file not found: %s", scriptPath) - } - - logger.Info("Executing: %s", scriptPath) - - resp, err := s.LuaRunner.RunScriptFile(scriptPath) - if err != nil { - return fmt.Errorf("execution failed: %v", err) - } - - if resp != nil && resp.Body != nil { - logger.Info("Script result: %v", resp.Body) - } else { - logger.Info("Script executed successfully (no return value)") - } - - return nil -} - -// Start starts the HTTP server -func (s *Moonshark) Start() error { - if s.scriptMode { - return errors.New("cannot start server in script mode") - } - - logger.Info("Surf's up on port %s!", color.Cyan(strconv.Itoa(s.Config.Server.Port))) - - go func() { - if err := s.HTTPServer.ListenAndServe(fmt.Sprintf(":%d", s.Config.Server.Port)); err != nil { - if err.Error() != "http: Server closed" { - logger.Error("Server error: %v", err) - } - } - }() - - return nil -} - -// Shutdown gracefully shuts down Moonshark -func (s *Moonshark) Shutdown() error { - logger.Info("Shutting down...") - - if !s.scriptMode && s.HTTPServer != nil { - ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) - defer cancel() - - if err := s.HTTPServer.Shutdown(ctx); err != nil { - logger.Error("HTTP server shutdown error: %v", err) - } - } - - for _, cleanup := range s.cleanupFuncs { - if err := cleanup(); err != nil { - logger.Warning("Cleanup error: %v", err) - } - } - - if s.LuaRunner != nil { - s.LuaRunner.Close() - } - - if err := runner.CleanupEnv(); err != nil { - logger.Warning("Environment cleanup failed: %v", err) - } - - logger.Info("Shutdown complete") - return nil -} - -func dirExists(path string) bool { - info, err := os.Stat(path) - if err != nil { - return false - } - return info.IsDir() -} - -func initLuaRouter(s *Moonshark) error { - if !dirExists(s.Config.Dirs.Routes) { - return fmt.Errorf("routes directory doesn't exist: %s", s.Config.Dirs.Routes) - } - - var err error - s.LuaRouter, err = router.NewLuaRouter(s.Config.Dirs.Routes) - if err != nil { - if errors.Is(err, router.ErrRoutesCompilationErrors) { - // Non-fatal, some routes failed - logger.Warning("Some routes failed to compile") - - if failedRoutes := s.LuaRouter.ReportFailedRoutes(); len(failedRoutes) > 0 { - for _, re := range failedRoutes { - logger.Error("Route %s %s: %v", re.Method, re.Path, re.Err) - } - } - } else { - return fmt.Errorf("lua router init failed: %v", err) - } - } - logger.Info("LuaRouter is g2g! %s", color.Yellow(s.Config.Dirs.Routes)) - - return nil -} - -func initRunner(s *Moonshark) error { - if !dirExists(s.Config.Dirs.Override) { - logger.Warning("Override directory not found... %s", color.Yellow(s.Config.Dirs.Override)) - s.Config.Dirs.Override = "" - } - - for _, dir := range s.Config.Dirs.Libs { - if !dirExists(dir) { - logger.Warning("Lib directory not found... %s", color.Yellow(dir)) - } - } - - // Initialize environment manager - if err := runner.InitEnv(s.Config.Dirs.Data); err != nil { - logger.Warning("Environment initialization failed: %v", err) - } - - sessionManager := sessions.GlobalSessionManager - sessionManager.SetCookieOptions( - "MoonsharkSID", - "/", - "", - false, - true, - 86400, - ) - - poolSize := s.Config.Runner.PoolSize - if s.scriptMode { - poolSize = 1 // Only need one state for script mode - } - - runnerOpts := []runner.RunnerOption{ - runner.WithPoolSize(poolSize), - runner.WithLibDirs(s.Config.Dirs.Libs...), - runner.WithFsDir(s.Config.Dirs.FS), - runner.WithDataDir(s.Config.Dirs.Data), - } - - var err error - s.LuaRunner, err = runner.NewRunner(runnerOpts...) - if err != nil { - return fmt.Errorf("lua runner init failed: %v", err) - } - - logger.Info("LuaRunner is g2g with %s states!", color.Yellow(strconv.Itoa(poolSize))) - return nil -} - -func setupWatchers(s *Moonshark) error { - manager := watchers.GetWatcherManager() - - // Watch routes directory - routeWatcher, err := watchers.WatchLuaRouter(s.LuaRouter, s.LuaRunner, s.Config.Dirs.Routes) - if err != nil { - logger.Warning("Routes directory watch failed: %v", err) - } else { - routesDir := routeWatcher.GetDir() - s.cleanupFuncs = append(s.cleanupFuncs, func() error { - return manager.UnwatchDirectory(routesDir) - }) - } - - // Watch module directories - moduleWatchers, err := watchers.WatchLuaModules(s.LuaRunner, s.Config.Dirs.Libs) - if err != nil { - logger.Warning("Module directories watch failed: %v", err) - } else { - for _, watcher := range moduleWatchers { - dirPath := watcher.GetDir() - s.cleanupFuncs = append(s.cleanupFuncs, func() error { - return manager.UnwatchDirectory(dirPath) - }) - } - plural := "" - if len(moduleWatchers) == 1 { - plural = "directory" - } else { - plural = "directories" - } - logger.Info("Watching %s module %s.", color.Yellow(strconv.Itoa(len(moduleWatchers))), plural) - } - - return nil -} - -func banner(scriptMode bool) { - if scriptMode { - fmt.Println(color.Blue(fmt.Sprintf("Moonshark %s << Script Mode >>", metadata.Version))) - return - } - - banner := ` - _____ _________.__ __ - / \ ____ ____ ____ / _____/| |__ _____ _______| | __ - / \ / \ / _ \ / _ \ / \ \_____ \ | | \\__ \\_ __ \ |/ / -/ Y ( <_> | <_> ) | \/ \| Y \/ __ \| | \/ < -\____|__ /\____/ \____/|___| /_______ /|___| (____ /__| |__|_ \ %s - \/ \/ \/ \/ \/ \/ - ` - fmt.Println(color.Blue(fmt.Sprintf(banner, metadata.Version))) -} - -// readConfig attempts to read config data from a Fin file -func readConfig(path string) *fin.Data { - file, err := os.Open(path) - if err != nil { - logger.Error("Failed to open config file %s", color.Yellow(path)) - cfg, _ := fin.Load(nil) - return cfg - } - defer file.Close() - - cfg, err := fin.Load(file) - if err != nil { - logger.Warning("Config load failed: %v, using defaults", color.Red(err.Error())) - } - - return cfg -} diff --git a/moonshark.go b/moonshark.go new file mode 100644 index 0000000..37f793e --- /dev/null +++ b/moonshark.go @@ -0,0 +1,334 @@ +package main + +import ( + "context" + "errors" + "flag" + "fmt" + "os" + "os/signal" + "path/filepath" + "strconv" + "syscall" + "time" + + "Moonshark/http" + "Moonshark/router" + "Moonshark/runner" + "Moonshark/sessions" + "Moonshark/utils/color" + "Moonshark/utils/config" + "Moonshark/utils/logger" + "Moonshark/utils/metadata" + "Moonshark/watchers" + + fin "git.sharkk.net/Sharkk/Fin" +) + +type Moonshark struct { + Config *config.Config + LuaRouter *router.LuaRouter + LuaRunner *runner.Runner + HTTPServer *http.Server + cleanupFuncs []func() error + scriptMode bool +} + +func main() { + configPath := flag.String("config", "config", "Path to configuration file") + debugFlag := flag.Bool("debug", false, "Enable debug mode") + scriptPath := flag.String("script", "", "Path to Lua script to execute once") + flag.Parse() + + scriptMode := *scriptPath != "" + color.SetColors(color.DetectShellColors()) + banner(scriptMode) + + cfg := config.New(readConfig(*configPath)) + debug := *debugFlag || cfg.Server.Debug + logger.Debug(debug) + + if debug { + logger.Debugf("Debug logging enabled") + } + + moonshark, err := newMoonshark(cfg, debug, scriptMode) + if err != nil { + logger.Fatalf("Initialization failed: %v", err) + } + + defer func() { + if err := moonshark.Shutdown(); err != nil { + logger.Errorf("Error during shutdown: %v", err) + os.Exit(1) + } + }() + + if scriptMode { + if err := moonshark.RunScript(*scriptPath); err != nil { + logger.Fatalf("Script execution failed: %v", err) + } + return + } + + if err := moonshark.Start(); err != nil { + logger.Fatalf("Failed to start server: %v", err) + } + + stop := make(chan os.Signal, 1) + signal.Notify(stop, os.Interrupt, syscall.SIGTERM) + <-stop + + fmt.Print("\n") + logger.Infof("Shutdown signal received") +} + +func newMoonshark(cfg *config.Config, debug, scriptMode bool) (*Moonshark, error) { + s := &Moonshark{Config: cfg, scriptMode: scriptMode} + + if debug { + cfg.Server.Debug = true + } + + poolSize := cfg.Runner.PoolSize + if scriptMode { + poolSize = 1 + } + + // Initialize runner first (needed for both modes) + if err := s.initRunner(poolSize); err != nil { + return nil, err + } + + if scriptMode { + logger.Debugf("Script mode initialized") + return s, nil + } + + // Server mode: initialize router, watchers, and HTTP server + if err := s.initRouter(); err != nil { + return nil, err + } + + s.setupWatchers() + + s.HTTPServer = http.New(s.LuaRouter, s.LuaRunner, cfg, debug) + + // Set caching based on debug mode + if cfg.Server.Debug { + s.HTTPServer.SetStaticCaching(0) + } else { + s.HTTPServer.SetStaticCaching(time.Hour) + } + + // Log static directory status + if dirExists(cfg.Dirs.Static) { + logger.Infof("Static files enabled: %s", color.Yellow(cfg.Dirs.Static)) + } else { + logger.Warnf("Static directory not found: %s", color.Yellow(cfg.Dirs.Static)) + } + + return s, nil +} + +func (s *Moonshark) initRunner(poolSize int) error { + // Warn about missing directories but continue + if !dirExists(s.Config.Dirs.Override) { + logger.Warnf("Override directory not found... %s", color.Yellow(s.Config.Dirs.Override)) + s.Config.Dirs.Override = "" + } + + for _, dir := range s.Config.Dirs.Libs { + if !dirExists(dir) { + logger.Warnf("Lib directory not found... %s", color.Yellow(dir)) + } + } + + if err := runner.InitEnv(s.Config.Dirs.Data); err != nil { + logger.Warnf("Environment initialization failed: %v", err) + } + + sessions.GlobalSessionManager.SetCookieOptions("MoonsharkSID", "/", "", false, true, 86400) + + var err error + s.LuaRunner, err = runner.NewRunner( + runner.WithPoolSize(poolSize), + runner.WithLibDirs(s.Config.Dirs.Libs...), + runner.WithFsDir(s.Config.Dirs.FS), + runner.WithDataDir(s.Config.Dirs.Data), + ) + if err != nil { + return fmt.Errorf("lua runner init failed: %v", err) + } + + logger.Infof("LuaRunner is g2g with %s states!", color.Yellow(strconv.Itoa(poolSize))) + return nil +} + +func (s *Moonshark) initRouter() error { + if err := os.MkdirAll(s.Config.Dirs.Routes, 0755); err != nil { + return fmt.Errorf("failed to create routes directory: %w", err) + } + + var err error + s.LuaRouter, err = router.NewLuaRouter(s.Config.Dirs.Routes) + if err != nil { + if errors.Is(err, router.ErrRoutesCompilationErrors) { + logger.Warnf("Some routes failed to compile") + if failedRoutes := s.LuaRouter.ReportFailedRoutes(); len(failedRoutes) > 0 { + for _, re := range failedRoutes { + logger.Errorf("Route %s %s: %v", re.Method, re.Path, re.Err) + } + } + } else { + return fmt.Errorf("lua router init failed: %v", err) + } + } + + logger.Infof("LuaRouter is g2g! %s", color.Yellow(s.Config.Dirs.Routes)) + return nil +} + +func (s *Moonshark) setupWatchers() { + manager := watchers.GetWatcherManager() + + // Watch routes + if routeWatcher, err := watchers.WatchLuaRouter(s.LuaRouter, s.LuaRunner, s.Config.Dirs.Routes); err != nil { + logger.Warnf("Routes directory watch failed: %v", err) + } else { + routesDir := routeWatcher.GetDir() + s.cleanupFuncs = append(s.cleanupFuncs, func() error { + return manager.UnwatchDirectory(routesDir) + }) + } + + // Watch modules + if moduleWatchers, err := watchers.WatchLuaModules(s.LuaRunner, s.Config.Dirs.Libs); err != nil { + logger.Warnf("Module directories watch failed: %v", err) + } else { + for _, watcher := range moduleWatchers { + dirPath := watcher.GetDir() + s.cleanupFuncs = append(s.cleanupFuncs, func() error { + return manager.UnwatchDirectory(dirPath) + }) + } + + plural := "directory" + if len(moduleWatchers) != 1 { + plural = "directories" + } + logger.Infof("Watching %s module %s.", color.Yellow(strconv.Itoa(len(moduleWatchers))), plural) + } +} + +func (s *Moonshark) RunScript(scriptPath string) error { + scriptPath, err := filepath.Abs(scriptPath) + if err != nil { + return fmt.Errorf("failed to resolve script path: %v", err) + } + + if _, err := os.Stat(scriptPath); os.IsNotExist(err) { + return fmt.Errorf("script file not found: %s", scriptPath) + } + + logger.Infof("Executing: %s", scriptPath) + + resp, err := s.LuaRunner.RunScriptFile(scriptPath) + if err != nil { + return fmt.Errorf("execution failed: %v", err) + } + + if resp != nil && resp.Body != nil { + logger.Infof("Script result: %v", resp.Body) + } else { + logger.Infof("Script executed successfully (no return value)") + } + + return nil +} + +func (s *Moonshark) Start() error { + if s.scriptMode { + return errors.New("cannot start server in script mode") + } + + logger.Infof("Surf's up on port %s!", color.Cyan(strconv.Itoa(s.Config.Server.Port))) + + go func() { + if err := s.HTTPServer.ListenAndServe(fmt.Sprintf(":%d", s.Config.Server.Port)); err != nil { + if err.Error() != "http: Server closed" { + logger.Errorf("Server error: %v", err) + } + } + }() + + return nil +} + +func (s *Moonshark) Shutdown() error { + logger.Infof("Shutting down...") + + if !s.scriptMode && s.HTTPServer != nil { + ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) + defer cancel() + + if err := s.HTTPServer.Shutdown(ctx); err != nil { + logger.Errorf("HTTP server shutdown error: %v", err) + } + } + + for _, cleanup := range s.cleanupFuncs { + if err := cleanup(); err != nil { + logger.Warnf("Cleanup error: %v", err) + } + } + + if s.LuaRunner != nil { + s.LuaRunner.Close() + } + + if err := runner.CleanupEnv(); err != nil { + logger.Warnf("Environment cleanup failed: %v", err) + } + + logger.Infof("Shutdown complete") + return nil +} + +func dirExists(path string) bool { + info, err := os.Stat(path) + return err == nil && info.IsDir() +} + +func banner(scriptMode bool) { + if scriptMode { + fmt.Println(color.Blue(fmt.Sprintf("Moonshark %s << Script Mode >>", metadata.Version))) + return + } + + banner := ` + _____ _________.__ __ + / \ ____ ____ ____ / _____/| |__ _____ _______| | __ + / \ / \ / _ \ / _ \ / \ \_____ \ | | \\__ \\_ __ \ |/ / +/ Y ( <_> | <_> ) | \/ \| Y \/ __ \| | \/ < +\____|__ /\____/ \____/|___| /_______ /|___| (____ /__| |__|_ \ %s + \/ \/ \/ \/ \/ \/ + ` + fmt.Println(color.Blue(fmt.Sprintf(banner, metadata.Version))) +} + +func readConfig(path string) *fin.Data { + file, err := os.Open(path) + if err != nil { + logger.Errorf("Failed to open config file %s, using defaults", color.Yellow(path)) + return fin.NewData() + } + defer file.Close() + + cfg, err := fin.Load(file) + if err != nil { + logger.Errorf("Failed to load config file %s, using defaults", color.Yellow(path)) + } + + return cfg +} diff --git a/runner/embed.go b/runner/embed.go index da9a2f0..af2dcc9 100644 --- a/runner/embed.go +++ b/runner/embed.go @@ -73,7 +73,7 @@ func precompileModule(m *ModuleInfo) { m.Once.Do(func() { tempState := luajit.New() if tempState == nil { - logger.Fatal("Failed to create temp Lua state for %s module compilation", m.Name) + logger.Fatalf("Failed to create temp Lua state for %s module compilation", m.Name) return } defer tempState.Close() @@ -81,7 +81,7 @@ func precompileModule(m *ModuleInfo) { code, err := tempState.CompileBytecode(m.Code, m.Name+".lua") if err != nil { - logger.Error("Failed to compile %s module: %v", m.Name, err) + logger.Errorf("Failed to compile %s module: %v", m.Name, err) return } @@ -89,7 +89,7 @@ func precompileModule(m *ModuleInfo) { copy(bytecode, code) m.Bytecode.Store(&bytecode) - logger.Debug("Successfully precompiled %s.lua to bytecode (%d bytes)", m.Name, len(code)) + logger.Debugf("Successfully precompiled %s.lua to bytecode (%d bytes)", m.Name, len(code)) }) } @@ -102,7 +102,7 @@ func loadModule(state *luajit.State, m *ModuleInfo, verbose bool) error { bytecode := m.Bytecode.Load() if bytecode != nil && len(*bytecode) > 0 { if verbose { - logger.Debug("Loading %s.lua from precompiled bytecode", m.Name) + logger.Debugf("Loading %s.lua from precompiled bytecode", m.Name) } if err := state.LoadBytecode(*bytecode, m.Name+".lua"); err != nil { @@ -124,7 +124,7 @@ func loadModule(state *luajit.State, m *ModuleInfo, verbose bool) error { } else { // Fallback to interpreting the source if verbose { - logger.Warning("Using non-precompiled %s.lua", m.Name) + logger.Warnf("Using non-precompiled %s.lua", m.Name) } if err := state.DoString(m.Code); err != nil { @@ -154,13 +154,13 @@ func loadSandboxIntoState(state *luajit.State, verbose bool) error { bytecode := sandbox.Bytecode.Load() if bytecode != nil && len(*bytecode) > 0 { if verbose { - logger.Debug("Loading sandbox.lua from precompiled bytecode") + logger.Debugf("Loading sandbox.lua from precompiled bytecode") } return state.LoadAndRunBytecode(*bytecode, "sandbox.lua") } if verbose { - logger.Warning("Using non-precompiled sandbox.lua") + logger.Warnf("Using non-precompiled sandbox.lua") } return state.DoString(sandboxLuaCode) } diff --git a/runner/env.go b/runner/env.go index b2ded8f..2be9d9a 100644 --- a/runner/env.go +++ b/runner/env.go @@ -45,16 +45,16 @@ func InitEnv(dataDir string) error { // Load existing .env file if it exists if err := globalEnvManager.load(); err != nil { - logger.Warning("Failed to load .env file: %v", err) + logger.Warnf("Failed to load .env file: %v", err) } count := len(globalEnvManager.vars) if count > 0 { - logger.Info("Environment loaded: %s vars from %s", + logger.Infof("Environment loaded: %s vars from %s", color.Yellow(fmt.Sprintf("%d", count)), color.Yellow(envPath)) } else { - logger.Info("Environment initialized: %s", color.Yellow(envPath)) + logger.Infof("Environment initialized: %s", color.Yellow(envPath)) } return nil @@ -95,7 +95,7 @@ func (e *EnvManager) load() error { // Parse key=value parts := strings.SplitN(line, "=", 2) if len(parts) != 2 { - logger.Warning("Invalid .env line %d: %s", lineNum, line) + logger.Warnf("Invalid .env line %d: %s", lineNum, line) continue } @@ -166,7 +166,7 @@ func (e *EnvManager) Save() error { fmt.Fprintf(file, "%s=%s\n", key, strValue) } - logger.Debug("Environment saved: %d vars to %s", len(e.vars), e.envPath) + logger.Debugf("Environment saved: %d vars to %s", len(e.vars), e.envPath) return nil } diff --git a/runner/fs.go b/runner/fs.go index c191bc8..c2e7a28 100644 --- a/runner/fs.go +++ b/runner/fs.go @@ -52,7 +52,7 @@ func InitFS(basePath string) error { // Initialize file cache with 2000 entries (reasonable for most use cases) fileCache = lru.NewLRUCache(2000) - logger.Info("Filesystem is g2g! %s", color.Yellow(fsBasePath)) + logger.Infof("Filesystem is g2g! %s", color.Yellow(fsBasePath)) return nil } @@ -60,7 +60,7 @@ func InitFS(basePath string) error { func CleanupFS() { if fileCache != nil { fileCache.Clear() - logger.Info( + logger.Infof( "File cache cleared - %s hits, %s misses", color.Yellow(fmt.Sprintf("%d", stats.hits)), color.Red(fmt.Sprintf("%d", stats.misses)), diff --git a/runner/http.go b/runner/http.go index 43bc7a1..830bca6 100644 --- a/runner/http.go +++ b/runner/http.go @@ -315,7 +315,7 @@ func generateToken(state *luajit.State) int { // Generate secure random bytes tokenBytes := make([]byte, length) if _, err := rand.Read(tokenBytes); err != nil { - logger.Error("Failed to generate secure token: %v", err) + logger.Errorf("Failed to generate secure token: %v", err) state.PushString("") return 1 // Return empty string on error } diff --git a/runner/moduleLoader.go b/runner/moduleLoader.go index 72bccb9..1880d81 100644 --- a/runner/moduleLoader.go +++ b/runner/moduleLoader.go @@ -59,7 +59,7 @@ func (l *ModuleLoader) SetScriptDir(dir string) { // debugLog logs a message if debug mode is enabled func (l *ModuleLoader) debugLog(format string, args ...interface{}) { if l.debug { - logger.Debug("ModuleLoader "+format, args...) + logger.Debugf("ModuleLoader "+format, args...) } } diff --git a/runner/runner.go b/runner/runner.go index 712645c..f8fddc1 100644 --- a/runner/runner.go +++ b/runner/runner.go @@ -134,7 +134,7 @@ func NewRunner(options ...RunnerOption) (*Runner, error) { // initializeStates creates and initializes all states in the pool func (r *Runner) initializeStates() error { - logger.Info("[LuaRunner] Creating %s states...", color.Yellow(strconv.Itoa(r.poolSize))) + logger.Infof("[LuaRunner] Creating %s states...", color.Yellow(strconv.Itoa(r.poolSize))) for i := range r.poolSize { state, err := r.createState(i) @@ -153,7 +153,7 @@ func (r *Runner) initializeStates() error { func (r *Runner) createState(index int) (*State, error) { verbose := index == 0 if verbose { - logger.Debug("Creating Lua state %d", index) + logger.Debugf("Creating Lua state %d", index) } L := luajit.New() @@ -185,7 +185,7 @@ func (r *Runner) createState(index int) (*State, error) { } if verbose { - logger.Debug("Lua state %d initialized successfully", index) + logger.Debugf("Lua state %d initialized successfully", index) } return &State{ @@ -291,7 +291,7 @@ waitForInUse: } if time.Now().After(timeout) { - logger.Warning("Timeout waiting for states to finish during shutdown, forcing close") + logger.Warnf("Timeout waiting for states to finish during shutdown, forcing close") break } @@ -302,7 +302,7 @@ waitForInUse: for i, state := range r.states { if state != nil { if state.inUse.Load() { - logger.Warning("Force closing state %d that is still in use", i) + logger.Warnf("Force closing state %d that is still in use", i) } state.L.Cleanup() state.L.Close() @@ -313,7 +313,7 @@ waitForInUse: CleanupFS() CleanupSQLite() - logger.Debug("Runner closed") + logger.Debugf("Runner closed") return nil } @@ -326,7 +326,7 @@ func (r *Runner) RefreshStates() error { return ErrRunnerClosed } - logger.Info("Runner is refreshing all states...") + logger.Infof("Runner is refreshing all states...") // Drain all states from the pool for { @@ -354,7 +354,7 @@ waitForInUse: } if time.Now().After(timeout) { - logger.Warning("Timeout waiting for states to finish, forcing refresh") + logger.Warnf("Timeout waiting for states to finish, forcing refresh") break } @@ -365,7 +365,7 @@ waitForInUse: for i, state := range r.states { if state != nil { if state.inUse.Load() { - logger.Warning("Force closing state %d that is still in use", i) + logger.Warnf("Force closing state %d that is still in use", i) } state.L.Cleanup() state.L.Close() @@ -378,21 +378,21 @@ waitForInUse: return err } - logger.Debug("All states refreshed successfully") + logger.Debugf("All states refreshed successfully") return nil } // NotifyFileChanged alerts the runner about file changes func (r *Runner) NotifyFileChanged(filePath string) bool { - logger.Debug("Runner notified of file change: %s", filePath) + logger.Debugf("Runner notified of file change: %s", filePath) module, isModule := r.moduleLoader.GetModuleByPath(filePath) if isModule { - logger.Debug("Refreshing module: %s", module) + logger.Debugf("Refreshing module: %s", module) return r.RefreshModule(module) } - logger.Debug("File change noted but no refresh needed: %s", filePath) + logger.Debugf("File change noted but no refresh needed: %s", filePath) return true } @@ -405,7 +405,7 @@ func (r *Runner) RefreshModule(moduleName string) bool { return false } - logger.Debug("Refreshing module: %s", moduleName) + logger.Debugf("Refreshing module: %s", moduleName) success := true for _, state := range r.states { @@ -416,12 +416,12 @@ func (r *Runner) RefreshModule(moduleName string) bool { // Use the enhanced module loader refresh if err := r.moduleLoader.RefreshModule(state.L, moduleName); err != nil { success = false - logger.Debug("Failed to refresh module %s in state %d: %v", moduleName, state.index, err) + logger.Debugf("Failed to refresh module %s in state %d: %v", moduleName, state.index, err) } } if success { - logger.Debug("Successfully refreshed module: %s", moduleName) + logger.Debugf("Successfully refreshed module: %s", moduleName) } return success @@ -436,7 +436,7 @@ func (r *Runner) RefreshModuleByPath(filePath string) bool { return false } - logger.Debug("Refreshing module by path: %s", filePath) + logger.Debugf("Refreshing module by path: %s", filePath) success := true for _, state := range r.states { @@ -447,7 +447,7 @@ func (r *Runner) RefreshModuleByPath(filePath string) bool { // Use the enhanced module loader refresh by path if err := r.moduleLoader.RefreshModuleByPath(state.L, filePath); err != nil { success = false - logger.Debug("Failed to refresh module at %s in state %d: %v", filePath, state.index, err) + logger.Debugf("Failed to refresh module at %s in state %d: %v", filePath, state.index, err) } } diff --git a/runner/sandbox.go b/runner/sandbox.go index 6fe6c5f..ae0ec65 100644 --- a/runner/sandbox.go +++ b/runner/sandbox.go @@ -46,31 +46,31 @@ func (s *Sandbox) AddModule(name string, module any) { s.mu.Lock() defer s.mu.Unlock() s.modules[name] = module - logger.Debug("Added module: %s", name) + logger.Debugf("Added module: %s", name) } // Setup initializes the sandbox in a Lua state func (s *Sandbox) Setup(state *luajit.State, verbose bool) error { if verbose { - logger.Debug("Setting up sandbox...") + logger.Debugf("Setting up sandbox...") } if err := loadSandboxIntoState(state, verbose); err != nil { - logger.Error("Failed to load sandbox: %v", err) + logger.Errorf("Failed to load sandbox: %v", err) return err } if err := s.registerCoreFunctions(state); err != nil { - logger.Error("Failed to register core functions: %v", err) + logger.Errorf("Failed to register core functions: %v", err) return err } s.mu.RLock() for name, module := range s.modules { - logger.Debug("Registering module: %s", name) + logger.Debugf("Registering module: %s", name) if err := state.PushValue(module); err != nil { s.mu.RUnlock() - logger.Error("Failed to register module %s: %v", name, err) + logger.Errorf("Failed to register module %s: %v", name, err) return err } state.SetGlobal(name) @@ -78,7 +78,7 @@ func (s *Sandbox) Setup(state *luajit.State, verbose bool) error { s.mu.RUnlock() if verbose { - logger.Debug("Sandbox setup complete") + logger.Debugf("Sandbox setup complete") } return nil } diff --git a/runner/sqlite.go b/runner/sqlite.go index 3d31e17..d41107f 100644 --- a/runner/sqlite.go +++ b/runner/sqlite.go @@ -28,7 +28,7 @@ var ( // InitSQLite initializes the SQLite subsystem func InitSQLite(dir string) { dataDir = dir - logger.Info("SQLite is g2g! %s", color.Yellow(dir)) + logger.Infof("SQLite is g2g! %s", color.Yellow(dir)) } // SetSQLitePoolSize sets the pool size to match the runner pool size @@ -45,12 +45,12 @@ func CleanupSQLite() { for name, pool := range dbPools { if err := pool.Close(); err != nil { - logger.Error("Failed to close database %s: %v", name, err) + logger.Errorf("Failed to close database %s: %v", name, err) } } dbPools = make(map[string]*sqlitex.Pool) - logger.Debug("SQLite connections closed") + logger.Debugf("SQLite connections closed") } // getPool returns a connection pool for the database @@ -105,7 +105,7 @@ func getPool(dbName string) (*sqlitex.Pool, error) { } dbPools[dbName] = pool - logger.Debug("Created SQLite pool for %s (size: %d)", dbName, poolSize) + logger.Debugf("Created SQLite pool for %s (size: %d)", dbName, poolSize) return pool, nil } diff --git a/utils/config/config.go b/utils/config/config.go index aa87ee6..43300e4 100644 --- a/utils/config/config.go +++ b/utils/config/config.go @@ -6,8 +6,8 @@ import ( fin "git.sharkk.net/Sharkk/Fin" ) +// Config represents the current loaded configuration for the server type Config struct { - // Server settings Server struct { Port int Debug bool @@ -15,12 +15,10 @@ type Config struct { StaticPrefix string } - // Runner settings Runner struct { PoolSize int } - // Directory paths Dirs struct { Routes string Static string @@ -30,7 +28,6 @@ type Config struct { Libs []string } - // Raw fin data struct for custom data data *fin.Data } diff --git a/utils/logger/logger.go b/utils/logger/logger.go index 81115f2..a38ecae 100644 --- a/utils/logger/logger.go +++ b/utils/logger/logger.go @@ -8,345 +8,184 @@ import ( "sync" "sync/atomic" "time" + + "Moonshark/utils/color" ) -// ANSI color codes +// Log levels const ( - colorReset = "\033[0m" - colorRed = "\033[31m" - colorGreen = "\033[32m" - colorYellow = "\033[33m" - colorBlue = "\033[34m" - colorPurple = "\033[35m" - colorCyan = "\033[36m" - colorGray = "\033[90m" + LevelDebug = iota + LevelInfo + LevelWarn + LevelError + LevelFatal ) -// Log types -const ( - TypeNone = iota - TypeDebug - TypeInfo - TypeWarning - TypeError - TypeServer - TypeFatal -) - -// Type properties -var typeProps = map[int]struct { +// Level config +var levels = map[int]struct { tag string - color string + color func(string) string }{ - TypeDebug: {"D", colorCyan}, - TypeInfo: {"I", colorBlue}, - TypeWarning: {"W", colorYellow}, - TypeError: {"E", colorRed}, - TypeServer: {"S", colorGreen}, - TypeFatal: {"F", colorPurple}, + LevelDebug: {"D", color.Cyan}, + LevelInfo: {"I", color.Blue}, + LevelWarn: {"W", color.Yellow}, + LevelError: {"E", color.Red}, + LevelFatal: {"F", color.Purple}, } -const timeFormat = "15:04:05" - var ( - globalLogger *Logger - globalLoggerOnce sync.Once + global *Logger + globalOnce sync.Once ) type Logger struct { - writer io.Writer - useColors bool - timeFormat string - showTimestamp bool - mu sync.Mutex - debugMode atomic.Bool + out io.Writer + enabled atomic.Bool + timestamp atomic.Bool + debug atomic.Bool + colors atomic.Bool + mu sync.Mutex } -func GetLogger() *Logger { - globalLoggerOnce.Do(func() { - globalLogger = newLogger(true, true) +func init() { + globalOnce.Do(func() { + global = &Logger{out: os.Stdout} + global.enabled.Store(true) + global.timestamp.Store(true) + global.colors.Store(true) }) - return globalLogger } -func InitGlobalLogger(useColors bool, showTimestamp bool) { - globalLogger = newLogger(useColors, showTimestamp) -} - -func newLogger(useColors bool, showTimestamp bool) *Logger { - return &Logger{ - writer: os.Stdout, - useColors: useColors, - timeFormat: timeFormat, - showTimestamp: showTimestamp, - } -} - -func New(useColors bool, showTimestamp bool) *Logger { - return newLogger(useColors, showTimestamp) -} - -func (l *Logger) SetOutput(w io.Writer) { - l.mu.Lock() - l.writer = w - l.mu.Unlock() -} - -func (l *Logger) TimeFormat() string { - return l.timeFormat -} - -func (l *Logger) SetTimeFormat(format string) { - l.mu.Lock() - l.timeFormat = format - l.mu.Unlock() -} - -func (l *Logger) EnableTimestamp() { - l.showTimestamp = true -} - -func (l *Logger) DisableTimestamp() { - l.showTimestamp = false -} - -func (l *Logger) EnableColors() { - l.useColors = true -} - -func (l *Logger) DisableColors() { - l.useColors = false -} - -func (l *Logger) EnableDebug() { - l.debugMode.Store(true) -} - -func (l *Logger) DisableDebug() { - l.debugMode.Store(false) -} - -func (l *Logger) IsDebugEnabled() bool { - return l.debugMode.Load() -} - -func (l *Logger) applyColor(text, color string) string { - if l.useColors { - return color + text + colorReset +func applyColor(text string, colorFunc func(string) string) string { + if global.colors.Load() { + return colorFunc(text) } return text } -func stripAnsiColors(s string) string { - result := "" - inEscape := false - - for _, c := range s { - if inEscape { - if c == 'm' { - inEscape = false - } - continue - } - if c == '\033' { - inEscape = true - continue - } - result += string(c) - } - return result -} - -func (l *Logger) writeMessage(logType int, message string, rawMode bool) { - if rawMode { - l.mu.Lock() - _, _ = fmt.Fprint(l.writer, message+"\n") - l.mu.Unlock() +func write(level int, msg string) { + if !global.enabled.Load() { return } - parts := []string{} - - if l.showTimestamp { - timestamp := time.Now().Format(l.timeFormat) - if l.useColors { - timestamp = l.applyColor(timestamp, colorGray) - } - parts = append(parts, timestamp) + if level == LevelDebug && !global.debug.Load() { + return } - if logType != TypeNone { - props := typeProps[logType] - tag := "[" + props.tag + "]" - if l.useColors { - tag = l.applyColor(tag, props.color) - } + var parts []string + + if global.timestamp.Load() { + ts := applyColor(time.Now().Format("3:04PM"), color.Gray) + parts = append(parts, ts) + } + + if cfg, ok := levels[level]; ok { + tag := applyColor("["+cfg.tag+"]", cfg.color) parts = append(parts, tag) } - parts = append(parts, message) - logLine := strings.Join(parts, " ") + "\n" + parts = append(parts, msg) + line := strings.Join(parts, " ") + "\n" - l.mu.Lock() - _, _ = fmt.Fprint(l.writer, logLine) - if logType == TypeFatal { - if f, ok := l.writer.(*os.File); ok { - _ = f.Sync() + global.mu.Lock() + fmt.Fprint(global.out, line) + if level == LevelFatal { + if f, ok := global.out.(*os.File); ok { + f.Sync() } } - l.mu.Unlock() -} + global.mu.Unlock() -func (l *Logger) log(logType int, format string, args ...any) { - // Only filter debug messages - if logType == TypeDebug && !l.debugMode.Load() { - return - } - - var message string - if len(args) > 0 { - message = fmt.Sprintf(format, args...) - } else { - message = format - } - - l.writeMessage(logType, message, false) - - if logType == TypeFatal { + if level == LevelFatal { os.Exit(1) } } -func (l *Logger) LogRaw(format string, args ...any) { - var message string +func log(level int, format string, args ...any) { + var msg string if len(args) > 0 { - message = fmt.Sprintf(format, args...) + msg = fmt.Sprintf(format, args...) } else { - message = format + msg = format + } + write(level, msg) +} + +func Debugf(format string, args ...any) { log(LevelDebug, format, args...) } +func Infof(format string, args ...any) { log(LevelInfo, format, args...) } +func Warnf(format string, args ...any) { log(LevelWarn, format, args...) } +func Errorf(format string, args ...any) { log(LevelError, format, args...) } +func Fatalf(format string, args ...any) { log(LevelFatal, format, args...) } + +func Raw(format string, args ...any) { + if !global.enabled.Load() { + return } - if !l.useColors { - message = stripAnsiColors(message) + var msg string + if len(args) > 0 { + msg = fmt.Sprintf(format, args...) + } else { + msg = format } - l.writeMessage(TypeInfo, message, true) + global.mu.Lock() + fmt.Fprint(global.out, msg+"\n") + global.mu.Unlock() } -func (l *Logger) Debug(format string, args ...any) { - l.log(TypeDebug, format, args...) -} - -func (l *Logger) Info(format string, args ...any) { - l.log(TypeInfo, format, args...) -} - -func (l *Logger) Warning(format string, args ...any) { - l.log(TypeWarning, format, args...) -} - -func (l *Logger) Error(format string, args ...any) { - l.log(TypeError, format, args...) -} - -func (l *Logger) Fatal(format string, args ...any) { - l.log(TypeFatal, format, args...) -} - -func (l *Logger) Server(format string, args ...any) { - l.log(TypeServer, format, args...) -} - -func (l *Logger) LogRequest(statusCode int, method, path string, duration time.Duration) { - var statusColor string +func Request(status int, method, path string, duration time.Duration) { + if !global.enabled.Load() { + return + } + var statusColor func(string) string switch { - case statusCode < 300: - statusColor = colorGreen - case statusCode < 400: - statusColor = colorCyan - case statusCode < 500: - statusColor = colorYellow + case status < 300: + statusColor = color.Green + case status < 400: + statusColor = color.Cyan + case status < 500: + statusColor = color.Yellow default: - statusColor = colorRed + statusColor = color.Red } - var durationStr string - micros := duration.Microseconds() - if micros < 1000 { - durationStr = fmt.Sprintf("%.0fµs", float64(micros)) - } else if micros < 1000000 { - durationStr = fmt.Sprintf("%.1fms", float64(micros)/1000) - } else { - durationStr = fmt.Sprintf("%.2fs", duration.Seconds()) + var dur string + us := duration.Microseconds() + switch { + case us < 1000: + dur = fmt.Sprintf("%.0fµs", float64(us)) + case us < 1000000: + dur = fmt.Sprintf("%.1fms", float64(us)/1000) + default: + dur = fmt.Sprintf("%.2fs", duration.Seconds()) } - message := fmt.Sprintf("%s %s %s %s", - l.applyColor("["+method+"]", colorGray), - l.applyColor(fmt.Sprintf("%d", statusCode), statusColor), - l.applyColor(path, colorGray), - l.applyColor(durationStr, colorGray), + msg := fmt.Sprintf("%s %s %s %s", + applyColor("["+method+"]", color.Gray), + applyColor(fmt.Sprintf("%d", status), statusColor), + applyColor(path, color.Gray), + applyColor(dur, color.Gray), ) - l.writeMessage(TypeNone, message, false) -} - -// Global functions -func Debug(format string, args ...any) { - GetLogger().Debug(format, args...) -} - -func Info(format string, args ...any) { - GetLogger().Info(format, args...) -} - -func Warning(format string, args ...any) { - GetLogger().Warning(format, args...) -} - -func Error(format string, args ...any) { - GetLogger().Error(format, args...) -} - -func Fatal(format string, args ...any) { - GetLogger().Fatal(format, args...) -} - -func Server(format string, args ...any) { - GetLogger().Server(format, args...) -} - -func LogRaw(format string, args ...any) { - GetLogger().LogRaw(format, args...) + global.mu.Lock() + fmt.Fprint(global.out, msg+"\n") + global.mu.Unlock() } func SetOutput(w io.Writer) { - GetLogger().SetOutput(w) + global.mu.Lock() + global.out = w + global.mu.Unlock() } -func TimeFormat() string { - return GetLogger().TimeFormat() -} - -func EnableDebug() { - GetLogger().EnableDebug() -} - -func DisableDebug() { - GetLogger().DisableDebug() -} - -func IsDebugEnabled() bool { - return GetLogger().IsDebugEnabled() -} - -func EnableTimestamp() { - GetLogger().EnableTimestamp() -} - -func DisableTimestamp() { - GetLogger().DisableTimestamp() -} - -func LogRequest(statusCode int, method, path string, duration time.Duration) { - GetLogger().LogRequest(statusCode, method, path, duration) -} +func Enable() { global.enabled.Store(true) } +func Disable() { global.enabled.Store(false) } +func IsEnabled() bool { return global.enabled.Load() } +func EnableColors() { global.colors.Store(true) } +func DisableColors() { global.colors.Store(false) } +func ColorsEnabled() bool { return global.colors.Load() } +func Timestamp(enabled bool) { global.timestamp.Store(enabled) } +func Debug(enabled bool) { global.debug.Store(enabled) } +func IsDebug() bool { return global.debug.Load() } diff --git a/watchers/api.go b/watchers/api.go index e795bd9..ca59bf9 100644 --- a/watchers/api.go +++ b/watchers/api.go @@ -48,7 +48,7 @@ func WatchLuaRouter(router *router.LuaRouter, runner *runner.Runner, routesDir s return nil, fmt.Errorf("failed to watch directory: %w", err) } - logger.Info("Started watching Lua routes! %s", color.Yellow(routesDir)) + logger.Infof("Started watching Lua routes! %s", color.Yellow(routesDir)) return watcher, nil } @@ -77,7 +77,7 @@ func WatchLuaModules(luaRunner *runner.Runner, libDirs []string) ([]*DirectoryWa } watchers = append(watchers, watcher) - logger.Info("Started watching Lua modules! %s", color.Yellow(dir)) + logger.Infof("Started watching Lua modules! %s", color.Yellow(dir)) } return watchers, nil diff --git a/watchers/dir.go b/watchers/dir.go index e4f2d96..fa35325 100644 --- a/watchers/dir.go +++ b/watchers/dir.go @@ -198,12 +198,12 @@ func (w *DirectoryWatcher) notifyChange() { // logDebug logs a debug message with the watcher's directory prefix func (w *DirectoryWatcher) logDebug(format string, args ...any) { - logger.Debug("[Watcher] [%s] %s", w.dir, fmt.Sprintf(format, args...)) + logger.Debugf("[Watcher] [%s] %s", w.dir, fmt.Sprintf(format, args...)) } // logError logs an error message with the watcher's directory prefix func (w *DirectoryWatcher) logError(format string, args ...any) { - logger.Error("[Watcher] [%s] %s", w.dir, fmt.Sprintf(format, args...)) + logger.Errorf("[Watcher] [%s] %s", w.dir, fmt.Sprintf(format, args...)) } // GetDir gets the DirectoryWatcher's current directory diff --git a/watchers/manager.go b/watchers/manager.go index 919d524..83ff160 100644 --- a/watchers/manager.go +++ b/watchers/manager.go @@ -86,7 +86,7 @@ func (m *WatcherManager) WatchDirectory(config DirectoryWatcherConfig) (*Directo } m.watchers[config.Dir] = watcher - logger.Debug("WatcherManager added watcher for %s", config.Dir) + logger.Debugf("WatcherManager added watcher for %s", config.Dir) return watcher, nil } @@ -101,7 +101,7 @@ func (m *WatcherManager) UnwatchDirectory(dir string) error { } delete(m.watchers, dir) - logger.Debug("WatcherManager removed watcher for %s", dir) + logger.Debugf("WatcherManager removed watcher for %s", dir) return nil } @@ -133,7 +133,7 @@ func (m *WatcherManager) checkAllDirectories() { for _, watcher := range watchers { if watcher.consecutiveErrors > 3 { if watcher.consecutiveErrors == 4 { - logger.Error("Temporarily skipping directory %s due to errors: %v", + logger.Errorf("Temporarily skipping directory %s due to errors: %v", watcher.dir, watcher.lastError) watcher.consecutiveErrors++ } @@ -142,7 +142,7 @@ func (m *WatcherManager) checkAllDirectories() { changed, err := watcher.checkForChanges() if err != nil { - logger.Error("Error checking directory %s: %v", watcher.dir, err) + logger.Errorf("Error checking directory %s: %v", watcher.dir, err) continue }