Files
acc-server-manager/documentation/LOGGING_USAGE_EXAMPLES.md
2025-06-30 22:50:52 +02:00

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.log
  • logs/acc-server-2024-01-16.log

Output Destinations

All logs are written to both:

  • Console (stdout) for development
  • Log files for persistence

Best Practices

  1. Use contextual logging for better debugging
  2. Use appropriate log levels (DEBUG for development, INFO for operations, WARN for issues, ERROR for failures)
  3. Use the error handler in controllers for consistent error responses
  4. Include relevant information in log messages (IDs, timestamps, etc.)
  5. Avoid logging sensitive information (passwords, tokens, etc.)
  6. 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.