Skip to content

Commit ac6836d

Browse files
committed
Enhance README and implement RotatingWriter for automatic log file rotation. Added examples for usage and configuration, including thread safety and file management. Updated tests to cover various rotation scenarios and improved error handling in the RotatingWriter implementation.
1 parent 0f47932 commit ac6836d

File tree

4 files changed

+779
-28
lines changed

4 files changed

+779
-28
lines changed

README.md

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ Fast and flexible structured logging library for Go inspired by zerolog
1515
- **Context Support**: Log attributes can be stored in and retrieved from context
1616
- **Colorized Output**: Beautiful colored console output with customizable colorizers
1717
- **Flexible Configuration**: Multiple writers, filters, and level configurations
18+
- **Rotating Log Files**: Automatic file rotation based on size thresholds
1819
- **HTTP Middleware**: Built-in HTTP request/response logging
1920
- **UUID Support**: Native UUID logging support
2021
- **Call Stack Tracing**: Capture and log call stacks for debugging
@@ -165,6 +166,64 @@ log := golog.NewLogger(config)
165166
log.Error("Database connection failed").Err(err).Log()
166167
```
167168

169+
## Rotating Log Files
170+
171+
Automatic file rotation based on size thresholds using the `logfile` subpackage:
172+
173+
```go
174+
import (
175+
"github.com/domonda/golog"
176+
"github.com/domonda/golog/logfile"
177+
)
178+
179+
// Create a rotating writer that rotates at 10MB
180+
writer, err := logfile.NewRotatingWriter(
181+
"/var/log/myapp.log", // File path
182+
logfile.RotatingWriterDefaultTimeFormat, // Time format for rotated files
183+
0644, // File permissions
184+
10*1024*1024, // Rotate at 10MB
185+
)
186+
if err != nil {
187+
log.Fatal(err)
188+
}
189+
defer writer.Close()
190+
191+
// Use with golog
192+
config := golog.NewConfig(
193+
&golog.DefaultLevels,
194+
golog.AllLevelsActive,
195+
golog.NewJSONWriterConfig(writer, nil),
196+
)
197+
198+
log := golog.NewLogger(config)
199+
200+
log.Info("Application started").Log()
201+
```
202+
203+
When the log file reaches 10MB:
204+
- The current file is renamed with a timestamp (e.g., `myapp.log.2024-01-15_10:30:45`)
205+
- A new file is created at the original path
206+
- Logging continues seamlessly to the new file
207+
208+
### Multiple Writers with Rotation
209+
210+
```go
211+
// Console output with colors + rotating JSON file
212+
fileWriter, _ := logfile.NewRotatingWriter("/var/log/app.log", "", 0644, 50*1024*1024)
213+
defer fileWriter.Close()
214+
215+
config := golog.NewConfig(
216+
&golog.DefaultLevels,
217+
golog.AllLevelsActive,
218+
golog.NewTextWriterConfig(os.Stdout, nil, golog.NewStyledColorizer()),
219+
golog.NewJSONWriterConfig(fileWriter, nil),
220+
)
221+
222+
log := golog.NewLogger(config)
223+
```
224+
225+
See the [logfile package documentation](logfile/README.md) for more details.
226+
168227
## HTTP Middleware
169228

170229
```go

logfile/README.md

