Files
websocket-qris/pkg/logger/middleware.go
2025-09-24 18:42:16 +07:00

192 lines
4.9 KiB
Go

package logger
import (
"bytes"
"io"
"strings"
"time"
"github.com/gin-gonic/gin"
"github.com/google/uuid"
)
// RequestLoggerMiddleware creates a Gin middleware for request logging
func RequestLoggerMiddleware(logger *Logger) gin.HandlerFunc {
return func(c *gin.Context) {
// Generate request ID if not present
requestID := c.GetHeader("X-Request-ID")
if requestID == "" {
requestID = uuid.New().String()
c.Header("X-Request-ID", requestID)
}
// Get correlation ID
correlationID := c.GetHeader("X-Correlation-ID")
if correlationID == "" {
correlationID = uuid.New().String()
c.Header("X-Correlation-ID", correlationID)
}
// Create request-scoped logger
reqLogger := logger.
WithRequestID(requestID).
WithCorrelationID(correlationID)
// Store logger in context
c.Set("logger", reqLogger)
c.Set("request_id", requestID)
c.Set("correlation_id", correlationID)
// Capture request body for logging if needed
var requestBody []byte
if c.Request.Body != nil && strings.HasPrefix(c.ContentType(), "application/json") {
requestBody, _ = io.ReadAll(c.Request.Body)
c.Request.Body = io.NopCloser(bytes.NewBuffer(requestBody))
}
// Start timer
start := time.Now()
// Log request start
reqLogger.Info("Request started", map[string]interface{}{
"method": c.Request.Method,
"path": c.Request.URL.Path,
"query": c.Request.URL.RawQuery,
"remote_addr": c.Request.RemoteAddr,
"user_agent": c.Request.UserAgent(),
"content_type": c.ContentType(),
"body_size": len(requestBody),
})
// Process request
c.Next()
// Calculate duration
duration := time.Since(start)
// Get response status
status := c.Writer.Status()
responseSize := c.Writer.Size()
// Log level based on status code
var logLevel LogLevel
switch {
case status >= 500:
logLevel = ERROR
case status >= 400:
logLevel = WARN
default:
logLevel = INFO
}
// Log request completion
fields := map[string]interface{}{
"method": c.Request.Method,
"path": c.Request.URL.Path,
"status": status,
"duration": duration.String(),
"duration_ms": duration.Milliseconds(),
"response_size": responseSize,
"client_ip": c.ClientIP(),
"user_agent": c.Request.UserAgent(),
"content_type": c.ContentType(),
"content_length": c.Request.ContentLength,
}
// Add query parameters if present
if c.Request.URL.RawQuery != "" {
fields["query"] = c.Request.URL.RawQuery
}
// Add error information if present
if len(c.Errors) > 0 {
errors := make([]string, len(c.Errors))
for i, err := range c.Errors {
errors[i] = err.Error()
}
fields["errors"] = errors
}
reqLogger.log(logLevel, "Request completed", &duration, fields)
}
}
// GetLoggerFromContext retrieves the logger from Gin context
func GetLoggerFromContext(c *gin.Context) *Logger {
if logger, exists := c.Get("logger"); exists {
if l, ok := logger.(*Logger); ok {
return l
}
}
return globalLogger
}
// GetRequestIDFromContext retrieves the request ID from Gin context
func GetRequestIDFromContext(c *gin.Context) string {
if requestID, exists := c.Get("request_id"); exists {
if id, ok := requestID.(string); ok {
return id
}
}
return ""
}
// GetCorrelationIDFromContext retrieves the correlation ID from Gin context
func GetCorrelationIDFromContext(c *gin.Context) string {
if correlationID, exists := c.Get("correlation_id"); exists {
if id, ok := correlationID.(string); ok {
return id
}
}
return ""
}
// DatabaseLoggerMiddleware creates middleware for database operation logging
func DatabaseLoggerMiddleware(logger *Logger, serviceName string) gin.HandlerFunc {
return func(c *gin.Context) {
reqLogger := GetLoggerFromContext(c).WithService(serviceName)
c.Set("db_logger", reqLogger)
c.Next()
}
}
// GetDBLoggerFromContext retrieves the database logger from Gin context
func GetDBLoggerFromContext(c *gin.Context) *Logger {
if logger, exists := c.Get("db_logger"); exists {
if l, ok := logger.(*Logger); ok {
return l
}
}
return GetLoggerFromContext(c)
}
// ServiceLogger creates a service-specific logger
func ServiceLogger(serviceName string) *Logger {
return globalLogger.WithService(serviceName)
}
// AuthServiceLogger returns a logger for auth service
func AuthServiceLogger() *Logger {
return ServiceLogger("auth-service")
}
// BPJSServiceLogger returns a logger for BPJS service
func BPJSServiceLogger() *Logger {
return ServiceLogger("bpjs-service")
}
// RetribusiServiceLogger returns a logger for retribusi service
func RetribusiServiceLogger() *Logger {
return ServiceLogger("retribusi-service")
}
// DatabaseServiceLogger returns a logger for database operations
func DatabaseServiceLogger() *Logger {
return ServiceLogger("database-service")
}
// MiddlewareServiceLogger returns a logger for middleware operations
func MiddlewareServiceLogger() *Logger {
return ServiceLogger("middleware-service")
}