Documentation Index
Fetch the complete documentation index at: https://docs.go-mizu.dev/llms.txt
Use this file to discover all available pages before exploring further.
Overview
The logger middleware logs HTTP requests with configurable format, output destination, and filtering. It captures method, path, status, latency, and custom fields.
Use it when you need:
- HTTP request logging
- Access logs for debugging
- Request timing metrics
Installation
import "github.com/go-mizu/mizu/middlewares/logger"
Quick Start
app := mizu.New()
// Default logger (stdout)
app.Use(logger.New())
app.Get("/", func(c *mizu.Ctx) error {
return c.Text(200, "Hello!")
})
// Output: 2024/01/15 10:30:00 | 200 | 1.2ms | GET /
Configuration
Options
| Option | Type | Default | Description |
|---|
Output | io.Writer | os.Stdout | Log output destination |
Format | string | Default format | Log format template |
Skip | func(*mizu.Ctx) bool | nil | Skip logging for requests |
| Tag | Description |
|---|
${method} | HTTP method |
${path} | Request path |
${status} | Response status code |
${latency} | Request duration |
${ip} | Client IP address |
${host} | Request host |
${protocol} | HTTP protocol |
${referer} | Referer header |
${user_agent} | User-Agent header |
${bytes_out} | Response size |
${query} | Query string |
${header:X-Name} | Custom header value |
Examples
Default Logger
app.Use(logger.WithOptions(logger.Options{
Format: "[${method}] ${path} -> ${status}\n",
}))
// Output: [GET] /api/users -> 200
app.Use(logger.WithOptions(logger.Options{
Format: `{"method":"${method}","path":"${path}","status":${status},"latency":"${latency}"}` + "\n",
}))
Write to File
file, _ := os.OpenFile("access.log", os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644)
app.Use(logger.WithOptions(logger.Options{
Output: file,
}))
Skip Health Checks
app.Use(logger.WithOptions(logger.Options{
Skip: func(c *mizu.Ctx) bool {
return c.Request().URL.Path == "/health"
},
}))
Include Request ID
app.Use(logger.WithOptions(logger.Options{
Format: "${header:X-Request-ID} | ${method} ${path} | ${status}\n",
}))
Full Access Log
app.Use(logger.WithOptions(logger.Options{
Format: `${ip} - [${time}] "${method} ${path} ${protocol}" ${status} ${bytes_out} "${referer}" "${user_agent}"` + "\n",
}))
API Reference
Functions
// New creates logger middleware with defaults
func New() mizu.Middleware
// WithOptions creates logger middleware with configuration
func WithOptions(opts Options) mizu.Middleware
Technical Details
Implementation Architecture
The logger middleware captures HTTP request metrics by wrapping the response writer and measuring execution time:
-
Response Writer Wrapping: A custom
responseWriter type wraps the standard http.ResponseWriter to capture:
- HTTP status code (defaults to 200)
- Response size in bytes
-
Timing Measurement: Uses
time.Now() before request processing and time.Since() after to calculate latency with nanosecond precision.
-
Client IP Detection: Implements intelligent IP extraction with fallback chain:
- Checks
X-Forwarded-For header (uses first IP if comma-separated list)
- Checks
X-Real-IP header
- Falls back to
RemoteAddr from the request
-
Format String Processing: The
formatLog function performs template tag replacement:
- Basic tags use
strings.ReplaceAll() for simple substitution
- Dynamic tags (
${header:name}, ${form:name}) use index-based parsing to extract custom values
- Supports all standard HTTP request/response attributes
-
Skip Function: Optional predicate function allows conditional logging based on request context, executed before timing starts to avoid overhead.
- Minimal overhead: Single writer wrap and string replacement operations
- Zero allocations for skipped requests
- String concatenation deferred until after request completion
- No buffering of response body (streaming-friendly)
Best Practices
- Skip logging for health check endpoints
- Use structured (JSON) format for log aggregation
- Include request IDs for tracing
- Log to stderr in containers for proper log handling
Testing
The logger middleware includes comprehensive test coverage for all features and edge cases:
| Test Case | Description | Expected Behavior |
|---|
TestNew | Default logger with standard output | Logs contain status code (200), HTTP method (GET), and request path (/test) |
TestWithOptions_CustomFormat | Custom format string with method, path, and status | Output matches exact format: [GET] /api -> 201\n |
TestWithOptions_Skip | Skip function filtering health check endpoint | No log output for /health endpoint, logs /api endpoint normally |
TestWithOptions_Headers | Custom header extraction using ${header:X-Request-ID} | Logs the exact value of the X-Request-ID header (test-123) |
TestWithOptions_AllTags | All available format tags (host, protocol, referer, user_agent, bytes_out, query) | Log contains all requested tag values from the HTTP request |
TestWithOptions_XForwardedFor | Client IP extraction from X-Forwarded-For header | Extracts first IP from comma-separated list (1.2.3.4) |
TestWithOptions_XRealIP | Client IP extraction from X-Real-IP header | Uses X-Real-IP value (10.0.0.1) when X-Forwarded-For not present |
TestDefaultOutput | Default output configuration (stdout) | Middleware executes without panic, returns 200 status |