feat: add error callback for file output writer
Some checks failed
Build RPM Package / Build RPM Packages (CentOS 7, Rocky 8/9/10) (push) Has been cancelled

- Add FileWriterOption type and WithFileErrorCallback option
- Add reportError method to FileWriter for error reporting
- Update Builder to propagate error callback to file writers
- File write errors now logged via the same callback mechanism
- Helps diagnose permission or disk space issues

Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
This commit is contained in:
Jacquin Antoine
2026-03-03 00:02:11 +01:00
parent babf254215
commit 76e68d15d9

View File

@ -68,6 +68,19 @@ type FileWriter struct {
maxSize int64
maxBackups int
currentSize int64
errorCallback ErrorCallback
failuresMu sync.Mutex
failures int
}
// FileWriterOption is a function type for configuring FileWriter
type FileWriterOption func(*FileWriter)
// WithFileErrorCallback sets an error callback for file write errors
func WithFileErrorCallback(cb ErrorCallback) FileWriterOption {
return func(w *FileWriter) {
w.errorCallback = cb
}
}
// NewFileWriter creates a new file writer with rotation
@ -76,7 +89,7 @@ func NewFileWriter(path string) (*FileWriter, error) {
}
// NewFileWriterWithConfig creates a new file writer with custom rotation config
func NewFileWriterWithConfig(path string, maxSize int64, maxBackups int) (*FileWriter, error) {
func NewFileWriterWithConfig(path string, maxSize int64, maxBackups int, opts ...FileWriterOption) (*FileWriter, error) {
// Create directory if it doesn't exist
dir := filepath.Dir(path)
if err := os.MkdirAll(dir, 0755); err != nil {
@ -96,14 +109,21 @@ func NewFileWriterWithConfig(path string, maxSize int64, maxBackups int) (*FileW
return nil, fmt.Errorf("failed to stat file: %w", err)
}
return &FileWriter{
w := &FileWriter{
file: file,
encoder: json.NewEncoder(file),
path: path,
maxSize: maxSize,
maxBackups: maxBackups,
currentSize: info.Size(),
}, nil
}
// Apply options (for error callback)
for _, opt := range opts {
opt(w)
}
return w, nil
}
// rotate rotates the log file if it exceeds the max size
@ -149,6 +169,7 @@ func (w *FileWriter) Write(rec api.LogRecord) error {
// Check if rotation is needed
if w.currentSize >= w.maxSize {
if err := w.rotate(); err != nil {
w.reportError(fmt.Errorf("failed to rotate file: %w", err))
return fmt.Errorf("failed to rotate file: %w", err)
}
}
@ -163,6 +184,7 @@ func (w *FileWriter) Write(rec api.LogRecord) error {
// Write to file
n, err := w.file.Write(data)
if err != nil {
w.reportError(fmt.Errorf("failed to write to file: %w", err))
return fmt.Errorf("failed to write to file: %w", err)
}
w.currentSize += int64(n)
@ -170,6 +192,17 @@ func (w *FileWriter) Write(rec api.LogRecord) error {
return nil
}
// reportError reports a file write error via the configured callback
func (w *FileWriter) reportError(err error) {
if w.errorCallback != nil {
w.failuresMu.Lock()
w.failures++
failures := w.failures
w.failuresMu.Unlock()
w.errorCallback(w.path, err, failures)
}
}
// Close closes the file
func (w *FileWriter) Close() error {
w.mutex.Lock()
@ -531,7 +564,7 @@ func NewBuilder() *BuilderImpl {
return &BuilderImpl{}
}
// WithErrorCallback sets an error callback for all unix_socket writers created by this builder
// WithErrorCallback sets an error callback for all unix_socket and file writers created by this builder
func (b *BuilderImpl) WithErrorCallback(cb ErrorCallback) *BuilderImpl {
b.errorCallback = cb
return b
@ -564,7 +597,12 @@ func (b *BuilderImpl) NewFromConfig(cfg api.AppConfig) (api.Writer, error) {
if path == "" {
return nil, fmt.Errorf("file output requires 'path' parameter")
}
writer, err = NewFileWriter(path)
// Build options list for file writer
var fileOpts []FileWriterOption
if b.errorCallback != nil {
fileOpts = append(fileOpts, WithFileErrorCallback(b.errorCallback))
}
writer, err = NewFileWriterWithConfig(path, DefaultMaxFileSize, DefaultMaxBackups, fileOpts...)
if err != nil {
return nil, err
}