@@ -37,6 +37,14 @@ func init() {
3737 RegisterPlugin [ConsoleAppender ]("Console" , PluginTypeAppender )
3838 RegisterPlugin [FileAppender ]("File" , PluginTypeAppender )
3939 RegisterPlugin [GroupAppender ]("Group" , PluginTypeAppender )
40+
41+ // register built-in converters
42+ RegisterConverter (ParseRotateStrategy )
43+
44+ // register built-in rotate strategies
45+ RegisterRotateStrategy ("1h" , FixedRotateStrategy {Interval : time .Hour })
46+ RegisterRotateStrategy ("30m" , FixedRotateStrategy {Interval : 30 * time .Minute })
47+ RegisterRotateStrategy ("10m" , FixedRotateStrategy {Interval : 10 * time .Minute })
4048}
4149
4250// Appender defines components that handle log output.
@@ -137,64 +145,10 @@ func (c *ConsoleAppender) Write(b []byte) {
137145 _ , _ = Stdout .Write (b )
138146}
139147
140- // FileAppender writes formatted log events to a specified file.
141- type FileAppender struct {
142- AppenderBase
143- Layout Layout `PluginElement:"Layout,default=TextLayout"`
144- FileDir string `PluginAttribute:"fileDir,default=./logs"`
145- FileName string `PluginAttribute:"fileName"`
146-
147- file * os.File
148- }
149-
150- func (c * FileAppender ) ConcurrentSafe () bool { return true }
151-
152- // Start opens the log file for appending.
153- func (c * FileAppender ) Start () error {
154- const fileFlag = os .O_WRONLY | os .O_CREATE | os .O_APPEND
155- fileName := filepath .Join (c .FileDir , c .FileName )
156- f , err := os .OpenFile (fileName , fileFlag , 0644 )
157- if err != nil {
158- return err
159- }
160- c .file = f
161- return nil
162- }
163-
164- // Append formats the log event and writes it to the file.
165- func (c * FileAppender ) Append (e * Event ) {
166- if c .EnableLevel (e .Level ) {
167- c .Write (c .Layout .ToBytes (e ))
168- }
169- }
170-
171- // Write writes a byte slice directly to the file.
172- func (c * FileAppender ) Write (b []byte ) {
173- _ , _ = c .file .Write (b )
174- }
175-
176- // Stop flushes and closes the file.
177- func (c * FileAppender ) Stop () {
178- if c .file != nil {
179- _ = c .file .Sync ()
180- _ = c .file .Close ()
181- }
182- }
183-
184- func init () {
185- // register built-in converters
186- RegisterConverter (ParseRotateStrategy )
187-
188- // register built-in rotate strategies
189- RegisterRotateStrategy ("1h" , FixedRotateStrategy {Interval : time .Hour })
190- RegisterRotateStrategy ("30m" , FixedRotateStrategy {Interval : 30 * time .Minute })
191- RegisterRotateStrategy ("10m" , FixedRotateStrategy {Interval : 10 * time .Minute })
192- }
193-
194- var rotateStrategyRegistry = map [string ]RotateStrategy {}
148+ var rotateStrategyRegistry = map [string ]RollingPolicy {}
195149
196- // RotateStrategy defines the interface for log rotation strategies.
197- type RotateStrategy interface {
150+ // RollingPolicy defines the interface for log rotation strategies.
151+ type RollingPolicy interface {
198152 Time (t time.Time ) int64
199153 Format (t time.Time ) string
200154}
@@ -216,20 +170,25 @@ func (r FixedRotateStrategy) Format(t time.Time) string {
216170}
217171
218172// RegisterRotateStrategy registers a rotation strategy with a given name.
219- func RegisterRotateStrategy (name string , strategy RotateStrategy ) {
173+ func RegisterRotateStrategy (name string , strategy RollingPolicy ) {
220174 rotateStrategyRegistry [name ] = strategy
221175}
222176
177+ var noneRotateStrategy = & FixedRotateStrategy {}
178+
223179// ParseRotateStrategy retrieves a registered rotation strategy by name.
224- func ParseRotateStrategy (name string ) (RotateStrategy , error ) {
180+ func ParseRotateStrategy (name string ) (RollingPolicy , error ) {
181+ if name == "None" {
182+ return noneRotateStrategy , nil
183+ }
225184 s , ok := rotateStrategyRegistry [name ]
226185 if ! ok {
227186 return nil , fmt .Errorf ("invalid rotate strategy: %q" , name )
228187 }
229188 return s , nil
230189}
231190
232- // RotateFileAppender allows **multiple goroutines** to call Write()
191+ // FileAppender allows **multiple goroutines** to call Write()
233192// safely, at the cost of slightly higher overhead and potential
234193// (acceptable) log loss during rotation.
235194//
@@ -243,39 +202,42 @@ func ParseRotateStrategy(name string) (RotateStrategy, error) {
243202// - During Stop(), concurrent writes may also be lost.
244203// - If zero log loss is required, use AsyncRotateFileWriter
245204// with a dedicated logging goroutine instead.
246- type RotateFileAppender struct {
247- FileDir string
248- FileName string
249- ClearHours int32
250- RotateStrategy RotateStrategy
251- file atomic.Pointer [os.File ]
252- mutex sync.Mutex
253- currTime atomic.Int64
205+ type FileAppender struct {
206+ AppenderBase
207+ Layout Layout `PluginElement:"Layout,default=TextLayout"`
208+ FileDir string `PluginAttribute:"fileDir,default=./logs"`
209+ FileName string `PluginAttribute:"fileName"`
210+
211+ ClearHours int32
212+ RollingPolicy RollingPolicy
213+ file atomic.Pointer [os.File ]
214+ mutex sync.Mutex
215+ currTime atomic.Int64
254216}
255217
256218// Start opens the initial log file.
257- func (c * RotateFileAppender ) Start () error {
219+ func (c * FileAppender ) Start () error {
258220 now := time .Now ()
259221 filePath , file , err := c .createFile (now )
260222 if err != nil {
261223 return util .WrapError (err , "Failed to create log file %s" , filePath )
262224 }
263225 c .file .Store (file )
264- c .currTime .Store (c .RotateStrategy .Time (now ))
226+ c .currTime .Store (c .RollingPolicy .Time (now ))
265227 return nil
266228}
267229
268230// Write writes bytes to the current log file.
269231// May lose a few writes during rotation or Stop().
270- func (c * RotateFileAppender ) Write (b []byte ) {
232+ func (c * FileAppender ) Write (b []byte ) {
271233 c .rotate ()
272234 if file := c .file .Load (); file != nil {
273235 _ , _ = file .Write (b )
274236 }
275237}
276238
277239// Stop flushes and closes the current file.
278- func (c * RotateFileAppender ) Stop () {
240+ func (c * FileAppender ) Stop () {
279241 c .rotate ()
280242 if file := c .file .Swap (nil ); file != nil {
281243 _ = file .Sync ()
@@ -287,9 +249,9 @@ func (c *RotateFileAppender) Stop() {
287249// If so, it closes the old file, opens a new one, and triggers cleanup.
288250// Risk: If file creation fails during rotation, new logs will be lost
289251// until the issue is resolved.
290- func (c * RotateFileAppender ) rotate () {
252+ func (c * FileAppender ) rotate () {
291253 now := time .Now ()
292- nowTime := c .RotateStrategy .Time (now )
254+ nowTime := c .RollingPolicy .Time (now )
293255 if nowTime <= c .currTime .Load () {
294256 return // still in the current slot
295257 }
@@ -323,16 +285,16 @@ func (c *RotateFileAppender) rotate() {
323285 go c .clearExpiredFiles ()
324286}
325287
326- func (c * RotateFileAppender ) ConcurrentSafe () bool { return true }
288+ func (c * FileAppender ) ConcurrentSafe () bool { return true }
327289
328- func (c * RotateFileAppender ) Append (e * Event ) {
290+ func (c * FileAppender ) Append (e * Event ) {
329291 panic (util .ErrForbiddenMethod )
330292}
331293
332294// createFile creates or opens the current log file for appending.
333295// The application is responsible for ensuring the directory exists.
334- func (c * RotateFileAppender ) createFile (t time.Time ) (string , * os.File , error ) {
335- fileName := c .FileName + "." + c .RotateStrategy .Format (t )
296+ func (c * FileAppender ) createFile (t time.Time ) (string , * os.File , error ) {
297+ fileName := c .FileName + "." + c .RollingPolicy .Format (t )
336298 filePath := filepath .Join (c .FileDir , fileName )
337299 const fileFlag = os .O_CREATE | os .O_WRONLY | os .O_APPEND
338300 file , err := os .OpenFile (filePath , fileFlag , 0644 )
@@ -343,7 +305,7 @@ func (c *RotateFileAppender) createFile(t time.Time) (string, *os.File, error) {
343305}
344306
345307// clearExpiredFiles removes expired log files.
346- func (c * RotateFileAppender ) clearExpiredFiles () {
308+ func (c * FileAppender ) clearExpiredFiles () {
347309 expiration := time .Now ().Add (- time .Duration (c .ClearHours ) * time .Hour )
348310 entries , _ := os .ReadDir (c .FileDir )
349311 for _ , entry := range entries {
0 commit comments