1
0
mirror of https://github.com/labstack/echo.git synced 2025-10-30 23:57:38 +02:00

Enhance Logger Middleware Documentation with Detailed Configuration Examples

Addresses issue #2665 by providing comprehensive documentation for the Logger
middleware including:

**Configuration Examples:**
- Basic usage with default settings
- Custom simple and JSON formats
- Custom time formatting
- Header, query, form, and cookie logging
- File output configuration
- Custom tag functions
- Conditional logging with Skipper
- External logging service integration

**Detailed Tag Reference:**
- Complete list of all available tags (time, request, response, dynamic)
- Clear explanations of each tag's purpose and format
- Examples showing proper usage

**Enhanced Field Documentation:**
- Detailed descriptions for all LoggerConfig fields
- Examples for each configuration option
- Default values and behavior

**Troubleshooting Section:**
- Common issues and solutions
- Performance optimization tips
- Best practices for high-traffic applications

**Function Documentation:**
- Enhanced Logger() and LoggerWithConfig() documentation
- Example outputs and usage patterns

This makes the Logger middleware much more accessible to new users while
providing advanced configuration guidance for experienced developers.

Fixes #2665

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
Vishal Rana
2025-09-15 19:27:34 -07:00
parent b7a781ce5d
commit f1ebc67c56

View File

