The implementation methods for logging and monitoring in the Gin framework are as follows:
1. Logging overview
The Gin framework has built-in basic logging capabilities and also supports integration with third-party logging libraries such as logrus, zap, zerolog, etc.
2. Using built-in logging
2.1 Basic logging
goimport "github.com/gin-gonic/gin" func main() { // Set Gin mode gin.SetMode(gin.DebugMode) // or gin.ReleaseMode r := gin.Default() // Default includes Logger and Recovery middleware r.GET("/", func(c *gin.Context) { c.String(200, "Hello World") }) r.Run(":8080") }
2.2 Custom log format
gofunc main() { r := gin.New() // Custom logging middleware r.Use(gin.LoggerWithFormatter(func(param gin.LogFormatterParams) string { return fmt.Sprintf("[%s] %s %s %d %s\n", param.TimeStamp.Format("2006-01-02 15:04:05"), param.Method, param.Path, param.StatusCode, param.Latency, ) })) r.Use(gin.Recovery()) r.GET("/", func(c *gin.Context) { c.String(200, "Hello World") }) r.Run(":8080") }
3. Integrating logrus
3.1 Configuring logrus
goimport ( "github.com/gin-gonic/gin" "github.com/sirupsen/logrus" ) var log = logrus.New() func init() { log.SetFormatter(&logrus.JSONFormatter{}) log.SetOutput(os.Stdout) log.SetLevel(logrus.InfoLevel) } func logrusMiddleware() gin.HandlerFunc { return func(c *gin.Context) { startTime := time.Now() c.Next() latency := time.Since(startTime) status := c.Writer.Status() entry := log.WithFields(logrus.Fields{ "method": c.Request.Method, "path": c.Request.URL.Path, "status": status, "latency": latency, "ip": c.ClientIP(), "user-agent": c.Request.UserAgent(), }) if status >= 500 { entry.Error("Server error") } else if status >= 400 { entry.Warn("Client error") } else { entry.Info("Request completed") } } }
3.2 Using logrus
gofunc main() { r := gin.New() r.Use(logrusMiddleware()) r.Use(gin.Recovery()) r.GET("/", func(c *gin.Context) { log.Info("Processing request") c.String(200, "Hello World") }) r.Run(":8080") }
4. Integrating zap
4.1 Configuring zap
goimport ( "go.uber.org/zap" "go.uber.org/zap/zapcore" ) var logger *zap.Logger func initLogger() { config := zap.NewProductionConfig() config.EncoderConfig.TimeKey = "timestamp" config.EncoderConfig.EncodeTime = zapcore.ISO8601TimeEncoder var err error logger, err = config.Build() if err != nil { panic(err) } } func zapMiddleware() gin.HandlerFunc { return func(c *gin.Context) { start := time.Now() path := c.Request.URL.Path query := c.Request.URL.RawQuery c.Next() latency := time.Since(start) status := c.Writer.Status() logger.Info("Request", zap.String("method", c.Request.Method), zap.String("path", path), zap.String("query", query), zap.Int("status", status), zap.Duration("latency", latency), zap.String("ip", c.ClientIP()), ) } }
5. Request tracing
5.1 Adding request ID
goimport "github.com/google/uuid" func requestIDMiddleware() gin.HandlerFunc { return func(c *gin.Context) { requestID := c.GetHeader("X-Request-ID") if requestID == "" { requestID = uuid.New().String() } c.Set("request_id", requestID) c.Header("X-Request-ID", requestID) c.Next() } }
5.2 Distributed tracing
goimport ( "go.opentelemetry.io/otel" "go.opentelemetry.io/otel/trace" ) func tracingMiddleware() gin.HandlerFunc { return func(c *gin.Context) { tracer := otel.Tracer("gin-server") ctx, span := tracer.Start(c.Request.Context(), c.Request.URL.Path) defer span.End() c.Request = c.Request.WithContext(ctx) c.Next() } }
6. Performance monitoring
6.1 Prometheus metrics
goimport ( "github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus/promauto" ) var ( httpDuration = promauto.NewHistogramVec(prometheus.HistogramOpts{ Name: "http_request_duration_seconds", Help: "HTTP request duration in seconds", }, []string{"method", "path", "status"}) httpRequestsTotal = promauto.NewCounterVec(prometheus.CounterOpts{ Name: "http_requests_total", Help: "Total number of HTTP requests", }, []string{"method", "path", "status"}) ) func prometheusMiddleware() gin.HandlerFunc { return func(c *gin.Context) { start := time.Now() c.Next() duration := time.Since(start).Seconds() status := strconv.Itoa(c.Writer.Status()) httpDuration.WithLabelValues(c.Request.Method, c.FullPath(), status).Observe(duration) httpRequestsTotal.WithLabelValues(c.Request.Method, c.FullPath(), status).Inc() } }
6.2 Exposing metrics endpoint
goimport "github.com/prometheus/client_golang/prometheus/promhttp" func setupMetrics(r *gin.Engine) { r.GET("/metrics", gin.WrapH(promhttp.Handler())) }
7. Error monitoring
7.1 Sentry integration
goimport "github.com/getsentry/sentry-go" func initSentry() { err := sentry.Init(sentry.ClientOptions{ Dsn: "your-sentry-dsn", }) if err != nil { panic(err) } } func sentryMiddleware() gin.HandlerFunc { return func(c *gin.Context) { hub := sentry.CurrentHub().Clone() hub.Scope().SetRequest(c.Request) c.Set("sentry", hub) defer func() { if err := recover(); err != nil { hub.CaptureException(err.(error)) c.JSON(500, gin.H{"error": "Internal server error"}) c.Abort() } }() c.Next() } }
8. Structured logging
8.1 Using structured fields
gofunc logStructured(c *gin.Context) { log.WithFields(logrus.Fields{ "request_id": c.GetString("request_id"), "user_id": c.GetInt("user_id"), "action": "user_login", "ip": c.ClientIP(), }).Info("User logged in") }
8.2 Log level control
gofunc logWithLevel(c *gin.Context, err error) { if err == nil { log.Info("Operation successful") return } switch { case errors.Is(err, ErrNotFound): log.WithField("error", err).Warn("Resource not found") case errors.Is(err, ErrUnauthorized): log.WithField("error", err).Warn("Unauthorized access") default: log.WithField("error", err).Error("Internal error") } }
9. Log rotation
9.1 Using lumberjack
goimport "gopkg.in/natefinch/lumberjack.v2" func setupRotatingLogger() { log.SetOutput(&lumberjack.Logger{ Filename: "app.log", MaxSize: 100, // MB MaxBackups: 3, MaxAge: 28, // days Compress: true, }) }
10. Best practices
-
Log content
- Record request ID for tracing
- Include timestamp, method, path, status code
- Record key business operations
- Avoid logging sensitive information
-
Log levels
- Debug: Development debugging information
- Info: Normal business flow
- Warn: Potential issues
- Error: Errors but recoverable
- Fatal: Fatal errors
-
Performance considerations
- Use asynchronous logging
- Avoid logging detailed information in hot paths
- Use structured logging for easy parsing
- Reasonably set log levels
-
Monitoring metrics
- Request latency distribution
- Request success rate
- Error rate
- Concurrent connections
- Memory and CPU usage
-
Alert configuration
- Set error rate thresholds
- Configure latency alerts
- Monitor resource usage
- Set log anomaly detection
Through the above methods, you can implement a comprehensive logging and monitoring system in the Gin framework.