rewrite logger and main

This commit is contained in:
Sky Johnson 2025-05-31 15:26:06 -05:00
parent ac646bbad8
commit c0c6100c17
16 changed files with 515 additions and 745 deletions

View File

@ -121,7 +121,7 @@ func New(luaRouter *router.LuaRouter, runner *runner.Runner, cfg *config.Config,
} }
func (s *Server) ListenAndServe(addr string) error { 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) return s.fasthttpServer.ListenAndServe(addr)
} }
@ -137,7 +137,7 @@ func (s *Server) handleRequest(ctx *fasthttp.RequestCtx) {
if s.debugMode && bytes.Equal(pathBytes, debugPath) { if s.debugMode && bytes.Equal(pathBytes, debugPath) {
s.handleDebugStats(ctx) s.handleDebugStats(ctx)
if s.cfg.Server.HTTPLogging { 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 return
} }
@ -145,7 +145,7 @@ func (s *Server) handleRequest(ctx *fasthttp.RequestCtx) {
if s.staticHandler != nil && bytes.HasPrefix(pathBytes, s.staticPrefixBytes) { if s.staticHandler != nil && bytes.HasPrefix(pathBytes, s.staticPrefixBytes) {
s.staticHandler(ctx) s.staticHandler(ctx)
if s.cfg.Server.HTTPLogging { 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 return
} }
@ -163,7 +163,7 @@ func (s *Server) handleRequest(ctx *fasthttp.RequestCtx) {
} }
if s.cfg.Server.HTTPLogging { 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) luaCtx.Set("form", formData)
} else { } else {
if s.debugMode { if s.debugMode {
logger.Warning("Error parsing form: %v", err) logger.Warnf("Error parsing form: %v", err)
} }
luaCtx.Set("form", emptyMap) 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) response, err := s.luaRunner.Run(bytecode, luaCtx, scriptPath)
if err != nil { if err != nil {
logger.Error("Lua execution error: %v", err) logger.Errorf("Lua execution error: %v", err)
s.sendError(ctx, fasthttp.StatusInternalServerError, pathBytes, err) s.sendError(ctx, fasthttp.StatusInternalServerError, pathBytes, err)
return return
} }

400
main.go
View File

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

334
moonshark.go Normal file
View File

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

View File

@ -73,7 +73,7 @@ func precompileModule(m *ModuleInfo) {
m.Once.Do(func() { m.Once.Do(func() {
tempState := luajit.New() tempState := luajit.New()
if tempState == nil { 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 return
} }
defer tempState.Close() defer tempState.Close()
@ -81,7 +81,7 @@ func precompileModule(m *ModuleInfo) {
code, err := tempState.CompileBytecode(m.Code, m.Name+".lua") code, err := tempState.CompileBytecode(m.Code, m.Name+".lua")
if err != nil { 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 return
} }
@ -89,7 +89,7 @@ func precompileModule(m *ModuleInfo) {
copy(bytecode, code) copy(bytecode, code)
m.Bytecode.Store(&bytecode) 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() bytecode := m.Bytecode.Load()
if bytecode != nil && len(*bytecode) > 0 { if bytecode != nil && len(*bytecode) > 0 {
if verbose { 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 { 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 { } else {
// Fallback to interpreting the source // Fallback to interpreting the source
if verbose { 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 { if err := state.DoString(m.Code); err != nil {
@ -154,13 +154,13 @@ func loadSandboxIntoState(state *luajit.State, verbose bool) error {
bytecode := sandbox.Bytecode.Load() bytecode := sandbox.Bytecode.Load()
if bytecode != nil && len(*bytecode) > 0 { if bytecode != nil && len(*bytecode) > 0 {
if verbose { if verbose {
logger.Debug("Loading sandbox.lua from precompiled bytecode") logger.Debugf("Loading sandbox.lua from precompiled bytecode")
} }
return state.LoadAndRunBytecode(*bytecode, "sandbox.lua") return state.LoadAndRunBytecode(*bytecode, "sandbox.lua")
} }
if verbose { if verbose {
logger.Warning("Using non-precompiled sandbox.lua") logger.Warnf("Using non-precompiled sandbox.lua")
} }
return state.DoString(sandboxLuaCode) return state.DoString(sandboxLuaCode)
} }

View File

@ -45,16 +45,16 @@ func InitEnv(dataDir string) error {
// Load existing .env file if it exists // Load existing .env file if it exists
if err := globalEnvManager.load(); err != nil { 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) count := len(globalEnvManager.vars)
if count > 0 { 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(fmt.Sprintf("%d", count)),
color.Yellow(envPath)) color.Yellow(envPath))
} else { } else {
logger.Info("Environment initialized: %s", color.Yellow(envPath)) logger.Infof("Environment initialized: %s", color.Yellow(envPath))
} }
return nil return nil
@ -95,7 +95,7 @@ func (e *EnvManager) load() error {
// Parse key=value // Parse key=value
parts := strings.SplitN(line, "=", 2) parts := strings.SplitN(line, "=", 2)
if len(parts) != 2 { if len(parts) != 2 {
logger.Warning("Invalid .env line %d: %s", lineNum, line) logger.Warnf("Invalid .env line %d: %s", lineNum, line)
continue continue
} }
@ -166,7 +166,7 @@ func (e *EnvManager) Save() error {
fmt.Fprintf(file, "%s=%s\n", key, strValue) 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 return nil
} }

View File

@ -52,7 +52,7 @@ func InitFS(basePath string) error {
// Initialize file cache with 2000 entries (reasonable for most use cases) // Initialize file cache with 2000 entries (reasonable for most use cases)
fileCache = lru.NewLRUCache(2000) fileCache = lru.NewLRUCache(2000)
logger.Info("Filesystem is g2g! %s", color.Yellow(fsBasePath)) logger.Infof("Filesystem is g2g! %s", color.Yellow(fsBasePath))
return nil return nil
} }
@ -60,7 +60,7 @@ func InitFS(basePath string) error {
func CleanupFS() { func CleanupFS() {
if fileCache != nil { if fileCache != nil {
fileCache.Clear() fileCache.Clear()
logger.Info( logger.Infof(
"File cache cleared - %s hits, %s misses", "File cache cleared - %s hits, %s misses",
color.Yellow(fmt.Sprintf("%d", stats.hits)), color.Yellow(fmt.Sprintf("%d", stats.hits)),
color.Red(fmt.Sprintf("%d", stats.misses)), color.Red(fmt.Sprintf("%d", stats.misses)),

View File

@ -315,7 +315,7 @@ func generateToken(state *luajit.State) int {
// Generate secure random bytes // Generate secure random bytes
tokenBytes := make([]byte, length) tokenBytes := make([]byte, length)
if _, err := rand.Read(tokenBytes); err != nil { 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("") state.PushString("")
return 1 // Return empty string on error return 1 // Return empty string on error
} }

View File

@ -59,7 +59,7 @@ func (l *ModuleLoader) SetScriptDir(dir string) {
// debugLog logs a message if debug mode is enabled // debugLog logs a message if debug mode is enabled
func (l *ModuleLoader) debugLog(format string, args ...interface{}) { func (l *ModuleLoader) debugLog(format string, args ...interface{}) {
if l.debug { if l.debug {
logger.Debug("ModuleLoader "+format, args...) logger.Debugf("ModuleLoader "+format, args...)
} }
} }

View File

@ -134,7 +134,7 @@ func NewRunner(options ...RunnerOption) (*Runner, error) {
// initializeStates creates and initializes all states in the pool // initializeStates creates and initializes all states in the pool
func (r *Runner) initializeStates() error { 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 { for i := range r.poolSize {
state, err := r.createState(i) state, err := r.createState(i)
@ -153,7 +153,7 @@ func (r *Runner) initializeStates() error {
func (r *Runner) createState(index int) (*State, error) { func (r *Runner) createState(index int) (*State, error) {
verbose := index == 0 verbose := index == 0
if verbose { if verbose {
logger.Debug("Creating Lua state %d", index) logger.Debugf("Creating Lua state %d", index)
} }
L := luajit.New() L := luajit.New()
@ -185,7 +185,7 @@ func (r *Runner) createState(index int) (*State, error) {
} }
if verbose { if verbose {
logger.Debug("Lua state %d initialized successfully", index) logger.Debugf("Lua state %d initialized successfully", index)
} }
return &State{ return &State{
@ -291,7 +291,7 @@ waitForInUse:
} }
if time.Now().After(timeout) { 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 break
} }
@ -302,7 +302,7 @@ waitForInUse:
for i, state := range r.states { for i, state := range r.states {
if state != nil { if state != nil {
if state.inUse.Load() { 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.Cleanup()
state.L.Close() state.L.Close()
@ -313,7 +313,7 @@ waitForInUse:
CleanupFS() CleanupFS()
CleanupSQLite() CleanupSQLite()
logger.Debug("Runner closed") logger.Debugf("Runner closed")
return nil return nil
} }
@ -326,7 +326,7 @@ func (r *Runner) RefreshStates() error {
return ErrRunnerClosed return ErrRunnerClosed
} }
logger.Info("Runner is refreshing all states...") logger.Infof("Runner is refreshing all states...")
// Drain all states from the pool // Drain all states from the pool
for { for {
@ -354,7 +354,7 @@ waitForInUse:
} }
if time.Now().After(timeout) { 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 break
} }
@ -365,7 +365,7 @@ waitForInUse:
for i, state := range r.states { for i, state := range r.states {
if state != nil { if state != nil {
if state.inUse.Load() { 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.Cleanup()
state.L.Close() state.L.Close()
@ -378,21 +378,21 @@ waitForInUse:
return err return err
} }
logger.Debug("All states refreshed successfully") logger.Debugf("All states refreshed successfully")
return nil return nil
} }
// NotifyFileChanged alerts the runner about file changes // NotifyFileChanged alerts the runner about file changes
func (r *Runner) NotifyFileChanged(filePath string) bool { 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) module, isModule := r.moduleLoader.GetModuleByPath(filePath)
if isModule { if isModule {
logger.Debug("Refreshing module: %s", module) logger.Debugf("Refreshing module: %s", module)
return r.RefreshModule(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 return true
} }
@ -405,7 +405,7 @@ func (r *Runner) RefreshModule(moduleName string) bool {
return false return false
} }
logger.Debug("Refreshing module: %s", moduleName) logger.Debugf("Refreshing module: %s", moduleName)
success := true success := true
for _, state := range r.states { for _, state := range r.states {
@ -416,12 +416,12 @@ func (r *Runner) RefreshModule(moduleName string) bool {
// Use the enhanced module loader refresh // Use the enhanced module loader refresh
if err := r.moduleLoader.RefreshModule(state.L, moduleName); err != nil { if err := r.moduleLoader.RefreshModule(state.L, moduleName); err != nil {
success = false 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 { if success {
logger.Debug("Successfully refreshed module: %s", moduleName) logger.Debugf("Successfully refreshed module: %s", moduleName)
} }
return success return success
@ -436,7 +436,7 @@ func (r *Runner) RefreshModuleByPath(filePath string) bool {
return false return false
} }
logger.Debug("Refreshing module by path: %s", filePath) logger.Debugf("Refreshing module by path: %s", filePath)
success := true success := true
for _, state := range r.states { for _, state := range r.states {
@ -447,7 +447,7 @@ func (r *Runner) RefreshModuleByPath(filePath string) bool {
// Use the enhanced module loader refresh by path // Use the enhanced module loader refresh by path
if err := r.moduleLoader.RefreshModuleByPath(state.L, filePath); err != nil { if err := r.moduleLoader.RefreshModuleByPath(state.L, filePath); err != nil {
success = false 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)
} }
} }

View File

@ -46,31 +46,31 @@ func (s *Sandbox) AddModule(name string, module any) {
s.mu.Lock() s.mu.Lock()
defer s.mu.Unlock() defer s.mu.Unlock()
s.modules[name] = module s.modules[name] = module
logger.Debug("Added module: %s", name) logger.Debugf("Added module: %s", name)
} }
// Setup initializes the sandbox in a Lua state // Setup initializes the sandbox in a Lua state
func (s *Sandbox) Setup(state *luajit.State, verbose bool) error { func (s *Sandbox) Setup(state *luajit.State, verbose bool) error {
if verbose { if verbose {
logger.Debug("Setting up sandbox...") logger.Debugf("Setting up sandbox...")
} }
if err := loadSandboxIntoState(state, verbose); err != nil { 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 return err
} }
if err := s.registerCoreFunctions(state); err != nil { 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 return err
} }
s.mu.RLock() s.mu.RLock()
for name, module := range s.modules { 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 { if err := state.PushValue(module); err != nil {
s.mu.RUnlock() 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 return err
} }
state.SetGlobal(name) state.SetGlobal(name)
@ -78,7 +78,7 @@ func (s *Sandbox) Setup(state *luajit.State, verbose bool) error {
s.mu.RUnlock() s.mu.RUnlock()
if verbose { if verbose {
logger.Debug("Sandbox setup complete") logger.Debugf("Sandbox setup complete")
} }
return nil return nil
} }

View File

@ -28,7 +28,7 @@ var (
// InitSQLite initializes the SQLite subsystem // InitSQLite initializes the SQLite subsystem
func InitSQLite(dir string) { func InitSQLite(dir string) {
dataDir = dir 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 // SetSQLitePoolSize sets the pool size to match the runner pool size
@ -45,12 +45,12 @@ func CleanupSQLite() {
for name, pool := range dbPools { for name, pool := range dbPools {
if err := pool.Close(); err != nil { 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) dbPools = make(map[string]*sqlitex.Pool)
logger.Debug("SQLite connections closed") logger.Debugf("SQLite connections closed")
} }
// getPool returns a connection pool for the database // getPool returns a connection pool for the database
@ -105,7 +105,7 @@ func getPool(dbName string) (*sqlitex.Pool, error) {
} }
dbPools[dbName] = pool 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 return pool, nil
} }

View File

@ -6,8 +6,8 @@ import (
fin "git.sharkk.net/Sharkk/Fin" fin "git.sharkk.net/Sharkk/Fin"
) )
// Config represents the current loaded configuration for the server
type Config struct { type Config struct {
// Server settings
Server struct { Server struct {
Port int Port int
Debug bool Debug bool
@ -15,12 +15,10 @@ type Config struct {
StaticPrefix string StaticPrefix string
} }
// Runner settings
Runner struct { Runner struct {
PoolSize int PoolSize int
} }
// Directory paths
Dirs struct { Dirs struct {
Routes string Routes string
Static string Static string
@ -30,7 +28,6 @@ type Config struct {
Libs []string Libs []string
} }
// Raw fin data struct for custom data
data *fin.Data data *fin.Data
} }

View File

@ -8,345 +8,184 @@ import (
"sync" "sync"
"sync/atomic" "sync/atomic"
"time" "time"
"Moonshark/utils/color"
) )
// ANSI color codes // Log levels
const ( const (
colorReset = "\033[0m" LevelDebug = iota
colorRed = "\033[31m" LevelInfo
colorGreen = "\033[32m" LevelWarn
colorYellow = "\033[33m" LevelError
colorBlue = "\033[34m" LevelFatal
colorPurple = "\033[35m"
colorCyan = "\033[36m"
colorGray = "\033[90m"
) )
// Log types // Level config
const ( var levels = map[int]struct {
TypeNone = iota
TypeDebug
TypeInfo
TypeWarning
TypeError
TypeServer
TypeFatal
)
// Type properties
var typeProps = map[int]struct {
tag string tag string
color string color func(string) string
}{ }{
TypeDebug: {"D", colorCyan}, LevelDebug: {"D", color.Cyan},
TypeInfo: {"I", colorBlue}, LevelInfo: {"I", color.Blue},
TypeWarning: {"W", colorYellow}, LevelWarn: {"W", color.Yellow},
TypeError: {"E", colorRed}, LevelError: {"E", color.Red},
TypeServer: {"S", colorGreen}, LevelFatal: {"F", color.Purple},
TypeFatal: {"F", colorPurple},
} }
const timeFormat = "15:04:05"
var ( var (
globalLogger *Logger global *Logger
globalLoggerOnce sync.Once globalOnce sync.Once
) )
type Logger struct { type Logger struct {
writer io.Writer out io.Writer
useColors bool enabled atomic.Bool
timeFormat string timestamp atomic.Bool
showTimestamp bool debug atomic.Bool
mu sync.Mutex colors atomic.Bool
debugMode atomic.Bool mu sync.Mutex
} }
func GetLogger() *Logger { func init() {
globalLoggerOnce.Do(func() { globalOnce.Do(func() {
globalLogger = newLogger(true, true) 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) { func applyColor(text string, colorFunc func(string) string) string {
globalLogger = newLogger(useColors, showTimestamp) if global.colors.Load() {
} return colorFunc(text)
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
} }
return text return text
} }
func stripAnsiColors(s string) string { func write(level int, msg string) {
result := "" if !global.enabled.Load() {
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()
return return
} }
parts := []string{} if level == LevelDebug && !global.debug.Load() {
return
if l.showTimestamp {
timestamp := time.Now().Format(l.timeFormat)
if l.useColors {
timestamp = l.applyColor(timestamp, colorGray)
}
parts = append(parts, timestamp)
} }
if logType != TypeNone { var parts []string
props := typeProps[logType]
tag := "[" + props.tag + "]" if global.timestamp.Load() {
if l.useColors { ts := applyColor(time.Now().Format("3:04PM"), color.Gray)
tag = l.applyColor(tag, props.color) parts = append(parts, ts)
} }
if cfg, ok := levels[level]; ok {
tag := applyColor("["+cfg.tag+"]", cfg.color)
parts = append(parts, tag) parts = append(parts, tag)
} }
parts = append(parts, message) parts = append(parts, msg)
logLine := strings.Join(parts, " ") + "\n" line := strings.Join(parts, " ") + "\n"
l.mu.Lock() global.mu.Lock()
_, _ = fmt.Fprint(l.writer, logLine) fmt.Fprint(global.out, line)
if logType == TypeFatal { if level == LevelFatal {
if f, ok := l.writer.(*os.File); ok { if f, ok := global.out.(*os.File); ok {
_ = f.Sync() f.Sync()
} }
} }
l.mu.Unlock() global.mu.Unlock()
}
func (l *Logger) log(logType int, format string, args ...any) { if level == LevelFatal {
// 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 {
os.Exit(1) os.Exit(1)
} }
} }
func (l *Logger) LogRaw(format string, args ...any) { func log(level int, format string, args ...any) {
var message string var msg string
if len(args) > 0 { if len(args) > 0 {
message = fmt.Sprintf(format, args...) msg = fmt.Sprintf(format, args...)
} else { } 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 { var msg string
message = stripAnsiColors(message) 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) { func Request(status int, method, path string, duration time.Duration) {
l.log(TypeDebug, format, args...) if !global.enabled.Load() {
} return
}
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
var statusColor func(string) string
switch { switch {
case statusCode < 300: case status < 300:
statusColor = colorGreen statusColor = color.Green
case statusCode < 400: case status < 400:
statusColor = colorCyan statusColor = color.Cyan
case statusCode < 500: case status < 500:
statusColor = colorYellow statusColor = color.Yellow
default: default:
statusColor = colorRed statusColor = color.Red
} }
var durationStr string var dur string
micros := duration.Microseconds() us := duration.Microseconds()
if micros < 1000 { switch {
durationStr = fmt.Sprintf("%.0fµs", float64(micros)) case us < 1000:
} else if micros < 1000000 { dur = fmt.Sprintf("%.0fµs", float64(us))
durationStr = fmt.Sprintf("%.1fms", float64(micros)/1000) case us < 1000000:
} else { dur = fmt.Sprintf("%.1fms", float64(us)/1000)
durationStr = fmt.Sprintf("%.2fs", duration.Seconds()) default:
dur = fmt.Sprintf("%.2fs", duration.Seconds())
} }
message := fmt.Sprintf("%s %s %s %s", msg := fmt.Sprintf("%s %s %s %s",
l.applyColor("["+method+"]", colorGray), applyColor("["+method+"]", color.Gray),
l.applyColor(fmt.Sprintf("%d", statusCode), statusColor), applyColor(fmt.Sprintf("%d", status), statusColor),
l.applyColor(path, colorGray), applyColor(path, color.Gray),
l.applyColor(durationStr, colorGray), applyColor(dur, color.Gray),
) )
l.writeMessage(TypeNone, message, false) global.mu.Lock()
} fmt.Fprint(global.out, msg+"\n")
global.mu.Unlock()
// 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...)
} }
func SetOutput(w io.Writer) { func SetOutput(w io.Writer) {
GetLogger().SetOutput(w) global.mu.Lock()
global.out = w
global.mu.Unlock()
} }
func TimeFormat() string { func Enable() { global.enabled.Store(true) }
return GetLogger().TimeFormat() func Disable() { global.enabled.Store(false) }
} func IsEnabled() bool { return global.enabled.Load() }
func EnableColors() { global.colors.Store(true) }
func EnableDebug() { func DisableColors() { global.colors.Store(false) }
GetLogger().EnableDebug() func ColorsEnabled() bool { return global.colors.Load() }
} func Timestamp(enabled bool) { global.timestamp.Store(enabled) }
func Debug(enabled bool) { global.debug.Store(enabled) }
func DisableDebug() { func IsDebug() bool { return global.debug.Load() }
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)
}

View File

@ -48,7 +48,7 @@ func WatchLuaRouter(router *router.LuaRouter, runner *runner.Runner, routesDir s
return nil, fmt.Errorf("failed to watch directory: %w", err) 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 return watcher, nil
} }
@ -77,7 +77,7 @@ func WatchLuaModules(luaRunner *runner.Runner, libDirs []string) ([]*DirectoryWa
} }
watchers = append(watchers, watcher) 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 return watchers, nil

View File

@ -198,12 +198,12 @@ func (w *DirectoryWatcher) notifyChange() {
// logDebug logs a debug message with the watcher's directory prefix // logDebug logs a debug message with the watcher's directory prefix
func (w *DirectoryWatcher) logDebug(format string, args ...any) { 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 // logError logs an error message with the watcher's directory prefix
func (w *DirectoryWatcher) logError(format string, args ...any) { 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 // GetDir gets the DirectoryWatcher's current directory

View File

@ -86,7 +86,7 @@ func (m *WatcherManager) WatchDirectory(config DirectoryWatcherConfig) (*Directo
} }
m.watchers[config.Dir] = watcher 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 return watcher, nil
} }
@ -101,7 +101,7 @@ func (m *WatcherManager) UnwatchDirectory(dir string) error {
} }
delete(m.watchers, dir) delete(m.watchers, dir)
logger.Debug("WatcherManager removed watcher for %s", dir) logger.Debugf("WatcherManager removed watcher for %s", dir)
return nil return nil
} }
@ -133,7 +133,7 @@ func (m *WatcherManager) checkAllDirectories() {
for _, watcher := range watchers { for _, watcher := range watchers {
if watcher.consecutiveErrors > 3 { if watcher.consecutiveErrors > 3 {
if watcher.consecutiveErrors == 4 { 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.dir, watcher.lastError)
watcher.consecutiveErrors++ watcher.consecutiveErrors++
} }
@ -142,7 +142,7 @@ func (m *WatcherManager) checkAllDirectories() {
changed, err := watcher.checkForChanges() changed, err := watcher.checkForChanges()
if err != nil { if err != nil {
logger.Error("Error checking directory %s: %v", watcher.dir, err) logger.Errorf("Error checking directory %s: %v", watcher.dir, err)
continue continue
} }