@@ -18,55 +18,180 @@ import (
)
// LoggerConfig defines the config for Logger middleware.
//
// # Configuration Examples
//
// ## Basic Usage with Default Settings
//
// e.Use(middleware.Logger())
//
// This uses the default JSON format that logs all common request/response details.
//
// ## Custom Simple Format
//
// e.Use(middleware.LoggerWithConfig(middleware.LoggerConfig{
// Format: "${time_rfc3339_nano} ${status} ${method} ${uri} ${latency_human}\n",
// }))
//
// ## JSON Format with Custom Fields
//
// e.Use(middleware.LoggerWithConfig(middleware.LoggerConfig{
// Format: `{"timestamp":"${time_rfc3339_nano}","level":"info","remote_ip":"${remote_ip}",` +
// `"method":"${method}","uri":"${uri}","status":${status},"latency":"${latency_human}",` +
// `"user_agent":"${user_agent}","error":"${error}"}` + "\n",
// }))
//
// ## Custom Time Format
//
// e.Use(middleware.LoggerWithConfig(middleware.LoggerConfig{
// Format: "${time_custom} ${method} ${uri} ${status}\n",
// CustomTimeFormat: "2006-01-02 15:04:05",
// }))
//
// ## Logging Headers and Parameters
//
// e.Use(middleware.LoggerWithConfig(middleware.LoggerConfig{
// Format: `{"time":"${time_rfc3339_nano}","method":"${method}","uri":"${uri}",` +
// `"status":${status},"auth":"${header:Authorization}","user":"${query:user}",` +
// `"form_data":"${form:action}","session":"${cookie:session_id}"}` + "\n",
// }))
//
// ## Custom Output (File Logging)
//
// file, err := os.OpenFile("app.log", os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0666)
// if err != nil {
// log.Fatal(err)
// }
// defer file.Close()
//
// e.Use(middleware.LoggerWithConfig(middleware.LoggerConfig{
// Output: file,
// }))
//
// ## Custom Tag Function
//
// e.Use(middleware.LoggerWithConfig(middleware.LoggerConfig{
// Format: `{"time":"${time_rfc3339_nano}","user_id":"${custom}","method":"${method}"}` + "\n",
// CustomTagFunc: func(c echo.Context, buf *bytes.Buffer) (int, error) {
// userID := getUserIDFromContext(c) // Your custom logic
// return buf.WriteString(strconv.Itoa(userID))
// },
// }))
//
// ## Conditional Logging (Skip Certain Requests)
//
// e.Use(middleware.LoggerWithConfig(middleware.LoggerConfig{
// Skipper: func(c echo.Context) bool {
// // Skip logging for health check endpoints
// return c.Request().URL.Path == "/health" || c.Request().URL.Path == "/metrics"
// },
// }))
//
// ## Integration with External Logging Service
//
// logBuffer := &SyncBuffer{} // Thread-safe buffer for external service
//
// e.Use(middleware.LoggerWithConfig(middleware.LoggerConfig{
// Format: `{"timestamp":"${time_rfc3339_nano}","service":"my-api","level":"info",` +
// `"method":"${method}","uri":"${uri}","status":${status},"latency_ms":${latency},` +
// `"remote_ip":"${remote_ip}","user_agent":"${user_agent}","error":"${error}"}` + "\n",
// Output: logBuffer,
// }))
//
// # Available Tags
//
// ## Time Tags
// - time_unix: Unix timestamp (seconds)
// - time_unix_milli: Unix timestamp (milliseconds)
// - time_unix_micro: Unix timestamp (microseconds)
// - time_unix_nano: Unix timestamp (nanoseconds)
// - time_rfc3339: RFC3339 format (2006-01-02T15:04:05Z07:00)
// - time_rfc3339_nano: RFC3339 with nanoseconds
// - time_custom: Uses CustomTimeFormat field
//
// ## Request Information
// - id: Request ID from X-Request-ID header
// - remote_ip: Client IP address (respects proxy headers)
// - uri: Full request URI with query parameters
// - host: Host header value
// - method: HTTP method (GET, POST, etc.)
// - path: URL path without query parameters
// - route: Echo route pattern (e.g., /users/:id)
// - protocol: HTTP protocol version
// - referer: Referer header value
// - user_agent: User-Agent header value
//
// ## Response Information
// - status: HTTP status code
// - error: Error message if request failed
// - latency: Request processing time in nanoseconds
// - latency_human: Human-readable processing time
// - bytes_in: Request body size in bytes
// - bytes_out: Response body size in bytes
//
// ## Dynamic Tags
// - header:<NAME>: Value of specific header (e.g., header:Authorization)
// - query:<NAME>: Value of specific query parameter (e.g., query:user_id)
// - form:<NAME>: Value of specific form field (e.g., form:username)
// - cookie:<NAME>: Value of specific cookie (e.g., cookie:session_id)
// - custom: Output from CustomTagFunc
//
// # Troubleshooting
//
// ## Common Issues
//
// 1. **Missing logs**: Check if Skipper function is filtering out requests
// 2. **Invalid JSON**: Ensure CustomTagFunc outputs valid JSON content
// 3. **Performance issues**: Consider using a buffered writer for high-traffic applications
// 4. **File permission errors**: Ensure write permissions when logging to files
//
// ## Performance Tips
//
// - Use time_unix formats for better performance than time_rfc3339
// - Minimize the number of dynamic tags (header:, query:, form:, cookie:)
// - Use Skipper to exclude high-frequency, low-value requests (health checks, etc.)
// - Consider async logging for very high-traffic applications
type LoggerConfig struct {
// Skipper defines a function to skip middleware.
// Use this to exclude certain requests from logging (e.g., health checks).
//
// Example:
// Skipper: func(c echo.Context) bool {
// return c.Request().URL.Path == "/health"
// },
Skipper Skipper
// Tags to construct the logger format.
// Format defines the logging format using template tags.
// Tags are enclosed in ${} and replaced with actual values.
// See the detailed tag documentation above for all available options.
//
// - time_unix
// - time_unix_milli
// - time_unix_micro
// - time_unix_nano
// - time_rfc3339
// - time_rfc3339_nano
// - time_custom
// - id (Request ID)
// - remote_ip
// - uri
// - host
// - method
// - path
// - route
// - protocol
// - referer
// - user_agent
// - status
// - error
// - latency (In nanoseconds)
// - latency_human (Human readable)
// - bytes_in (Bytes received)
// - bytes_out (Bytes sent)
// - header:<NAME>
// - query:<NAME>
// - form:<NAME>
// - custom (see CustomTagFunc field)
//
// Example "${remote_ip} ${status}"
//
// Optional. Default value DefaultLoggerConfig.Format.
// Default: JSON format with common fields
// Example: "${time_rfc3339_nano} ${status} ${method} ${uri} ${latency_human}\n"
Format string `yaml:"format"`
// Optional. Default value DefaultLoggerConfig.CustomTimeFormat.
// CustomTimeFormat specifies the time format used by ${time_custom} tag.
// Uses Go's reference time: Mon Jan 2 15:04:05 MST 2006
//
// Default: "2006-01-02 15:04:05.00000"
// Example: "2006-01-02 15:04:05" or "15:04:05.000"
CustomTimeFormat string `yaml:"custom_time_format"`
// CustomTagFunc is function called for `${custom}` tag to output user implemented text by writing it to buf.
// Make sure that outputted text creates valid JSON string with other logged tags.
// Optional.
// CustomTagFunc is called when ${custom} tag is encountered.
// Use this to add application-specific information to logs.
// The function should write valid content for your log format.
//
// Example:
// CustomTagFunc: func(c echo.Context, buf *bytes.Buffer) (int, error) {
// userID := getUserFromContext(c)
// return buf.WriteString(`"user_id":"` + userID + `"`)
// },
CustomTagFunc func(c echo.Context, buf *bytes.Buffer) (int, error)
// Output is a writer where logs in JSON format are written.
// Optional. Default value os.Stdout.
// Output specifies where logs are written.
// Can be any io.Writer: files, buffers, network connections, etc.
//
// Default: os.Stdout
// Example: Custom file, syslog, or external logging service
Output io.Writer
template *fasttemplate.Template
@@ -85,13 +210,55 @@ var DefaultLoggerConfig = LoggerConfig{
colorer: color.New(),
}
// Logger returns a middleware that logs HTTP requests.
// Logger returns a middleware that logs HTTP requests using the default configuration.
//
// The default format logs requests as JSON with the following fields:
// - time: RFC3339 nano timestamp
// - id: Request ID from X-Request-ID header
// - remote_ip: Client IP address
// - host: Host header
// - method: HTTP method
// - uri: Request URI
// - user_agent: User-Agent header
// - status: HTTP status code
// - error: Error message (if any)
// - latency: Processing time in nanoseconds
// - latency_human: Human-readable processing time
// - bytes_in: Request body size
// - bytes_out: Response body size
//
// Example output:
//
// {"time":"2023-01-15T10:30:45.123456789Z","id":"","remote_ip":"127.0.0.1",
// "host":"localhost:8080","method":"GET","uri":"/users/123","user_agent":"curl/7.81.0",
// "status":200,"error":"","latency":1234567,"latency_human":"1.234567ms",
// "bytes_in":0,"bytes_out":42}
//
// For custom configurations, use LoggerWithConfig instead.
func Logger() echo.MiddlewareFunc {
return LoggerWithConfig(DefaultLoggerConfig)
}
// LoggerWithConfig returns a Logger middleware with config.
// See: `Logger()`.
// LoggerWithConfig returns a Logger middleware with custom configuration.
//
// This function allows you to customize all aspects of request logging including:
// - Log format and fields
// - Output destination
// - Time formatting
// - Custom tags and logic
// - Request filtering
//
// See LoggerConfig documentation for detailed configuration examples and options.
//
// Example:
//
// e.Use(middleware.LoggerWithConfig(middleware.LoggerConfig{
// Format: "${time_rfc3339} ${status} ${method} ${uri} ${latency_human}\n",
// Output: customLogWriter,
// Skipper: func(c echo.Context) bool {
// return c.Request().URL.Path == "/health"
// },
// }))
func LoggerWithConfig(config LoggerConfig) echo.MiddlewareFunc {
// Defaults
if config.Skipper == nil {