Go Web Server Access Logging
Building robust web applications requires understanding how users interact with your service. Access logging is a fundamental practice that records details of each incoming request, providing invaluable insights for debugging, security analysis, and performance monitoring. This challenge will guide you through implementing an effective access logging middleware for a Go web server.
Problem Description
Your task is to create a Go middleware function that intercepts incoming HTTP requests to a web server and logs relevant information about each request. This middleware should be integrated with a simple HTTP server to demonstrate its functionality.
Key Requirements:
- Log Format: Each log entry should include:
- Timestamp of the request (e.g.,
2006-01-02 15:04:05) - HTTP Method (e.g.,
GET,POST) - Request URL (including path and query parameters)
- Remote IP Address of the client
- HTTP Status Code returned by the handler
- Request Duration (time taken to process the request)
- Timestamp of the request (e.g.,
- Middleware Structure: The logging functionality should be implemented as a Go HTTP middleware. This means it should accept an
http.Handlerand return a newhttp.Handlerthat wraps the original handler. - Output Destination: Log entries should be written to standard output (
os.Stdout). - Integration: The middleware should be easily pluggable into a standard Go
http.ServeMuxornet/httpserver.
Expected Behavior:
When a request hits the server, the middleware should record the start time, pass the request to the next handler in the chain, record the end time and the status code from the response, calculate the duration, and then print the formatted log entry before returning the response to the client.
Edge Cases to Consider:
- Requests that result in errors or panics (though for this challenge, we'll focus on successful responses and standard error handling).
- Requests with unusual URL structures or methods.
Examples
Example 1: Simple GET Request
Input:
- A GET request to "/hello" with no query parameters.
- The server handler for "/hello" returns a 200 OK status and a simple "Hello, World!" body.
Expected Output (example, actual timestamp will vary):
2023-10-27 10:30:00 GET /hello - 192.168.1.100 200 15ms
Example 2: POST Request with Query Parameters
Input:
- A POST request to "/submit?id=123"
- The server handler for "/submit" returns a 201 Created status.
Expected Output (example, actual timestamp will vary):
2023-10-27 10:31:05 POST /submit?id=123 - 10.0.0.5 201 30ms
Example 3: Handler that takes longer to process
Input:
- A GET request to "/long-process"
- The server handler for "/long-process" simulates a delay (e.g., using time.Sleep) and returns a 200 OK status.
Expected Output (example, actual timestamp and duration will vary):
2023-10-27 10:35:15 GET /long-process - 172.16.0.1 200 500ms
Constraints
- The Go version used should be Go 1.18 or later.
- The solution should be a single Go file (
main.go). - No external third-party logging libraries are allowed. Use only standard Go libraries.
- Performance is important; the middleware should introduce minimal overhead.
Notes
- Consider using
time.Now()to capture timestamps andtime.Since()to calculate durations. - The
net/httppackage provides tools for accessing request details liker.Method,r.URL, andr.RemoteAddr. - To access the status code, you'll need a way to capture it from the
http.ResponseWriter. A common pattern is to create a customResponseWriterthat wraps the original and intercepts theWriteHeadermethod. - Think about how to chain your middleware with actual handler functions. The
http.HandlerFunctype can be useful.