112 lines
2.9 KiB
Go
112 lines
2.9 KiB
Go
package logging
|
|
|
|
import (
|
|
"io"
|
|
"os"
|
|
"path/filepath"
|
|
"time"
|
|
|
|
"counter/internal/infrastructure/config"
|
|
|
|
"github.com/gin-gonic/gin"
|
|
"github.com/sirupsen/logrus"
|
|
)
|
|
|
|
// Logger interface defines the contract for logging
|
|
type Logger interface {
|
|
Info(args ...interface{})
|
|
Infof(format string, args ...interface{})
|
|
Warn(args ...interface{})
|
|
Warnf(format string, args ...interface{})
|
|
Error(args ...interface{})
|
|
Errorf(format string, args ...interface{})
|
|
Fatal(args ...interface{})
|
|
Fatalf(format string, args ...interface{})
|
|
WithFields(fields logrus.Fields) *logrus.Entry
|
|
WithError(err error) *logrus.Entry
|
|
}
|
|
|
|
// LogrusLogger implements the Logger interface using logrus
|
|
type LogrusLogger struct {
|
|
*logrus.Logger
|
|
}
|
|
|
|
// InitLogger initializes the structured logger with file output
|
|
func InitLogger(cfg *config.Config) (Logger, error) {
|
|
logger := logrus.New()
|
|
|
|
// Set log level based on configuration
|
|
level, err := logrus.ParseLevel(cfg.LogLevel)
|
|
if err != nil {
|
|
level = logrus.InfoLevel
|
|
}
|
|
logger.SetLevel(level)
|
|
|
|
// Set JSON formatter for structured logging
|
|
logger.SetFormatter(&logrus.JSONFormatter{
|
|
TimestampFormat: time.RFC3339,
|
|
FieldMap: logrus.FieldMap{
|
|
logrus.FieldKeyTime: "timestamp",
|
|
logrus.FieldKeyLevel: "level",
|
|
logrus.FieldKeyMsg: "message",
|
|
},
|
|
})
|
|
|
|
// Create log directory if it doesn't exist
|
|
if err := os.MkdirAll(cfg.LogDir, 0755); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
// Create log file with timestamp
|
|
logFile := filepath.Join(cfg.LogDir, "app.log")
|
|
file, err := os.OpenFile(logFile, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0666)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
// Set output to both file and stdout
|
|
multiWriter := io.MultiWriter(os.Stdout, file)
|
|
logger.SetOutput(multiWriter)
|
|
|
|
// Log initialization with default fields
|
|
logger.WithFields(logrus.Fields{
|
|
"service": "counter-app",
|
|
"environment": string(cfg.Environment),
|
|
"version": "1.0.0",
|
|
}).Info("Logger initialized successfully")
|
|
|
|
return &LogrusLogger{Logger: logger}, nil
|
|
}
|
|
|
|
// LoggingMiddleware creates a Gin middleware for HTTP request logging
|
|
func LoggingMiddleware(logger Logger, cfg *config.Config) gin.HandlerFunc {
|
|
return gin.LoggerWithFormatter(func(param gin.LogFormatterParams) string {
|
|
// Create structured log entry with default fields
|
|
entry := logger.WithFields(logrus.Fields{
|
|
"service": "counter-app",
|
|
"environment": string(cfg.Environment),
|
|
"version": "1.0.0",
|
|
"method": param.Method,
|
|
"path": param.Path,
|
|
"status": param.StatusCode,
|
|
"latency": param.Latency.String(),
|
|
"client_ip": param.ClientIP,
|
|
"user_agent": param.Request.UserAgent(),
|
|
"timestamp": param.TimeStamp.Format(time.RFC3339),
|
|
})
|
|
|
|
// Set log level based on status code
|
|
switch {
|
|
case param.StatusCode >= 500:
|
|
entry.Error("HTTP Request")
|
|
case param.StatusCode >= 400:
|
|
entry.Warn("HTTP Request")
|
|
default:
|
|
entry.Info("HTTP Request")
|
|
}
|
|
|
|
// Return empty string since we're handling logging ourselves
|
|
return ""
|
|
})
|
|
}
|