- Add new `app` package to manage application initialization and lifecycle - Refactor `main.go` to use new application management approach - Implement graceful shutdown with context timeout and signal handling - Add dependency injection container initialization - Enhance logging with configurable log levels and structured logging - Update configuration loading and server initialization process - Modify Jitsi configuration in `.env` for custom deployment - Improve error handling and logging throughout application startup - Centralize application startup and shutdown logic in single package Introduces a more robust and flexible application management system with improved initialization, logging, and shutdown capabilities.
115 lines
2.7 KiB
Go
115 lines
2.7 KiB
Go
package middleware
|
|
|
|
import (
|
|
"attune-heart-therapy/internal/logger"
|
|
"fmt"
|
|
"time"
|
|
|
|
"github.com/gin-gonic/gin"
|
|
)
|
|
|
|
// LoggingMiddleware creates a custom logging middleware with detailed request information
|
|
func LoggingMiddleware() gin.HandlerFunc {
|
|
return gin.LoggerWithFormatter(func(param gin.LogFormatterParams) string {
|
|
// Custom log format with more details
|
|
return fmt.Sprintf("[%s] %s %s %s %d %s \"%s\" %s \"%s\" %s\n",
|
|
param.TimeStamp.Format("2006-01-02 15:04:05"),
|
|
param.ClientIP,
|
|
param.Method,
|
|
param.Path,
|
|
param.StatusCode,
|
|
param.Latency,
|
|
param.Request.UserAgent(),
|
|
param.ErrorMessage,
|
|
param.Request.Referer(),
|
|
formatBodySize(param.BodySize),
|
|
)
|
|
})
|
|
}
|
|
|
|
// StructuredLoggingMiddleware creates a structured logging middleware for better log parsing
|
|
func StructuredLoggingMiddleware() gin.HandlerFunc {
|
|
log := logger.New("http")
|
|
|
|
return func(c *gin.Context) {
|
|
// Start timer
|
|
start := time.Now()
|
|
path := c.Request.URL.Path
|
|
raw := c.Request.URL.RawQuery
|
|
|
|
// Process request
|
|
c.Next()
|
|
|
|
// Calculate latency
|
|
latency := time.Since(start)
|
|
|
|
// Build full path with query string
|
|
if raw != "" {
|
|
path = path + "?" + raw
|
|
}
|
|
|
|
// Prepare log fields
|
|
fields := map[string]interface{}{
|
|
"method": c.Request.Method,
|
|
"path": path,
|
|
"status": c.Writer.Status(),
|
|
"latency_ms": latency.Milliseconds(),
|
|
"client_ip": c.ClientIP(),
|
|
"body_size": c.Writer.Size(),
|
|
"user_agent": c.Request.UserAgent(),
|
|
}
|
|
|
|
// Add trace ID if available
|
|
if traceID, exists := c.Get("trace_id"); exists {
|
|
fields["trace_id"] = traceID
|
|
}
|
|
|
|
// Add user ID if available
|
|
if userID, exists := c.Get("user_id"); exists {
|
|
fields["user_id"] = userID
|
|
}
|
|
|
|
// Log based on status code
|
|
statusCode := c.Writer.Status()
|
|
|
|
if statusCode >= 500 {
|
|
log.Error("HTTP request completed with server error", nil, fields)
|
|
} else if statusCode >= 400 {
|
|
log.Warn("HTTP request completed with client error", fields)
|
|
} else {
|
|
log.Info("HTTP request completed successfully", fields)
|
|
}
|
|
|
|
// Log errors if any
|
|
if len(c.Errors) > 0 {
|
|
errorFields := map[string]interface{}{
|
|
"method": c.Request.Method,
|
|
"path": path,
|
|
"client_ip": c.ClientIP(),
|
|
"errors": c.Errors.String(),
|
|
}
|
|
log.Error("Request completed with errors", c.Errors.Last().Err, errorFields)
|
|
}
|
|
}
|
|
}
|
|
|
|
// formatBodySize formats body size in human readable format
|
|
func formatBodySize(size int) string {
|
|
if size == 0 {
|
|
return "0B"
|
|
}
|
|
|
|
const unit = 1024
|
|
if size < unit {
|
|
return fmt.Sprintf("%dB", size)
|
|
}
|
|
|
|
div, exp := int64(unit), 0
|
|
for n := size / unit; n >= unit; n /= unit {
|
|
div *= unit
|
|
exp++
|
|
}
|
|
|
|
return fmt.Sprintf("%.1f%cB", float64(size)/float64(div), "KMGTPE"[exp])
|
|
}
|