Robust Access Logging in Go
Access logging is crucial for monitoring application usage, debugging issues, and auditing security events. This challenge asks you to implement a simple access logging system in Go that records incoming requests, their timestamps, and their status codes. A well-designed logging system provides valuable insights into application behavior.
Problem Description
You are tasked with creating a Go program that simulates a basic web server and logs incoming requests to a file. The program should:
- Accept HTTP requests: The program should listen on a specified port (default: 8080) and accept incoming HTTP requests. It doesn't need to handle complex routing or request bodies; simply accept any request.
- Generate Status Codes: For simplicity, the program should randomly generate a status code between 200 (OK) and 500 (Internal Server Error) for each request.
- Log Request Information: For each incoming request, the program should log the following information to a file named "access.log":
- Timestamp (in a readable format, e.g., "2023-10-27 10:00:00")
- Client IP Address (obtained from the request)
- Requested Path (obtained from the request)
- HTTP Status Code (randomly generated)
- File Rotation (Basic): After logging 100 requests, the program should create a new log file named "access.log.1" and continue logging to "access.log". This simulates a basic form of log rotation.
- Error Handling: The program should gracefully handle errors, such as failing to bind to the specified port or failing to write to the log file. Log any errors to standard error.
Examples
Example 1:
Input: Multiple HTTP requests sent to localhost:8080 (e.g., using curl or a browser)
Output: A file named "access.log" containing log entries like:
"2023-10-27 10:00:00 127.0.0.1 / 200"
"2023-10-27 10:00:01 127.0.0.1 / 500"
... (up to 100 entries)
A file named "access.log.1" containing log entries from the 101st request onwards.
Explanation: The program receives requests, generates random status codes, and logs the relevant information to the access log files.
Example 2:
Input: The program is started with the command `go run main.go :8081`
Output: The program listens on port 8081 instead of the default 8080. The access logs are written to "access.log" and "access.log.1" as in Example 1.
Explanation: The program correctly parses the command-line argument and binds to the specified port.
Example 3: (Edge Case)
Input: The program is started, but port 8080 is already in use.
Output: The program prints an error message to standard error (e.g., "Error: listen tcp :8080: bind: address already in use") and exits gracefully.
Explanation: The program handles the error of failing to bind to the port and provides informative output.
Constraints
- The program must be written in Go.
- The program must listen on a port specified either as a command-line argument (e.g.,
:8081) or default to port 8080 if no argument is provided. - The program must log at least 100 requests before rotating the log file.
- The timestamp format should be consistent and readable (YYYY-MM-DD HH:MM:SS).
- The program should not use external libraries for HTTP handling or logging (use the standard
net/httpandospackages). - The program should handle potential errors gracefully.
Notes
- Consider using the
time.Now().Format()function for generating timestamps. - The
net/httppackage provides functions for listening on ports and handling requests. - The
ospackage provides functions for file operations. - Focus on clarity and readability of the code. Error handling is a key aspect of this challenge.
- The random status code generation is a simplification; in a real-world scenario, the status code would be determined by the application logic.
- The log rotation is a basic implementation; more sophisticated log rotation strategies exist.
- The IP address can be obtained from the
RemoteAddrfield of thehttp.Requestobject. - The path can be obtained from the
URL.Pathfield of thehttp.Requestobject.