@@ -18,55 +18,180 @@ import (
18
18
)
19
19
20
20
// LoggerConfig defines the config for Logger middleware.
21
+ //
22
+ // # Configuration Examples
23
+ //
24
+ // ## Basic Usage with Default Settings
25
+ //
26
+ // e.Use(middleware.Logger())
27
+ //
28
+ // This uses the default JSON format that logs all common request/response details.
29
+ //
30
+ // ## Custom Simple Format
31
+ //
32
+ // e.Use(middleware.LoggerWithConfig(middleware.LoggerConfig{
33
+ // Format: "${time_rfc3339_nano} ${status} ${method} ${uri} ${latency_human}\n",
34
+ // }))
35
+ //
36
+ // ## JSON Format with Custom Fields
37
+ //
38
+ // e.Use(middleware.LoggerWithConfig(middleware.LoggerConfig{
39
+ // Format: `{"timestamp":"${time_rfc3339_nano}","level":"info","remote_ip":"${remote_ip}",` +
40
+ // `"method":"${method}","uri":"${uri}","status":${status},"latency":"${latency_human}",` +
41
+ // `"user_agent":"${user_agent}","error":"${error}"}` + "\n",
42
+ // }))
43
+ //
44
+ // ## Custom Time Format
45
+ //
46
+ // e.Use(middleware.LoggerWithConfig(middleware.LoggerConfig{
47
+ // Format: "${time_custom} ${method} ${uri} ${status}\n",
48
+ // CustomTimeFormat: "2006-01-02 15:04:05",
49
+ // }))
50
+ //
51
+ // ## Logging Headers and Parameters
52
+ //
53
+ // e.Use(middleware.LoggerWithConfig(middleware.LoggerConfig{
54
+ // Format: `{"time":"${time_rfc3339_nano}","method":"${method}","uri":"${uri}",` +
55
+ // `"status":${status},"auth":"${header:Authorization}","user":"${query:user}",` +
56
+ // `"form_data":"${form:action}","session":"${cookie:session_id}"}` + "\n",
57
+ // }))
58
+ //
59
+ // ## Custom Output (File Logging)
60
+ //
61
+ // file, err := os.OpenFile("app.log", os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0666)
62
+ // if err != nil {
63
+ // log.Fatal(err)
64
+ // }
65
+ // defer file.Close()
66
+ //
67
+ // e.Use(middleware.LoggerWithConfig(middleware.LoggerConfig{
68
+ // Output: file,
69
+ // }))
70
+ //
71
+ // ## Custom Tag Function
72
+ //
73
+ // e.Use(middleware.LoggerWithConfig(middleware.LoggerConfig{
74
+ // Format: `{"time":"${time_rfc3339_nano}","user_id":"${custom}","method":"${method}"}` + "\n",
75
+ // CustomTagFunc: func(c echo.Context, buf *bytes.Buffer) (int, error) {
76
+ // userID := getUserIDFromContext(c) // Your custom logic
77
+ // return buf.WriteString(strconv.Itoa(userID))
78
+ // },
79
+ // }))
80
+ //
81
+ // ## Conditional Logging (Skip Certain Requests)
82
+ //
83
+ // e.Use(middleware.LoggerWithConfig(middleware.LoggerConfig{
84
+ // Skipper: func(c echo.Context) bool {
85
+ // // Skip logging for health check endpoints
86
+ // return c.Request().URL.Path == "/health" || c.Request().URL.Path == "/metrics"
87
+ // },
88
+ // }))
89
+ //
90
+ // ## Integration with External Logging Service
91
+ //
92
+ // logBuffer := &SyncBuffer{} // Thread-safe buffer for external service
93
+ //
94
+ // e.Use(middleware.LoggerWithConfig(middleware.LoggerConfig{
95
+ // Format: `{"timestamp":"${time_rfc3339_nano}","service":"my-api","level":"info",` +
96
+ // `"method":"${method}","uri":"${uri}","status":${status},"latency_ms":${latency},` +
97
+ // `"remote_ip":"${remote_ip}","user_agent":"${user_agent}","error":"${error}"}` + "\n",
98
+ // Output: logBuffer,
99
+ // }))
100
+ //
101
+ // # Available Tags
102
+ //
103
+ // ## Time Tags
104
+ // - time_unix: Unix timestamp (seconds)
105
+ // - time_unix_milli: Unix timestamp (milliseconds)
106
+ // - time_unix_micro: Unix timestamp (microseconds)
107
+ // - time_unix_nano: Unix timestamp (nanoseconds)
108
+ // - time_rfc3339: RFC3339 format (2006-01-02T15:04:05Z07:00)
109
+ // - time_rfc3339_nano: RFC3339 with nanoseconds
110
+ // - time_custom: Uses CustomTimeFormat field
111
+ //
112
+ // ## Request Information
113
+ // - id: Request ID from X-Request-ID header
114
+ // - remote_ip: Client IP address (respects proxy headers)
115
+ // - uri: Full request URI with query parameters
116
+ // - host: Host header value
117
+ // - method: HTTP method (GET, POST, etc.)
118
+ // - path: URL path without query parameters
119
+ // - route: Echo route pattern (e.g., /users/:id)
120
+ // - protocol: HTTP protocol version
121
+ // - referer: Referer header value
122
+ // - user_agent: User-Agent header value
123
+ //
124
+ // ## Response Information
125
+ // - status: HTTP status code
126
+ // - error: Error message if request failed
127
+ // - latency: Request processing time in nanoseconds
128
+ // - latency_human: Human-readable processing time
129
+ // - bytes_in: Request body size in bytes
130
+ // - bytes_out: Response body size in bytes
131
+ //
132
+ // ## Dynamic Tags
133
+ // - header:<NAME>: Value of specific header (e.g., header:Authorization)
134
+ // - query:<NAME>: Value of specific query parameter (e.g., query:user_id)
135
+ // - form:<NAME>: Value of specific form field (e.g., form:username)
136
+ // - cookie:<NAME>: Value of specific cookie (e.g., cookie:session_id)
137
+ // - custom: Output from CustomTagFunc
138
+ //
139
+ // # Troubleshooting
140
+ //
141
+ // ## Common Issues
142
+ //
143
+ // 1. **Missing logs**: Check if Skipper function is filtering out requests
144
+ // 2. **Invalid JSON**: Ensure CustomTagFunc outputs valid JSON content
145
+ // 3. **Performance issues**: Consider using a buffered writer for high-traffic applications
146
+ // 4. **File permission errors**: Ensure write permissions when logging to files
147
+ //
148
+ // ## Performance Tips
149
+ //
150
+ // - Use time_unix formats for better performance than time_rfc3339
151
+ // - Minimize the number of dynamic tags (header:, query:, form:, cookie:)
152
+ // - Use Skipper to exclude high-frequency, low-value requests (health checks, etc.)
153
+ // - Consider async logging for very high-traffic applications
21
154
type LoggerConfig struct {
22
155
// Skipper defines a function to skip middleware.
156
+ // Use this to exclude certain requests from logging (e.g., health checks).
157
+ //
158
+ // Example:
159
+ // Skipper: func(c echo.Context) bool {
160
+ // return c.Request().URL.Path == "/health"
161
+ // },
23
162
Skipper Skipper
24
163
25
- // Tags to construct the logger format.
26
- //
27
- // - time_unix
28
- // - time_unix_milli
29
- // - time_unix_micro
30
- // - time_unix_nano
31
- // - time_rfc3339
32
- // - time_rfc3339_nano
33
- // - time_custom
34
- // - id (Request ID)
35
- // - remote_ip
36
- // - uri
37
- // - host
38
- // - method
39
- // - path
40
- // - route
41
- // - protocol
42
- // - referer
43
- // - user_agent
44
- // - status
45
- // - error
46
- // - latency (In nanoseconds)
47
- // - latency_human (Human readable)
48
- // - bytes_in (Bytes received)
49
- // - bytes_out (Bytes sent)
50
- // - header:<NAME>
51
- // - query:<NAME>
52
- // - form:<NAME>
53
- // - custom (see CustomTagFunc field)
54
- //
55
- // Example "${remote_ip} ${status}"
164
+ // Format defines the logging format using template tags.
165
+ // Tags are enclosed in ${} and replaced with actual values.
166
+ // See the detailed tag documentation above for all available options.
56
167
//
57
- // Optional. Default value DefaultLoggerConfig.Format.
168
+ // Default: JSON format with common fields
169
+ // Example: "${time_rfc3339_nano} ${status} ${method} ${uri} ${latency_human}\n"
58
170
Format string `yaml:"format"`
59
171
60
- // Optional. Default value DefaultLoggerConfig.CustomTimeFormat.
172
+ // CustomTimeFormat specifies the time format used by ${time_custom} tag.
173
+ // Uses Go's reference time: Mon Jan 2 15:04:05 MST 2006
174
+ //
175
+ // Default: "2006-01-02 15:04:05.00000"
176
+ // Example: "2006-01-02 15:04:05" or "15:04:05.000"
61
177
CustomTimeFormat string `yaml:"custom_time_format"`
62
178
63
- // CustomTagFunc is function called for `${custom}` tag to output user implemented text by writing it to buf.
64
- // Make sure that outputted text creates valid JSON string with other logged tags.
65
- // Optional.
179
+ // CustomTagFunc is called when ${custom} tag is encountered.
180
+ // Use this to add application-specific information to logs.
181
+ // The function should write valid content for your log format.
182
+ //
183
+ // Example:
184
+ // CustomTagFunc: func(c echo.Context, buf *bytes.Buffer) (int, error) {
185
+ // userID := getUserFromContext(c)
186
+ // return buf.WriteString(`"user_id":"` + userID + `"`)
187
+ // },
66
188
CustomTagFunc func (c echo.Context , buf * bytes.Buffer ) (int , error )
67
189
68
- // Output is a writer where logs in JSON format are written.
69
- // Optional. Default value os.Stdout.
190
+ // Output specifies where logs are written.
191
+ // Can be any io.Writer: files, buffers, network connections, etc.
192
+ //
193
+ // Default: os.Stdout
194
+ // Example: Custom file, syslog, or external logging service
70
195
Output io.Writer
71
196
72
197
template * fasttemplate.Template
@@ -85,13 +210,55 @@ var DefaultLoggerConfig = LoggerConfig{
85
210
colorer : color .New (),
86
211
}
87
212
88
- // Logger returns a middleware that logs HTTP requests.
213
+ // Logger returns a middleware that logs HTTP requests using the default configuration.
214
+ //
215
+ // The default format logs requests as JSON with the following fields:
216
+ // - time: RFC3339 nano timestamp
217
+ // - id: Request ID from X-Request-ID header
218
+ // - remote_ip: Client IP address
219
+ // - host: Host header
220
+ // - method: HTTP method
221
+ // - uri: Request URI
222
+ // - user_agent: User-Agent header
223
+ // - status: HTTP status code
224
+ // - error: Error message (if any)
225
+ // - latency: Processing time in nanoseconds
226
+ // - latency_human: Human-readable processing time
227
+ // - bytes_in: Request body size
228
+ // - bytes_out: Response body size
229
+ //
230
+ // Example output:
231
+ //
232
+ // {"time":"2023-01-15T10:30:45.123456789Z","id":"","remote_ip":"127.0.0.1",
233
+ // "host":"localhost:8080","method":"GET","uri":"/users/123","user_agent":"curl/7.81.0",
234
+ // "status":200,"error":"","latency":1234567,"latency_human":"1.234567ms",
235
+ // "bytes_in":0,"bytes_out":42}
236
+ //
237
+ // For custom configurations, use LoggerWithConfig instead.
89
238
func Logger () echo.MiddlewareFunc {
90
239
return LoggerWithConfig (DefaultLoggerConfig )
91
240
}
92
241
93
- // LoggerWithConfig returns a Logger middleware with config.
94
- // See: `Logger()`.
242
+ // LoggerWithConfig returns a Logger middleware with custom configuration.
243
+ //
244
+ // This function allows you to customize all aspects of request logging including:
245
+ // - Log format and fields
246
+ // - Output destination
247
+ // - Time formatting
248
+ // - Custom tags and logic
249
+ // - Request filtering
250
+ //
251
+ // See LoggerConfig documentation for detailed configuration examples and options.
252
+ //
253
+ // Example:
254
+ //
255
+ // e.Use(middleware.LoggerWithConfig(middleware.LoggerConfig{
256
+ // Format: "${time_rfc3339} ${status} ${method} ${uri} ${latency_human}\n",
257
+ // Output: customLogWriter,
258
+ // Skipper: func(c echo.Context) bool {
259
+ // return c.Request().URL.Path == "/health"
260
+ // },
261
+ // }))
95
262
func LoggerWithConfig (config LoggerConfig ) echo.MiddlewareFunc {
96
263
// Defaults
97
264
if config .Skipper == nil {
0 commit comments