go
42 lines · 6 steps
Building a request logger middleware in Gin
A Gin middleware that times each request and logs its outcome at a severity matching the response status.
Explained by
highlit
1package middleware
2
3import (
4 "time"
5
6 "github.com/gin-gonic/gin"
7 "github.com/rs/zerolog"
8)
9
10func RequestLogger(logger zerolog.Logger) gin.HandlerFunc {
11 return func(c *gin.Context) {
12 start := time.Now()
13 path := c.Request.URL.Path
14 if raw := c.Request.URL.RawQuery; raw != "" {
15 path = path + "?" + raw
16 }
17
18 c.Next()
19
20 latency := time.Since(start)
21 status := c.Writer.Status()
22
23 evt := logger.Info()
24 if len(c.Errors) > 0 {
25 evt = logger.Error().Str("errors", c.Errors.String())
26 } else if status >= 500 {
27 evt = logger.Error()
28 } else if status >= 400 {
29 evt = logger.Warn()
30 }
31
32 evt.
33 Str("method", c.Request.Method).
34 Str("path", path).
35 Int("status", status).
36 Dur("latency", latency).
37 Int("bytes", c.Writer.Size()).
38 Str("client_ip", c.ClientIP()).
39 Str("request_id", c.GetString("request_id")).
40 Msg("handled request")
41 }
42}
01 / 01
STEP 01
‹ swipe to step through ›
Walkthrough
Space play
←→ step
click any line
Three takeaways
- 1Middleware can wrap the rest of the chain by capturing state before `c.Next()` and reading results after it returns.
- 2Choosing log level from status code and errors keeps noise low while surfacing real failures.
- 3Returning a closure over a dependency like a logger is Go's idiomatic way to inject configuration into a handler.
Related explainers
go
package breaker import ( "errors"
How a circuit breaker works in Go
circuit-breaker
state-machine
concurrency
Intermediate
8 steps
typescript
import { Controller, All, Req,
Catch-all routes and error shaping in NestJS
exception-handling
routing
middleware
Intermediate
6 steps
go
package middleware import ( "net/http"
Role-based access control middleware in Gin
middleware
authorization
closures
Intermediate
7 steps
python
from fastapi import FastAPI, Request, status from fastapi.encoders import jsonable_encoder from fastapi.exceptions import RequestValidationError from fastapi.responses import JSONResponse
Redacting sensitive fields in FastAPI errors
validation
error-handling
security
Intermediate
7 steps
go
func UserDashboardCache(rdb *redis.Client, ttl time.Duration) gin.HandlerFunc { return func(c *gin.Context) { claims, ok := c.Get("claims") if !ok {
Per-user response caching in Gin with Redis
middleware
caching
redis
Advanced
9 steps
rust
use std::{collections::HashSet, sync::Arc}; use axum::{ body::Body,
Feature-flag middleware in Axum
middleware
async
shared-state
Advanced
7 steps
Share this explainer
Here's the card — post it anywhere.
Made with highlit — turn any snippet into a walkthrough like this in about a minute.
Explain your code
Embed this explainer
Drop the interactive walkthrough into a blog or docs. Views never cost a credit.
<iframe src="https://highlit.co/explainers/building-a-request-logger-middleware-in-gin-explained-go-ac68/embed?autoplay=1" width="100%" height="520" loading="lazy" style="border:0"></iframe>
Autoplay is on by default — add ?autoplay=0 to start paused.