From 5bba4ffcf8f4c945cad7905952588d1d912a7aec Mon Sep 17 00:00:00 2001 From: Sky Johnson Date: Thu, 3 Apr 2025 12:59:12 -0500 Subject: [PATCH] big logger update 1 --- Moonshark.go | 23 ++- core/config/Config.go | 2 +- core/http/Server.go | 3 +- core/logger/Logger.go | 264 +++++++++++++++++++++++++++++++---- core/routers/LuaRouter.go | 2 +- core/routers/StaticRouter.go | 19 +-- core/runner/CoreModules.go | 66 +++++---- core/runner/Http.go | 18 ++- core/runner/Runner.go | 49 +++++-- core/runner/Sandbox.go | 98 +++++++------ core/watchers/Api.go | 1 - core/watchers/Manager.go | 4 +- main.go | 11 +- 13 files changed, 404 insertions(+), 156 deletions(-) diff --git a/Moonshark.go b/Moonshark.go index 4a89bdf..8f7a8b8 100644 --- a/Moonshark.go +++ b/Moonshark.go @@ -77,8 +77,8 @@ func (s *Moonshark) loadConfig(configPath string) error { // Load configuration from file s.Config, err = config.Load(configPath) if err != nil { - logger.Warning("Failed to load config file: %v", err) - logger.Info("Using default configuration") + logger.Warning("Wipeout! Couldn't load config file: %v", err) + logger.WarningCont("Rolling with the default setup") s.Config = config.New() } @@ -104,7 +104,7 @@ func (s *Moonshark) setupLogging() { // Set debug mode if configured if s.Config.Debug { logger.EnableDebug() // Force debug logs regardless of level - logger.Debug("Debug mode enabled") + logger.Debug("Debug mode is ready to party, bro") } } @@ -139,14 +139,14 @@ func (s *Moonshark) initRouters() error { return fmt.Errorf("failed to initialize Lua router: %v", err) } } - logger.Info("Lua router initialized with routes from %s", s.Config.RoutesDir) + logger.Info("Lua router is stoked and riding routes from %s", s.Config.RoutesDir) // Initialize static file router s.StaticRouter, err = routers.NewStaticRouter(s.Config.StaticDir) if err != nil { return fmt.Errorf("failed to initialize static router: %v", err) } - logger.Info("Static router initialized with files from %s", s.Config.StaticDir) + logger.Info("Static router catching waves with files from %s", s.Config.StaticDir) s.StaticRouter.EnableDebugLog() return nil @@ -201,7 +201,7 @@ func (s *Moonshark) initRunner() error { return fmt.Errorf("failed to initialize Lua runner: %v", err) } - logger.Server("Lua runner initialized with pool size %d", s.Config.PoolSize) + logger.Server("Lua runner waxing up with a pool size of %d", s.Config.PoolSize) return nil } @@ -246,13 +246,13 @@ func (s *Moonshark) setupWatchers() error { // Start starts the HTTP server func (s *Moonshark) Start() error { - logger.Server("Starting server on port %d", s.Config.Port) + logger.Server("Surf's up on port %d!", s.Config.Port) // Log HTTP logging status if s.Config.HTTPLoggingEnabled { - logger.Info("HTTP logging is enabled") + logger.ServerCont("HTTP logging is turned on - watch those waves") } else { - logger.Info("HTTP logging is disabled") + logger.ServerCont("HTTP logging is turned off - waves are flat bro") } // Start the server in a non-blocking way @@ -271,7 +271,6 @@ func (s *Moonshark) Start() error { func (s *Moonshark) Shutdown() error { logger.Server("Shutting down server...") - // Shutdown HTTP server with timeout ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) defer cancel() @@ -280,16 +279,14 @@ func (s *Moonshark) Shutdown() error { return err } - // Run cleanup functions for _, cleanup := range s.cleanupFuncs { if err := cleanup(); err != nil { logger.Warning("Cleanup error: %v", err) } } - // Close Lua runner s.LuaRunner.Close() - logger.Server("Server stopped") + logger.ServerCont("Server stopped") return nil } diff --git a/core/config/Config.go b/core/config/Config.go index bd45d14..a5cb0b2 100644 --- a/core/config/Config.go +++ b/core/config/Config.go @@ -76,7 +76,7 @@ func Load(filePath string) (*Config, error) { // Execute the config file if err := state.DoFile(filePath); err != nil { - return nil, fmt.Errorf("failed to load config file: %w", err) + return nil, fmt.Errorf("%w", err) } // Extract configuration values diff --git a/core/http/Server.go b/core/http/Server.go index 99b96d3..170bc09 100644 --- a/core/http/Server.go +++ b/core/http/Server.go @@ -61,13 +61,12 @@ func New(luaRouter *routers.LuaRouter, staticRouter *routers.StaticRouter, runne // ListenAndServe starts the server on the given address func (s *Server) ListenAndServe(addr string) error { s.httpServer.Addr = addr - logger.Info("Server listening at http://localhost%s", addr) + logger.ServerCont("Catch the swell at http://localhost%s", addr) return s.httpServer.ListenAndServe() } // Shutdown gracefully shuts down the server func (s *Server) Shutdown(ctx context.Context) error { - logger.Info("Server shutting down...") return s.httpServer.Shutdown(ctx) } diff --git a/core/logger/Logger.go b/core/logger/Logger.go index a1b8e50..9544d7c 100644 --- a/core/logger/Logger.go +++ b/core/logger/Logger.go @@ -4,6 +4,7 @@ import ( "fmt" "io" "os" + "strings" "sync" "sync/atomic" "time" @@ -62,12 +63,16 @@ var ( // Logger handles logging operations type Logger struct { - writer io.Writer - level int - useColors bool - timeFormat string - mu sync.Mutex // Mutex for thread-safe writing - debugMode atomic.Bool // Force debug logging regardless of level + writer io.Writer + level int + useColors bool + timeFormat string + showTimestamp bool // Whether to show timestamp + mu sync.Mutex // Mutex for thread-safe writing + debugMode atomic.Bool // Force debug logging regardless of level + indentCache string // Cached indent string for continuations + indentSize int // Size of the indent for continuations + lastLevel int // Last log level used, for continuations // Simple rate limiting logCount atomic.Int64 // Number of logs in current window @@ -81,38 +86,42 @@ type Logger struct { // GetLogger returns the global logger instance, creating it if needed func GetLogger() *Logger { globalLoggerOnce.Do(func() { - globalLogger = newLogger(LevelInfo, true) + globalLogger = newLogger(LevelInfo, true, true) }) return globalLogger } // InitGlobalLogger initializes the global logger with custom settings -func InitGlobalLogger(minLevel int, useColors bool) { - globalLoggerOnce.Do(func() { - globalLogger = newLogger(minLevel, useColors) - }) +func InitGlobalLogger(minLevel int, useColors bool, showTimestamp bool) { + // Reset the global logger instance + globalLogger = newLogger(minLevel, useColors, showTimestamp) } // newLogger creates a new logger instance (internal use) -func newLogger(minLevel int, useColors bool) *Logger { +func newLogger(minLevel int, useColors bool, showTimestamp bool) *Logger { logger := &Logger{ writer: os.Stdout, level: minLevel, useColors: useColors, timeFormat: timeFormat, + showTimestamp: showTimestamp, maxLogsPerSec: defaultMaxLogs, limitDuration: defaultRateLimitTime, + lastLevel: -1, // Initialize to invalid level } // Initialize counters logger.resetCounters() + // Calculate the base indent size + logger.updateIndentCache() + return logger } // New creates a new logger (deprecated - use GetLogger() instead) -func New(minLevel int, useColors bool) *Logger { - return newLogger(minLevel, useColors) +func New(minLevel int, useColors bool, showTimestamp bool) *Logger { + return newLogger(minLevel, useColors, showTimestamp) } // resetCounters resets the rate limiting counters @@ -135,9 +144,47 @@ func (l *Logger) TimeFormat() string { return l.timeFormat } -// SetTimeFormat changes the time format string +// updateIndentCache recalculates and updates the indent cache +func (l *Logger) updateIndentCache() { + tagWidth := 7 + + if l.showTimestamp { + // Format: "15:04:05 DEBUG " + timeWidth := len(time.Now().Format(l.timeFormat)) + l.indentSize = timeWidth + 1 + tagWidth + 1 + } else { + // Format: "DEBUG " + l.indentSize = tagWidth + 1 + } + + l.indentCache = strings.Repeat(" ", l.indentSize) +} + +// SetTimeFormat changes the time format string and updates the indent cache func (l *Logger) SetTimeFormat(format string) { + l.mu.Lock() + defer l.mu.Unlock() + l.timeFormat = format + l.updateIndentCache() +} + +// EnableTimestamp enables timestamp display +func (l *Logger) EnableTimestamp() { + l.mu.Lock() + defer l.mu.Unlock() + + l.showTimestamp = true + l.updateIndentCache() +} + +// DisableTimestamp disables timestamp display +func (l *Logger) DisableTimestamp() { + l.mu.Lock() + defer l.mu.Unlock() + + l.showTimestamp = false + l.updateIndentCache() } // SetLevel changes the minimum log level @@ -171,24 +218,49 @@ func (l *Logger) IsDebugEnabled() bool { } // writeMessage writes a formatted log message directly to the writer -func (l *Logger) writeMessage(level int, message string, rawMode bool) { +func (l *Logger) writeMessage(level int, message string, rawMode bool, continuation bool) { var logLine string if rawMode { // Raw mode - message is already formatted, just append newline logLine = message + "\n" + } else if continuation { + // Continuation format - just indent and message + if l.useColors { + // For colored output, use the color of the last level + props := levelProps[l.lastLevel] + logLine = fmt.Sprintf("%s%s%s\n", + l.indentCache, props.color, message+colorReset) + } else { + logLine = fmt.Sprintf("%s%s\n", l.indentCache, message) + } } else { - // Standard format with timestamp, level tag, and message - now := time.Now().Format(l.timeFormat) + // Standard format with level tag and optional timestamp props := levelProps[level] - if l.useColors { - logLine = fmt.Sprintf("%s%s%s %s%s%s %s\n", - colorGray, now, colorReset, props.color, props.tag, colorReset, message) + if l.showTimestamp { + now := time.Now().Format(l.timeFormat) + + if l.useColors { + logLine = fmt.Sprintf("%s%s%s %s[%s]%s %s\n", + colorGray, now, colorReset, props.color, props.tag, colorReset, message) + } else { + logLine = fmt.Sprintf("%s [%s] %s\n", + now, props.tag, message) + } } else { - logLine = fmt.Sprintf("%s %s %s\n", - now, props.tag, message) + // No timestamp, just level tag and message + if l.useColors { + logLine = fmt.Sprintf("%s[%s]%s %s\n", + props.color, props.tag, colorReset, message) + } else { + logLine = fmt.Sprintf("[%s] %s\n", + props.tag, message) + } } + + // Store the level for continuations + l.lastLevel = level } // Synchronously write the log message @@ -249,7 +321,7 @@ func (l *Logger) checkRateLimit(level int) bool { // Log a warning about rate limiting l.writeMessage(LevelServer, fmt.Sprintf("Rate limiting logger temporarily due to high demand (%d logs/sec exceeded)", count), - false) + false, false) return false } @@ -278,7 +350,7 @@ func (l *Logger) log(level int, format string, args ...any) { message = format } - l.writeMessage(level, message, false) + l.writeMessage(level, message, false, false) // Exit on fatal errors if level == LevelFatal { @@ -286,6 +358,31 @@ func (l *Logger) log(level int, format string, args ...any) { } } +// continuation handles continuation log messages (messages that continue from a previous log) +func (l *Logger) continuation(level int, format string, args ...any) { + // Check if we should log this message + // Either level is high enough OR (it's a debug message AND debug mode is enabled) + if level < l.level && !(level == LevelDebug && l.debugMode.Load()) { + return + } + + // Check rate limiting + if !l.checkRateLimit(level) { + return + } + + // Format message + var message string + if len(args) > 0 { + message = fmt.Sprintf(format, args...) + } else { + message = format + } + + // Use the continuation format + l.writeMessage(level, message, false, true) +} + // LogRaw logs a message with raw formatting, bypassing the standard format func (l *Logger) LogRaw(format string, args ...any) { // Use info level for filtering @@ -311,7 +408,7 @@ func (l *Logger) LogRaw(format string, args ...any) { message = removeAnsiColors(message) } - l.writeMessage(LevelInfo, message, true) + l.writeMessage(LevelInfo, message, true, false) } // Simple helper to remove ANSI color codes @@ -343,32 +440,63 @@ func (l *Logger) Debug(format string, args ...any) { l.log(LevelDebug, format, args...) } +// DebugCont logs a debug message as a continuation of the previous log +func (l *Logger) DebugCont(format string, args ...any) { + l.continuation(LevelDebug, format, args...) +} + // Info logs an informational message func (l *Logger) Info(format string, args ...any) { l.log(LevelInfo, format, args...) } +// InfoCont logs an informational message as a continuation of the previous log +func (l *Logger) InfoCont(format string, args ...any) { + l.continuation(LevelInfo, format, args...) +} + // Warning logs a warning message func (l *Logger) Warning(format string, args ...any) { l.log(LevelWarning, format, args...) } +// WarningCont logs a warning message as a continuation of the previous log +func (l *Logger) WarningCont(format string, args ...any) { + l.continuation(LevelWarning, format, args...) +} + // Error logs an error message func (l *Logger) Error(format string, args ...any) { l.log(LevelError, format, args...) } +// ErrorCont logs an error message as a continuation of the previous log +func (l *Logger) ErrorCont(format string, args ...any) { + l.continuation(LevelError, format, args...) +} + // Fatal logs a fatal error message and exits func (l *Logger) Fatal(format string, args ...any) { l.log(LevelFatal, format, args...) // No need for os.Exit here as it's handled in log() } +// FatalCont logs a fatal error message as a continuation of the previous log and exits +func (l *Logger) FatalCont(format string, args ...any) { + l.continuation(LevelFatal, format, args...) + os.Exit(1) +} + // Server logs a server message func (l *Logger) Server(format string, args ...any) { l.log(LevelServer, format, args...) } +// ServerCont logs a server message as a continuation of the previous log +func (l *Logger) ServerCont(format string, args ...any) { + l.continuation(LevelServer, format, args...) +} + // Global helper functions that use the global logger // Debug logs a debug message to the global logger @@ -376,31 +504,61 @@ func Debug(format string, args ...any) { GetLogger().Debug(format, args...) } +// DebugCont logs a debug message as a continuation of the previous log to the global logger +func DebugCont(format string, args ...any) { + GetLogger().DebugCont(format, args...) +} + // Info logs an informational message to the global logger func Info(format string, args ...any) { GetLogger().Info(format, args...) } +// InfoCont logs an informational message as a continuation of the previous log to the global logger +func InfoCont(format string, args ...any) { + GetLogger().InfoCont(format, args...) +} + // Warning logs a warning message to the global logger func Warning(format string, args ...any) { GetLogger().Warning(format, args...) } +// WarningCont logs a warning message as a continuation of the previous log to the global logger +func WarningCont(format string, args ...any) { + GetLogger().WarningCont(format, args...) +} + // Error logs an error message to the global logger func Error(format string, args ...any) { GetLogger().Error(format, args...) } +// ErrorCont logs an error message as a continuation of the previous log to the global logger +func ErrorCont(format string, args ...any) { + GetLogger().ErrorCont(format, args...) +} + // Fatal logs a fatal error message to the global logger and exits func Fatal(format string, args ...any) { GetLogger().Fatal(format, args...) } +// FatalCont logs a fatal error message as a continuation of the previous log to the global logger and exits +func FatalCont(format string, args ...any) { + GetLogger().FatalCont(format, args...) +} + // Server logs a server message to the global logger func Server(format string, args ...any) { GetLogger().Server(format, args...) } +// ServerCont logs a server message as a continuation of the previous log to the global logger +func ServerCont(format string, args ...any) { + GetLogger().ServerCont(format, args...) +} + // LogRaw logs a raw message to the global logger func LogRaw(format string, args ...any) { GetLogger().LogRaw(format, args...) @@ -435,3 +593,57 @@ func DisableDebug() { func IsDebugEnabled() bool { return GetLogger().IsDebugEnabled() } + +// EnableTimestamp enables timestamp display +func EnableTimestamp() { + GetLogger().EnableTimestamp() +} + +// DisableTimestamp disables timestamp display +func DisableTimestamp() { + GetLogger().DisableTimestamp() +} + +// LogSpacer adds a horizontal line separator to the log output +func (l *Logger) LogSpacer() { + l.mu.Lock() + defer l.mu.Unlock() + + // Calculate spacer width + tagWidth := 7 // Standard width of tag area "[DEBUG]" + + var spacer string + if l.showTimestamp { + // Format: "15:04:05 [DEBUG] ----" + timeWidth := len(time.Now().Format(l.timeFormat)) + tagSpacer := strings.Repeat("-", tagWidth) + restSpacer := strings.Repeat("-", 20) // Fixed width for the rest + + if l.useColors { + spacer = fmt.Sprintf("%s%s%s %s%s%s %s\n", + colorGray, strings.Repeat("-", timeWidth), colorReset, + colorCyan, tagSpacer, colorReset, restSpacer) + } else { + spacer = fmt.Sprintf("%s %s %s\n", + strings.Repeat("-", timeWidth), tagSpacer, restSpacer) + } + } else { + // No timestamp: "[DEBUG] ----" + tagSpacer := strings.Repeat("-", tagWidth) + restSpacer := strings.Repeat("-", 20) // Fixed width for the rest + + if l.useColors { + spacer = fmt.Sprintf("%s%s%s %s\n", + colorCyan, tagSpacer, colorReset, restSpacer) + } else { + spacer = fmt.Sprintf("%s %s\n", tagSpacer, restSpacer) + } + } + + _, _ = fmt.Fprint(l.writer, spacer) +} + +// LogSpacer adds a horizontal line separator to the global logger +func LogSpacer() { + GetLogger().LogSpacer() +} diff --git a/core/routers/LuaRouter.go b/core/routers/LuaRouter.go index 4bd8439..bae7dca 100644 --- a/core/routers/LuaRouter.go +++ b/core/routers/LuaRouter.go @@ -244,7 +244,7 @@ func (r *LuaRouter) matchPath(current *node, segments []string, params *Params, } // compileHandler compiles a Lua file to bytecode -func (r *LuaRouter) compileHandler(n *node, urlPath string) error { +func (r *LuaRouter) compileHandler(n *node, _ string) error { if n.handler == "" { return nil } diff --git a/core/routers/StaticRouter.go b/core/routers/StaticRouter.go index 82f794b..baee219 100644 --- a/core/routers/StaticRouter.go +++ b/core/routers/StaticRouter.go @@ -44,16 +44,10 @@ type StaticRouter struct { bufferPool sync.Pool // Buffer pool for compression urlPrefix string // URL prefix for static assets log bool // Whether to log debug info - logger *logger.Logger // Logger instance } -// NewStaticRouter creates a new StaticRouter instance +// NewStaticRouterWithLogger creates a new StaticRouter instance func NewStaticRouter(rootDir string) (*StaticRouter, error) { - return NewStaticRouterWithLogger(rootDir, logger.New(logger.LevelInfo, true)) -} - -// NewStaticRouterWithLogger creates a new StaticRouter instance with a custom logger -func NewStaticRouterWithLogger(rootDir string, log *logger.Logger) (*StaticRouter, error) { // Verify root directory exists info, err := os.Stat(rootDir) if err != nil { @@ -74,7 +68,6 @@ func NewStaticRouterWithLogger(rootDir string, log *logger.Logger) (*StaticRoute fileServer: http.FileServer(http.Dir(rootDir)), urlPrefix: "/static", // Default prefix for static assets log: false, // Debug logging off by default - logger: log, bufferPool: sync.Pool{ New: func() any { return new(bytes.Buffer) @@ -177,13 +170,13 @@ func (r *StaticRouter) ServeHTTP(w http.ResponseWriter, req *http.Request) { // Try to serve from cache if client accepts gzip if acceptsGzip && r.serveFromCache(w, &newReq, fileURLPath) { if r.log { - r.logger.Debug("[StaticRouter] CACHE HIT: %s", origPath) + logger.Debug("[StaticRouter] CACHE HIT: %s", origPath) } return } if r.log { - r.logger.Debug("[StaticRouter] CACHE MISS: %s", origPath) + logger.Debug("[StaticRouter] CACHE MISS: %s", origPath) } // Fall back to standard file serving @@ -238,7 +231,7 @@ func (r *StaticRouter) Match(urlPath string) (string, bool) { _, err := os.Stat(filePath) if r.log && err == nil { - r.logger.Debug("[StaticRouter] MATCH: %s -> %s", urlPath, filePath) + logger.Debug("[StaticRouter] MATCH: %s -> %s", urlPath, filePath) } return filePath, err == nil @@ -443,7 +436,7 @@ func (r *StaticRouter) PreloadCommonFiles() { } if r.log { - r.logger.Debug("[StaticRouter] Preloading common files from %s", r.rootDir) + logger.Debug("[StaticRouter] Preloading common files from %s", r.rootDir) } count := 0 @@ -477,7 +470,7 @@ func (r *StaticRouter) PreloadCommonFiles() { }) if r.log { - r.logger.Debug("[StaticRouter] Preloaded %d files", count) + logger.Debug("[StaticRouter] Preloaded %d files", count) } } diff --git a/core/runner/CoreModules.go b/core/runner/CoreModules.go index dffcedb..d92e26d 100644 --- a/core/runner/CoreModules.go +++ b/core/runner/CoreModules.go @@ -41,7 +41,14 @@ func (r *CoreModuleRegistry) EnableDebug() { // debugLog prints debug messages if enabled func (r *CoreModuleRegistry) debugLog(format string, args ...interface{}) { if r.debug { - logger.Debug("[CoreModuleRegistry] "+format, args...) + logger.Debug("CoreRegistry "+format, args...) + } +} + +// debugLogCont prints continuation debug messages if enabled +func (r *CoreModuleRegistry) debugLogCont(format string, args ...interface{}) { + if r.debug { + logger.DebugCont(format, args...) } } @@ -55,13 +62,12 @@ func (r *CoreModuleRegistry) Register(name string, initFunc StateInitFunc) { // Add to initialization order if not already there for _, n := range r.initOrder { if n == name { - r.debugLog("Module already in init order: %s", name) - return + return // Already registered, silently continue } } r.initOrder = append(r.initOrder, name) - r.debugLog("Registered module: %s", name) + r.debugLog("registered module %s", name) } // RegisterWithDependencies registers a module with explicit dependencies @@ -75,13 +81,15 @@ func (r *CoreModuleRegistry) RegisterWithDependencies(name string, initFunc Stat // Add to initialization order if not already there for _, n := range r.initOrder { if n == name { - r.debugLog("Module already in init order: %s", name) - return + return // Already registered, silently continue } } r.initOrder = append(r.initOrder, name) - r.debugLog("Registered module %s with dependencies: %v", name, dependencies) + r.debugLog("registered module %s", name) + if len(dependencies) > 0 { + r.debugLogCont("Dependencies: %v", dependencies) + } } // SetInitOrder sets explicit initialization order @@ -131,28 +139,34 @@ func (r *CoreModuleRegistry) SetInitOrder(order []string) { } // Initialize initializes all registered modules -func (r *CoreModuleRegistry) Initialize(state *luajit.State) error { +func (r *CoreModuleRegistry) Initialize(state *luajit.State, stateIndex int) error { r.mu.RLock() defer r.mu.RUnlock() - r.debugLog("Initializing all modules...") + verbose := stateIndex == 0 + if verbose { + r.debugLog("initializing %d modules...", len(r.initOrder)) + } // Clear initialization flags r.initializedFlag = make(map[string]bool) // Initialize modules in order, respecting dependencies for _, name := range r.initOrder { - if err := r.initializeModule(state, name, []string{}); err != nil { + if err := r.initializeModule(state, name, []string{}, verbose); err != nil { return err } } - r.debugLog("All modules initialized successfully") + if verbose { + r.debugLogCont("All modules initialized successfully") + } return nil } // initializeModule initializes a module and its dependencies -func (r *CoreModuleRegistry) initializeModule(state *luajit.State, name string, initStack []string) error { +func (r *CoreModuleRegistry) initializeModule(state *luajit.State, name string, + initStack []string, verbose bool) error { // Check if already initialized if r.initializedFlag[name] { return nil @@ -177,22 +191,24 @@ func (r *CoreModuleRegistry) initializeModule(state *luajit.State, name string, if len(deps) > 0 { newStack := append(initStack, name) for _, dep := range deps { - if err := r.initializeModule(state, dep, newStack); err != nil { + if err := r.initializeModule(state, dep, newStack, verbose); err != nil { return err } } } - // Initialize this module - r.debugLog("Initializing module: %s", name) - if err := initFunc(state); err != nil { - r.debugLog("Failed to initialize module %s: %v", name, err) + err := initFunc(state) + if err != nil { + // Always log failures regardless of verbose setting + r.debugLogCont("Initializing module %s... failure: %v", name, err) return fmt.Errorf("failed to initialize module %s: %w", name, err) } - // Mark as initialized r.initializedFlag[name] = true - r.debugLog("Module %s initialized successfully", name) + + if verbose { + r.debugLogCont("Initializing module %s... success", name) + } return nil } @@ -205,7 +221,8 @@ func (r *CoreModuleRegistry) InitializeModule(state *luajit.State, name string) // Clear initialization flag for this module r.initializedFlag[name] = false - return r.initializeModule(state, name, []string{}) + // Always use verbose logging for explicit module initialization + return r.initializeModule(state, name, []string{}, true) } // ModuleNames returns a list of all registered module names @@ -246,16 +263,11 @@ var GlobalRegistry = NewCoreModuleRegistry() // Initialize global registry with core modules func init() { GlobalRegistry.EnableDebug() // Enable debugging by default + logger.Debug("[ModuleRegistry] Registering core modules...") GlobalRegistry.Register("go", GoModuleInitFunc()) - - // Register HTTP module (no dependencies) GlobalRegistry.Register("http", HTTPModuleInitFunc()) - - // Register cookie module (depends on http) GlobalRegistry.RegisterWithDependencies("cookie", CookieModuleInitFunc(), []string{"http"}) - - // Register CSRF module (depends on go) GlobalRegistry.RegisterWithDependencies("csrf", CSRFModuleInitFunc(), []string{"go"}) // Set explicit initialization order @@ -266,7 +278,7 @@ func init() { "csrf", // Fourth: CSRF protection (uses go and possibly session) }) - logger.Debug("[CoreModuleRegistry] Core modules registered in init()") + logger.DebugCont("Core modules registered successfully") } // RegisterCoreModule is a helper to register a core module with the global registry diff --git a/core/runner/Http.go b/core/runner/Http.go index 2fa6378..6435529 100644 --- a/core/runner/Http.go +++ b/core/runner/Http.go @@ -371,7 +371,8 @@ func HTTPModuleInitFunc() StateInitFunc { // CRITICAL: Register the native Go function first // This must be done BEFORE any Lua code that references it if err := state.RegisterGoFunction(httpRequestFuncName, httpRequest); err != nil { - logger.Error("[HTTP Module] Failed to register __http_request function: %v\n", err) + logger.Error("[HTTP Module] Failed to register __http_request function") + logger.ErrorCont("%v", err) return err } @@ -380,7 +381,8 @@ func HTTPModuleInitFunc() StateInitFunc { // Initialize Lua HTTP module if err := state.DoString(LuaHTTPModule); err != nil { - logger.Error("[HTTP Module] Failed to initialize HTTP module Lua code: %v\n", err) + logger.Error("[HTTP Module] Failed to initialize HTTP module Lua code") + logger.ErrorCont("%v", err) return err } @@ -510,14 +512,14 @@ func verifyHTTPClient(state *luajit.State) { // Get the client table state.GetGlobal("http") if !state.IsTable(-1) { - logger.Warning("[HTTP Module] 'http' is not a table\n") + logger.Warning("[HTTP Module] 'http' is not a table") state.Pop(1) return } state.GetField(-1, "client") if !state.IsTable(-1) { - logger.Warning("[HTTP Module] 'http.client' is not a table\n") + logger.Warning("[HTTP Module] 'http.client' is not a table") state.Pop(2) return } @@ -525,18 +527,14 @@ func verifyHTTPClient(state *luajit.State) { // Check for get function state.GetField(-1, "get") if !state.IsFunction(-1) { - logger.Warning("[HTTP Module] 'http.client.get' is not a function\n") - } else { - logger.Debug("[HTTP Module] 'http.client.get' is properly registered\n") + logger.Warning("[HTTP Module] 'http.client.get' is not a function") } state.Pop(1) // Check for the request function state.GetField(-1, "request") if !state.IsFunction(-1) { - logger.Warning("[HTTP Module] 'http.client.request' is not a function\n") - } else { - logger.Debug("[HTTP Module] 'http.client.request' is properly registered\n") + logger.Warning("[HTTP Module] 'http.client.request' is not a function") } state.Pop(3) // Pop request, client, http } diff --git a/core/runner/Runner.go b/core/runner/Runner.go index ce9411c..5ac2858 100644 --- a/core/runner/Runner.go +++ b/core/runner/Runner.go @@ -137,15 +137,21 @@ func NewRunner(options ...RunnerOption) (*Runner, error) { // debugLog logs a message if debug mode is enabled func (r *Runner) debugLog(format string, args ...interface{}) { if r.debug { - logger.Debug("[Runner] "+format, args...) + logger.Debug("Runner "+format, args...) + } +} + +func (r *Runner) debugLogCont(format string, args ...interface{}) { + if r.debug { + logger.DebugCont(format, args...) } } // initializeStates creates and initializes all states in the pool func (r *Runner) initializeStates() error { - r.debugLog("Initializing %d Lua states", r.poolSize) + r.debugLog("is initializing %d states", r.poolSize) - // Create main template state first + // Create main template state first with full logging templateState, err := r.createState(0) if err != nil { return err @@ -154,7 +160,8 @@ func (r *Runner) initializeStates() error { r.states[0] = templateState r.statePool <- 0 // Add index to the pool - // Create remaining states + // Create remaining states with minimal logging + successCount := 1 for i := 1; i < r.poolSize; i++ { state, err := r.createState(i) if err != nil { @@ -163,15 +170,19 @@ func (r *Runner) initializeStates() error { r.states[i] = state r.statePool <- i // Add index to the pool + successCount++ } - r.debugLog("All %d Lua states initialized successfully", r.poolSize) + r.debugLog("has built %d/%d states successfully", successCount, r.poolSize) return nil } // createState initializes a new Lua state func (r *Runner) createState(index int) (*State, error) { - r.debugLog("Creating Lua state %d", index) + verbose := index == 0 + if verbose { + r.debugLog("Creating Lua state %d", index) + } // Create a new state L := luajit.New() @@ -181,29 +192,35 @@ func (r *Runner) createState(index int) (*State, error) { // Create sandbox sandbox := NewSandbox() - if r.debug { + if r.debug && verbose { sandbox.EnableDebug() } // Set up require system if err := r.moduleLoader.SetupRequire(L); err != nil { - r.debugLog("Failed to set up require for state %d: %v", index, err) + if verbose { + r.debugLogCont("Failed to set up require for state %d: %v", index, err) + } L.Cleanup() L.Close() return nil, ErrInitFailed } // Initialize all core modules from the registry - if err := GlobalRegistry.Initialize(L); err != nil { - r.debugLog("Failed to initialize core modules for state %d: %v", index, err) + if err := GlobalRegistry.Initialize(L, index); err != nil { + if verbose { + r.debugLogCont("Failed to initialize core modules for state %d: %v", index, err) + } L.Cleanup() L.Close() return nil, ErrInitFailed } // Set up sandbox after core modules are initialized - if err := sandbox.Setup(L); err != nil { - r.debugLog("Failed to set up sandbox for state %d: %v", index, err) + if err := sandbox.Setup(L, index); err != nil { + if verbose { + r.debugLogCont("Failed to set up sandbox for state %d: %v", index, err) + } L.Cleanup() L.Close() return nil, ErrInitFailed @@ -211,7 +228,9 @@ func (r *Runner) createState(index int) (*State, error) { // Preload all modules if err := r.moduleLoader.PreloadModules(L); err != nil { - r.debugLog("Failed to preload modules for state %d: %v", index, err) + if verbose { + r.debugLogCont("Failed to preload modules for state %d: %v", index, err) + } L.Cleanup() L.Close() return nil, errors.New("failed to preload modules") @@ -225,7 +244,9 @@ func (r *Runner) createState(index int) (*State, error) { initTime: time.Now(), } - r.debugLog("State %d created successfully", index) + if verbose { + r.debugLog("State %d created successfully", index) + } return state, nil } diff --git a/core/runner/Sandbox.go b/core/runner/Sandbox.go index b2b9c8a..e4ecf40 100644 --- a/core/runner/Sandbox.go +++ b/core/runner/Sandbox.go @@ -31,7 +31,14 @@ func (s *Sandbox) EnableDebug() { // debugLog logs a message if debug mode is enabled func (s *Sandbox) debugLog(format string, args ...interface{}) { if s.debug { - logger.Debug("[Sandbox] "+format, args...) + logger.Debug("Sandbox "+format, args...) + } +} + +// debugLog logs a message if debug mode is enabled +func (s *Sandbox) debugLogCont(format string, args ...interface{}) { + if s.debug { + logger.DebugCont(format, args...) } } @@ -45,16 +52,24 @@ func (s *Sandbox) AddModule(name string, module any) { } // Setup initializes the sandbox in a Lua state -func (s *Sandbox) Setup(state *luajit.State) error { - s.debugLog("Setting up sandbox environment") +func (s *Sandbox) Setup(state *luajit.State, stateIndex int) error { + verbose := stateIndex == 0 + + if verbose { + s.debugLog("is setting up...") + } // Register modules in the global environment s.mu.RLock() for name, module := range s.modules { - s.debugLog("Registering module: %s", name) + if verbose { + s.debugLog("is registering module: %s", name) + } if err := state.PushValue(module); err != nil { s.mu.RUnlock() - s.debugLog("Failed to register module %s: %v", name, err) + if verbose { + s.debugLog("failed to register module %s: %v", name, err) + } return err } state.SetGlobal(name) @@ -63,54 +78,59 @@ func (s *Sandbox) Setup(state *luajit.State) error { // Initialize environment setup err := state.DoString(` - -- Global tables for response handling - __http_responses = __http_responses or {} + -- Global tables for response handling + __http_responses = __http_responses or {} - -- Create environment inheriting from _G - function __create_env(ctx) - -- Create environment with metatable inheriting from _G - local env = setmetatable({}, {__index = _G}) + -- Create environment inheriting from _G + function __create_env(ctx) + -- Create environment with metatable inheriting from _G + local env = setmetatable({}, {__index = _G}) - -- Add context if provided - if ctx then - env.ctx = ctx - end + -- Add context if provided + if ctx then + env.ctx = ctx + end - -- Add proper require function to this environment - if __setup_require then - __setup_require(env) - end + -- Add proper require function to this environment + if __setup_require then + __setup_require(env) + end - return env - end + return env + end - -- Execute script with clean environment - function __execute_script(fn, ctx) - -- Clear previous responses - __http_responses[1] = nil + -- Execute script with clean environment + function __execute_script(fn, ctx) + -- Clear previous responses + __http_responses[1] = nil - -- Create environment - local env = __create_env(ctx) + -- Create environment + local env = __create_env(ctx) - -- Set environment for function - setfenv(fn, env) + -- Set environment for function + setfenv(fn, env) - -- Execute with protected call - local ok, result = pcall(fn) - if not ok then - error(result, 0) - end + -- Execute with protected call + local ok, result = pcall(fn) + if not ok then + error(result, 0) + end - return result - end - `) + return result + end + `) if err != nil { - s.debugLog("Failed to set up sandbox: %v", err) + if verbose { + s.debugLog("failed to set up...") + s.debugLogCont("%v", err) + } return err } - s.debugLog("Sandbox setup complete") + if verbose { + s.debugLogCont("Complete") + } return nil } diff --git a/core/watchers/Api.go b/core/watchers/Api.go index 39bf109..f65f29c 100644 --- a/core/watchers/Api.go +++ b/core/watchers/Api.go @@ -39,7 +39,6 @@ func WatchDirectory(config DirectoryWatcherConfig, manager *WatcherManager) (*Wa manager: manager, } - logger.Debug("Started watching directory: %s", config.Dir) return w, nil } diff --git a/core/watchers/Manager.go b/core/watchers/Manager.go index e196aa1..4a1c8c2 100644 --- a/core/watchers/Manager.go +++ b/core/watchers/Manager.go @@ -67,7 +67,7 @@ func (m *WatcherManager) AddWatcher(watcher *DirectoryWatcher) { defer m.mu.Unlock() m.watchers[watcher.dir] = watcher - logger.Debug("[WatcherManager] Added watcher for directory: %s", watcher.dir) + logger.Debug("WatcherManager added watcher for %s", watcher.dir) } // RemoveWatcher unregisters a directory watcher @@ -76,7 +76,7 @@ func (m *WatcherManager) RemoveWatcher(dir string) { defer m.mu.Unlock() delete(m.watchers, dir) - logger.Debug("[WatcherManager] Removed watcher for directory: %s", dir) + logger.Debug("WatcherManager removed watcher for %s", dir) } // pollLoop is the main polling loop that checks all watched directories diff --git a/main.go b/main.go index 632e3e2..3747583 100644 --- a/main.go +++ b/main.go @@ -1,6 +1,7 @@ package main import ( + "fmt" "os" "os/signal" "syscall" @@ -9,29 +10,25 @@ import ( ) func main() { - // Initialize global logger - logger.InitGlobalLogger(logger.LevelDebug, true) - logger.Server("Starting Moonshark server") + logger.InitGlobalLogger(logger.LevelDebug, true, false) + logger.Server("Moonshark is starting to prowl 🦈") - // Create and initialize server server, err := NewMoonshark("config.lua") if err != nil { logger.Fatal("Failed to initialize server: %v", err) } - // Start server if err := server.Start(); err != nil { logger.Fatal("Failed to start server: %v", err) } - // Wait for interrupt signal stop := make(chan os.Signal, 1) signal.Notify(stop, os.Interrupt, syscall.SIGTERM) <-stop + fmt.Print("\n") logger.Server("Shutdown signal received") - // Shutdown server if err := server.Shutdown(); err != nil { logger.Error("Error during shutdown: %v", err) os.Exit(1)