Lines changed: 285 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,285 @@
1+
# logfile
2+
3+
Package logfile provides file-based log writers with automatic rotation capabilities for the [golog](https://github.com/domonda/golog) logging library.
4+
5+
## Features
6+
7+
- **Automatic File Rotation**: Rotates log files based on size thresholds
8+
- **Thread-Safe**: Safe for concurrent use by multiple goroutines
9+
- **Timestamp-Based Naming**: Rotated files are named with timestamps for easy identification
10+
- **Configurable**: Customizable file paths, permissions, rotation sizes, and time formats
11+
- **Seamless Integration**: Works with any `io.Writer` compatible logging system
12+
13+
## Installation
14+
15+
```bash
16+
go get github.com/domonda/golog/logfile
17+
```
18+
19+
## Quick Start
20+
21+
### Basic Usage
22+
23+
```go
24+
package main
25+
26+
import (
27+
"os"
28+
29+
"github.com/domonda/golog"
30+
"github.com/domonda/golog/logfile"
31+
)
32+
33+
func main() {
34+
// Create a rotating writer that rotates at 10MB
35+
writer, err := logfile.NewRotatingWriter(
36+
"/var/log/myapp.log", // File path
37+
logfile.RotatingWriterDefaultTimeFormat, // Time format for rotated files
38+
0644, // File permissions
39+
10*1024*1024, // Rotate at 10MB
40+
)
41+
if err != nil {
42+
panic(err)
43+
}
44+
defer writer.Close()
45+
46+
// Use with golog
47+
config := golog.NewConfig(
48+
&golog.DefaultLevels,
49+
golog.AllLevelsActive,
50+
golog.NewJSONWriterConfig(writer, nil),
51+
)
52+
53+
log := golog.NewLogger(config)
54+
55+
log.Info("Application started").Log()
56+
log.Error("An error occurred").Err(err).Log()
57+
}
58+
```
59+
60+
### Multiple Writers (Console + Rotating File)
61+
62+
```go
63+
package main
64+
65+
import (
66+
"os"
67+
68+
"github.com/domonda/golog"
69+
"github.com/domonda/golog/logfile"
70+
)
71+
72+
func main() {
73+
// Create rotating file writer
74+
fileWriter, err := logfile.NewRotatingWriter(
75+
"/var/log/myapp.log",
76+
"", // Use default time format
77+
0644, // File permissions
78+
5*1024*1024, // Rotate at 5MB
79+
)
80+
if err != nil {
81+
panic(err)
82+
}
83+
defer fileWriter.Close()
84+
85+
// Configure logger with both console and file output
86+
config := golog.NewConfig(
87+
&golog.DefaultLevels,
88+
golog.AllLevelsActive,
89+
// Colored text output to console
90+
golog.NewTextWriterConfig(
91+
os.Stdout,
92+
nil,
93+
golog.NewStyledColorizer(),
94+
),
95+
// JSON output to rotating file
96+
golog.NewJSONWriterConfig(fileWriter, nil),
97+
)
98+
99+
log := golog.NewLogger(config)
100+
101+
// Logs will appear on console in color AND be written to file in JSON
102+
log.Info("Server starting").
103+
Str("host", "localhost").
104+
Int("port", 8080).
105+
Log()
106+
}
107+
```
108+
109+
### Different Log Levels to Different Files
110+
111+
```go
112+
package main
113+
114+
import (
115+
"github.com/domonda/golog"
116+
"github.com/domonda/golog/logfile"
117+
)
118+
119+
func main() {
120+
// All logs file (rotates at 10MB)
121+
allLogsWriter, _ := logfile.NewRotatingWriter(
122+
"/var/log/myapp.log",
123+
"",
124+
0644,
125+
10*1024*1024,
126+
)
127+
defer allLogsWriter.Close()
128+
129+
// Errors only file (rotates at 5MB)
130+
errorLogsWriter, _ := logfile.NewRotatingWriter(
131+
"/var/log/myapp-errors.log",
132+
"",
133+
0644,
134+
5*1024*1024,
135+
)
136+
defer errorLogsWriter.Close()
137+
138+
// Configure with level filtering
139+
config := golog.NewConfig(
140+
&golog.DefaultLevels,
141+
golog.AllLevelsActive,
142+
// All logs
143+
golog.NewJSONWriterConfig(allLogsWriter, nil),
144+
// Errors and above only
145+
golog.NewJSONWriterConfig(
146+
errorLogsWriter,
147+
nil,
148+
golog.LevelFilterFrom(golog.DefaultLevels.Error),
149+
),
150+
)
151+
152+
log := golog.NewLogger(config)
153+
154+
log.Info("This goes to all logs").Log()
155+
log.Error("This goes to both all logs and error logs").Log()
156+
}
157+
```
158+
159+
## How Rotation Works
160+
161+
When a log file reaches the configured size threshold:
162+
163+
1. The current file is closed
164+
2. The file is renamed with a timestamp suffix (e.g., `myapp.log.2024-01-15_10:30:45`)
165+
3. If a file with that name already exists, a numeric suffix is added (e.g., `myapp.log.2024-01-15_10:30:45.1`)
166+
4. A new file is created at the original path
167+
5. Logging continues to the new file
168+
169+
### Example File Rotation
170+
171+
```
172+
# Before rotation
173+
myapp.log (10MB)
174+
175+
# After first rotation
176+
myapp.log (0 bytes, new file)
177+
myapp.log.2024-01-15_10:30:45 (10MB)
178+
179+
# After second rotation (same second)
180+
myapp.log (0 bytes, new file)
181+
myapp.log.2024-01-15_10:30:45 (10MB)
182+
myapp.log.2024-01-15_10:30:45.1 (10MB)
183+
```
184+
185+
## Configuration Options
186+
187+
### NewRotatingWriter Parameters
188+
189+
```go
190+
func NewRotatingWriter(
191+
filePath string, // Path to log file
192+
timeFormat string, // Time format for rotated files (empty = default)
193+
filePerm os.FileMode, // File permissions (e.g., 0644)
194+
rotateSize int64, // Size in bytes (0 = no rotation)
195+
) (*RotatingWriter, error)
196+
```
197+
198+
### Time Format
199+
200+
The `timeFormat` parameter uses Go's time layout format. Common formats:
201+
202+
```go
203+
// Default format (recommended)
204+
logfile.RotatingWriterDefaultTimeFormat // "2006-01-02_15:04:05"
205+
206+
// Date only
207+
"2006-01-02" // myapp.log.2024-01-15
208+
209+
// Date and hour
210+
"2006-01-02_15" // myapp.log.2024-01-15_10
211+
212+
// Custom format
213+
"2006-01-02_15-04-05" // myapp.log.2024-01-15_10-30-45
214+
```
215+
216+
### Rotation Size Guidelines
217+
218+
```go
219+
// No rotation (file grows indefinitely)
220+
0
221+
222+
// Common sizes
223+
1024 * 1024 // 1 MB
224+
5 * 1024 * 1024 // 5 MB
225+
10 * 1024 * 1024 // 10 MB
226+
100 * 1024 * 1024 // 100 MB
227+
1024 * 1024 * 1024 // 1 GB
228+
```
229+
230+
## Thread Safety
231+
232+
`RotatingWriter` is fully thread-safe. All operations (Write, Sync, Close) are protected by an internal mutex, making it safe to use from multiple goroutines simultaneously.
233+
234+
```go
235+
// Safe to use from multiple goroutines
236+
go func() {
237+
log.Info("From goroutine 1").Log()
238+
}()
239+
240+
go func() {
241+
log.Info("From goroutine 2").Log()
242+
}()
243+
```
244+
245+
## Methods
246+
247+
### Write([]byte) (int, error)
248+
249+
Writes data to the log file. Automatically rotates if size threshold is exceeded.
250+
251+
### Sync() error
252+
253+
Flushes buffered data to disk. Useful for ensuring logs are persisted before shutdown.
254+
255+
```go
256+
defer func() {
257+
writer.Sync() // Ensure all data is written
258+
// Do something else...
259+
writer.Close() // Note that Close also writes all buffered data to disk
260+
}()
261+
```
262+
263+
## Integration with Standard Library
264+
265+
Since `RotatingWriter` implements `io.Writer`, it can be used with any logging library that accepts an `io.Writer`:
266+
267+
```go
268+
// Standard library log
269+
import "log"
270+
271+
writer, _ := logfile.NewRotatingWriter("/var/log/app.log", "", 0644, 10*1024*1024)
272+
defer writer.Close()
273+
274+
log.SetOutput(writer)
275+
log.Println("This will be written to a rotating log file")
276+
```
277+
278+
## License
279+
280+
This package is part of the [golog](https://github.com/domonda/golog) project and is licensed under the MIT License.
281+
282+
## See Also
283+
284+
- [golog documentation](https://pkg.go.dev/github.com/domonda/golog)
285+
- [Main golog README](https://github.com/domonda/golog)

0 commit comments

Comments
 (0)