11 KiB
11 KiB
Logging System Usage Examples
This document provides comprehensive examples and documentation for using the new structured logging system in the ACC Server Manager.
Overview
The logging system has been refactored to provide:
- Structured logging with separate files for each log level
- Base logger providing core functionality
- Centralized error handling for controllers
- Backward compatibility with existing code
Architecture
logging/
├── base.go # Base logger with core functionality
├── error.go # Error-specific logging
├── warn.go # Warning-specific logging
├── info.go # Info-specific logging
├── debug.go # Debug-specific logging
└── logger.go # Main logger for backward compatibility
Basic Usage
Simple Logging (Backward Compatible)
import "acc-server-manager/local/utl/logging"
// These work exactly as before
logging.Info("Server started on port %d", 8080)
logging.Error("Failed to connect to database: %v", err)
logging.Warn("Configuration value missing, using default")
logging.Debug("Processing request with ID: %s", requestID)
Enhanced Logging with Context
// Error logging with context
logging.ErrorWithContext("DATABASE", "Connection failed: %v", err)
logging.ErrorWithContext("AUTH", "Invalid credentials for user: %s", username)
// Info logging with context
logging.InfoWithContext("STARTUP", "Service initialized: %s", serviceName)
logging.InfoWithContext("SHUTDOWN", "Gracefully shutting down service: %s", serviceName)
// Warning with context
logging.WarnWithContext("CONFIG", "Missing configuration key: %s", configKey)
// Debug with context
logging.DebugWithContext("REQUEST", "Processing API call: %s", endpoint)
Specialized Logging Functions
// Application lifecycle
logging.LogStartup("DATABASE", "Connection pool initialized")
logging.LogShutdown("API_SERVER", "HTTP server stopped")
// Operations tracking
logging.LogOperation("USER_CREATE", "Created user with ID: " + userID.String())
logging.LogOperation("SERVER_START", "Started ACC server: " + serverName)
// HTTP request/response logging
logging.LogRequest("GET", "/api/v1/servers", "Mozilla/5.0...")
logging.LogResponse("GET", "/api/v1/servers", 200, "15ms")
// Error object logging
logging.LogError(err, "Failed to parse configuration file")
// Performance and debugging
logging.LogSQL("SELECT * FROM servers WHERE active = ?", true)
logging.LogMemory() // Logs current memory usage
logging.LogTiming("database_query", duration)
Direct Logger Instances
// Get specific logger instances for advanced usage
errorLogger := logging.GetErrorLogger()
infoLogger := logging.GetInfoLogger()
debugLogger := logging.GetDebugLogger()
warnLogger := logging.GetWarnLogger()
// Use specific logger methods
errorLogger.LogWithStackTrace("Critical system error occurred")
debugLogger.LogVariable("userConfig", userConfigObject)
debugLogger.LogState("cache", cacheState)
warnLogger.LogDeprecation("OldFunction", "NewFunction")
Controller Error Handling
Using the Centralized Error Handler
package controller
import (
"acc-server-manager/local/utl/error_handler"
"github.com/gofiber/fiber/v2"
)
type MyController struct {
service *MyService
errorHandler *error_handler.ControllerErrorHandler
}
func NewMyController(service *MyService) *MyController {
return &MyController{
service: service,
errorHandler: error_handler.NewControllerErrorHandler(),
}
}
func (mc *MyController) GetUser(c *fiber.Ctx) error {
userID, err := uuid.Parse(c.Params("id"))
if err != nil {
// Automatically logs error and returns standardized response
return mc.errorHandler.HandleUUIDError(c, "user ID")
}
user, err := mc.service.GetUser(userID)
if err != nil {
// Logs error with context and returns appropriate HTTP status
return mc.errorHandler.HandleServiceError(c, err)
}
return c.JSON(user)
}
func (mc *MyController) CreateUser(c *fiber.Ctx) error {
var user User
if err := c.BodyParser(&user); err != nil {
return mc.errorHandler.HandleParsingError(c, err)
}
if err := mc.service.CreateUser(&user); err != nil {
return mc.errorHandler.HandleServiceError(c, err)
}
return c.JSON(user)
}
Available Error Handler Methods
// Generic error handling
HandleError(c *fiber.Ctx, err error, statusCode int, context ...string)
// Specific error types
HandleValidationError(c *fiber.Ctx, err error, field string)
HandleDatabaseError(c *fiber.Ctx, err error)
HandleAuthError(c *fiber.Ctx, err error)
HandleNotFoundError(c *fiber.Ctx, resource string)
HandleBusinessLogicError(c *fiber.Ctx, err error)
HandleServiceError(c *fiber.Ctx, err error)
HandleParsingError(c *fiber.Ctx, err error)
HandleUUIDError(c *fiber.Ctx, field string)
Global Error Handler Functions
import "acc-server-manager/local/utl/error_handler"
// Use global error handler functions for convenience
func (mc *MyController) SomeEndpoint(c *fiber.Ctx) error {
if err := someOperation(); err != nil {
return error_handler.HandleServiceError(c, err)
}
return c.JSON(result)
}
Request Logging Middleware
Setup Request Logging
import (
middlewareLogging "acc-server-manager/local/middleware/logging"
)
func setupRoutes(app *fiber.App) {
// Add request logging middleware
app.Use(middlewareLogging.Handler())
// Your routes here...
}
This will automatically log:
- Incoming requests with method, URL, and user agent
- Outgoing responses with status code and duration
- Any errors that occur during request processing
Advanced Usage Examples
Custom Logger with Specific Configuration
// Create a custom base logger instance
baseLogger, err := logging.InitializeBase()
if err != nil {
log.Fatal("Failed to initialize logger")
}
// Create specialized loggers
errorLogger := logging.NewErrorLogger()
debugLogger := logging.NewDebugLogger()
// Use them directly
errorLogger.LogWithStackTrace("Critical error in payment processing")
debugLogger.LogMemory()
debugLogger.LogGoroutines()
Panic Recovery and Logging
func dangerousOperation() {
defer logging.RecoverAndLog()
// Your potentially panicking code here
// If panic occurs, it will be logged with full stack trace
}
Performance Monitoring
func processRequest() {
start := time.Now()
defer func() {
duration := time.Since(start)
logging.LogTiming("request_processing", duration)
}()
// Log memory usage periodically
logging.LogMemory()
// Your processing logic here
}
Database Query Logging
func (r *Repository) GetUser(id uuid.UUID) (*User, error) {
query := "SELECT * FROM users WHERE id = ?"
logging.LogSQL(query, id)
var user User
err := r.db.Get(&user, query, id)
if err != nil {
logging.ErrorWithContext("DATABASE", "Failed to get user %s: %v", id, err)
return nil, err
}
return &user, nil
}
Migration Guide
For Existing Code
Your existing logging calls will continue to work:
// These still work exactly as before
logging.Info("Message")
logging.Error("Error: %v", err)
logging.Warn("Warning message")
logging.Debug("Debug info")
Upgrading to New Features
Consider upgrading to new features gradually:
// Instead of:
logging.Error("Database error: %v", err)
// Use:
logging.ErrorWithContext("DATABASE", "Connection failed: %v", err)
// or
logging.LogError(err, "Database connection failed")
Controller Updates
Replace manual error handling:
// Old way:
if err != nil {
logging.Error("Service error: %v", err)
return c.Status(500).JSON(fiber.Map{"error": err.Error()})
}
// New way:
if err != nil {
return mc.errorHandler.HandleServiceError(c, err)
}
Configuration
Log Levels
The system automatically handles different log levels. All logs are written to the same file but with different level indicators:
[2024-01-15 10:30:45.123] [INFO] [server.go:45] Server started successfully
[2024-01-15 10:30:46.456] [ERROR] [database.go:12] Connection failed: timeout
[2024-01-15 10:30:47.789] [WARN] [config.go:67] Using default configuration
[2024-01-15 10:30:48.012] [DEBUG] [handler.go:23] Processing request ID: 12345
File Organization
Logs are automatically organized by date in the logs/ directory:
logs/acc-server-2024-01-15.loglogs/acc-server-2024-01-16.log
Output Destinations
All logs are written to both:
- Console (stdout) for development
- Log files for persistence
Best Practices
- Use contextual logging for better debugging
- Use appropriate log levels (DEBUG for development, INFO for operations, WARN for issues, ERROR for failures)
- Use the error handler in controllers for consistent error responses
- Include relevant information in log messages (IDs, timestamps, etc.)
- Avoid logging sensitive information (passwords, tokens, etc.)
- Use structured fields when possible for better parsing
Examples by Use Case
API Controller Logging
func (ac *APIController) CreateServer(c *fiber.Ctx) error {
var server Server
if err := c.BodyParser(&server); err != nil {
return ac.errorHandler.HandleParsingError(c, err)
}
logging.InfoOperation("SERVER_CREATE", fmt.Sprintf("Creating server: %s", server.Name))
if err := ac.service.CreateServer(&server); err != nil {
return ac.errorHandler.HandleServiceError(c, err)
}
logging.InfoOperation("SERVER_CREATE", fmt.Sprintf("Successfully created server: %s (ID: %s)", server.Name, server.ID))
return c.JSON(server)
}
Service Layer Logging
func (s *ServerService) StartServer(serverID uuid.UUID) error {
logging.InfoWithContext("SERVER_SERVICE", "Starting server %s", serverID)
server, err := s.repository.GetServer(serverID)
if err != nil {
logging.ErrorWithContext("SERVER_SERVICE", "Failed to get server %s: %v", serverID, err)
return err
}
logging.DebugState("server_config", server)
if err := s.processManager.Start(server); err != nil {
logging.ErrorWithContext("SERVER_SERVICE", "Failed to start server %s: %v", serverID, err)
return err
}
logging.InfoOperation("SERVER_START", fmt.Sprintf("Server %s started successfully", server.Name))
return nil
}
This new logging system provides comprehensive error handling and logging capabilities while maintaining backward compatibility with existing code.