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
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:
@ -61,13 +61,26 @@ func (w *StdoutWriter) Close() error {
|
|||||||
|
|
||||||
// FileWriter writes log records to a file with rotation support
|
// FileWriter writes log records to a file with rotation support
|
||||||
type FileWriter struct {
|
type FileWriter struct {
|
||||||
file *os.File
|
file *os.File
|
||||||
encoder *json.Encoder
|
encoder *json.Encoder
|
||||||
mutex sync.Mutex
|
mutex sync.Mutex
|
||||||
path string
|
path string
|
||||||
maxSize int64
|
maxSize int64
|
||||||
maxBackups int
|
maxBackups int
|
||||||
currentSize int64
|
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
|
// 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
|
// 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
|
// Create directory if it doesn't exist
|
||||||
dir := filepath.Dir(path)
|
dir := filepath.Dir(path)
|
||||||
if err := os.MkdirAll(dir, 0755); err != nil {
|
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 nil, fmt.Errorf("failed to stat file: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
return &FileWriter{
|
w := &FileWriter{
|
||||||
file: file,
|
file: file,
|
||||||
encoder: json.NewEncoder(file),
|
encoder: json.NewEncoder(file),
|
||||||
path: path,
|
path: path,
|
||||||
maxSize: maxSize,
|
maxSize: maxSize,
|
||||||
maxBackups: maxBackups,
|
maxBackups: maxBackups,
|
||||||
currentSize: info.Size(),
|
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
|
// 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
|
// Check if rotation is needed
|
||||||
if w.currentSize >= w.maxSize {
|
if w.currentSize >= w.maxSize {
|
||||||
if err := w.rotate(); err != nil {
|
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)
|
return fmt.Errorf("failed to rotate file: %w", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -163,6 +184,7 @@ func (w *FileWriter) Write(rec api.LogRecord) error {
|
|||||||
// Write to file
|
// Write to file
|
||||||
n, err := w.file.Write(data)
|
n, err := w.file.Write(data)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
w.reportError(fmt.Errorf("failed to write to file: %w", err))
|
||||||
return fmt.Errorf("failed to write to file: %w", err)
|
return fmt.Errorf("failed to write to file: %w", err)
|
||||||
}
|
}
|
||||||
w.currentSize += int64(n)
|
w.currentSize += int64(n)
|
||||||
@ -170,6 +192,17 @@ func (w *FileWriter) Write(rec api.LogRecord) error {
|
|||||||
return nil
|
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
|
// Close closes the file
|
||||||
func (w *FileWriter) Close() error {
|
func (w *FileWriter) Close() error {
|
||||||
w.mutex.Lock()
|
w.mutex.Lock()
|
||||||
@ -531,7 +564,7 @@ func NewBuilder() *BuilderImpl {
|
|||||||
return &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 {
|
func (b *BuilderImpl) WithErrorCallback(cb ErrorCallback) *BuilderImpl {
|
||||||
b.errorCallback = cb
|
b.errorCallback = cb
|
||||||
return b
|
return b
|
||||||
@ -564,7 +597,12 @@ func (b *BuilderImpl) NewFromConfig(cfg api.AppConfig) (api.Writer, error) {
|
|||||||
if path == "" {
|
if path == "" {
|
||||||
return nil, fmt.Errorf("file output requires 'path' parameter")
|
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 {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user