Skip to content

Commit b57c067

Browse files
lvan100lianghuan
authored andcommitted
111
1 parent 8f5b8aa commit b57c067

File tree

4 files changed

+61
-16
lines changed

4 files changed

+61
-16
lines changed

plugin_appender.go

Lines changed: 57 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -33,10 +33,11 @@ import (
3333
var Stdout io.Writer = os.Stdout
3434

3535
func init() {
36+
RegisterPlugin[GroupAppender]("Group", PluginTypeAppender)
3637
RegisterPlugin[DiscardAppender]("Discard", PluginTypeAppender)
3738
RegisterPlugin[ConsoleAppender]("Console", PluginTypeAppender)
3839
RegisterPlugin[FileAppender]("File", PluginTypeAppender)
39-
RegisterPlugin[GroupAppender]("Group", PluginTypeAppender)
40+
RegisterPlugin[RollingFileAppender]("RotateFile", PluginTypeAppender)
4041

4142
// register built-in converters
4243
RegisterConverter(ParseRotateStrategy)
@@ -63,7 +64,7 @@ var (
6364
_ Appender = (*GroupAppender)(nil)
6465
_ Appender = (*DiscardAppender)(nil)
6566
_ Appender = (*ConsoleAppender)(nil)
66-
_ Appender = (*FileAppender)(nil)
67+
_ Appender = (*RollingFileAppender)(nil)
6768
)
6869

6970
// AppenderBase provides common configuration fields for all appenders.
@@ -145,6 +146,50 @@ func (c *ConsoleAppender) Write(b []byte) {
145146
_, _ = Stdout.Write(b)
146147
}
147148

149+
// FileAppender writes formatted log events to a specified file.
150+
type FileAppender struct {
151+
AppenderBase
152+
Layout Layout `PluginElement:"Layout,default=TextLayout"`
153+
FileDir string `PluginAttribute:"fileDir,default=./logs"`
154+
FileName string `PluginAttribute:"fileName"`
155+
156+
file *os.File
157+
}
158+
159+
func (c *FileAppender) ConcurrentSafe() bool { return true }
160+
161+
// Start opens the log file for appending.
162+
func (c *FileAppender) Start() error {
163+
const fileFlag = os.O_WRONLY | os.O_CREATE | os.O_APPEND
164+
fileName := filepath.Join(c.FileDir, c.FileName)
165+
f, err := os.OpenFile(fileName, fileFlag, 0644)
166+
if err != nil {
167+
return err
168+
}
169+
c.file = f
170+
return nil
171+
}
172+
173+
// Append formats the log event and writes it to the file.
174+
func (c *FileAppender) Append(e *Event) {
175+
if c.EnableLevel(e.Level) {
176+
c.Write(c.Layout.ToBytes(e))
177+
}
178+
}
179+
180+
// Write writes a byte slice directly to the file.
181+
func (c *FileAppender) Write(b []byte) {
182+
_, _ = c.file.Write(b)
183+
}
184+
185+
// Stop flushes and closes the file.
186+
func (c *FileAppender) Stop() {
187+
if c.file != nil {
188+
_ = c.file.Sync()
189+
_ = c.file.Close()
190+
}
191+
}
192+
148193
var rotateStrategyRegistry = map[string]RollingPolicy{}
149194

150195
// RollingPolicy defines the interface for log rotation strategies.
@@ -188,7 +233,7 @@ func ParseRotateStrategy(name string) (RollingPolicy, error) {
188233
return s, nil
189234
}
190235

191-
// FileAppender allows **multiple goroutines** to call Write()
236+
// RollingFileAppender allows **multiple goroutines** to call Write()
192237
// safely, at the cost of slightly higher overhead and potential
193238
// (acceptable) log loss during rotation.
194239
//
@@ -202,7 +247,7 @@ func ParseRotateStrategy(name string) (RollingPolicy, error) {
202247
// - During Stop(), concurrent writes may also be lost.
203248
// - If zero log loss is required, use AsyncRotateFileWriter
204249
// with a dedicated logging goroutine instead.
205-
type FileAppender struct {
250+
type RollingFileAppender struct {
206251
AppenderBase
207252
Layout Layout `PluginElement:"Layout,default=TextLayout"`
208253
FileDir string `PluginAttribute:"fileDir,default=./logs"`
@@ -216,7 +261,7 @@ type FileAppender struct {
216261
}
217262

218263
// Start opens the initial log file.
219-
func (c *FileAppender) Start() error {
264+
func (c *RollingFileAppender) Start() error {
220265
now := time.Now()
221266
filePath, file, err := c.createFile(now)
222267
if err != nil {
@@ -229,15 +274,15 @@ func (c *FileAppender) Start() error {
229274

230275
// Write writes bytes to the current log file.
231276
// May lose a few writes during rotation or Stop().
232-
func (c *FileAppender) Write(b []byte) {
277+
func (c *RollingFileAppender) Write(b []byte) {
233278
c.rotate()
234279
if file := c.file.Load(); file != nil {
235280
_, _ = file.Write(b)
236281
}
237282
}
238283

239284
// Stop flushes and closes the current file.
240-
func (c *FileAppender) Stop() {
285+
func (c *RollingFileAppender) Stop() {
241286
c.rotate()
242287
if file := c.file.Swap(nil); file != nil {
243288
_ = file.Sync()
@@ -249,7 +294,7 @@ func (c *FileAppender) Stop() {
249294
// If so, it closes the old file, opens a new one, and triggers cleanup.
250295
// Risk: If file creation fails during rotation, new logs will be lost
251296
// until the issue is resolved.
252-
func (c *FileAppender) rotate() {
297+
func (c *RollingFileAppender) rotate() {
253298
now := time.Now()
254299
nowTime := c.RollingPolicy.Time(now)
255300
if nowTime <= c.currTime.Load() {
@@ -285,15 +330,15 @@ func (c *FileAppender) rotate() {
285330
go c.clearExpiredFiles()
286331
}
287332

288-
func (c *FileAppender) ConcurrentSafe() bool { return true }
333+
func (c *RollingFileAppender) ConcurrentSafe() bool { return true }
289334

290-
func (c *FileAppender) Append(e *Event) {
335+
func (c *RollingFileAppender) Append(e *Event) {
291336
panic(util.ErrForbiddenMethod)
292337
}
293338

294339
// createFile creates or opens the current log file for appending.
295340
// The application is responsible for ensuring the directory exists.
296-
func (c *FileAppender) createFile(t time.Time) (string, *os.File, error) {
341+
func (c *RollingFileAppender) createFile(t time.Time) (string, *os.File, error) {
297342
fileName := c.FileName + "." + c.RollingPolicy.Format(t)
298343
filePath := filepath.Join(c.FileDir, fileName)
299344
const fileFlag = os.O_CREATE | os.O_WRONLY | os.O_APPEND
@@ -305,7 +350,7 @@ func (c *FileAppender) createFile(t time.Time) (string, *os.File, error) {
305350
}
306351

307352
// clearExpiredFiles removes expired log files.
308-
func (c *FileAppender) clearExpiredFiles() {
353+
func (c *RollingFileAppender) clearExpiredFiles() {
309354
expiration := time.Now().Add(-time.Duration(c.ClearHours) * time.Hour)
310355
entries, _ := os.ReadDir(c.FileDir)
311356
for _, entry := range entries {

plugin_appender_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -141,7 +141,7 @@ func TestFileAppender(t *testing.T) {
141141

142142
a.Stop()
143143

144-
b, err := os.ReadFile(a.file.Load().Name())
144+
b, err := os.ReadFile(a.file.Name())
145145
assert.Error(t, err).Nil()
146146
assert.String(t, string(b)).Equal("[INFO][0001-01-01T00:00:00.000][file.go:100] _def||msg=hello world\n")
147147
})

plugin_logger.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -302,7 +302,7 @@ func initFileLogger(
302302
// Create appenders for the normal log file
303303
appenders := []*AppenderRef{
304304
{
305-
Appender: &FileAppender{
305+
Appender: &RollingFileAppender{
306306
AppenderBase: AppenderBase{
307307
MinLevel: f.MinLevel,
308308
MaxLevel: normalMaxLevel,
@@ -318,7 +318,7 @@ func initFileLogger(
318318
// Create appenders for warning and error logs if Separate is enabled
319319
if f.Separate {
320320
appenders = append(appenders, &AppenderRef{
321-
Appender: &FileAppender{
321+
Appender: &RollingFileAppender{
322322
AppenderBase: AppenderBase{
323323
MinLevel: WarnLevel,
324324
MaxLevel: MaxLevel,

plugin_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ func TestRegisterPlugin(t *testing.T) {
3030
}, "T must be struct")
3131
assert.Panic(t, func() {
3232
RegisterPlugin[FileAppender]("File", PluginTypeAppender)
33-
}, "duplicate plugin name \"File\" in .*/plugin_appender.go:31 and .*/plugin_test.go:32")
33+
}, "duplicate plugin name \"File\" in .*/plugin_appender.go:39 and .*/plugin_test.go:32")
3434
}
3535

3636
func TestInjectAttribute(t *testing.T) {

0 commit comments

Comments
 (0)