lnd/build/logrotator.go

106 lines
2.6 KiB
Go
Raw Normal View History

2019-09-20 16:01:31 +02:00
package build
import (
2024-08-27 00:59:52 +02:00
"compress/gzip"
2019-09-20 16:01:31 +02:00
"fmt"
"io"
"os"
"path/filepath"
"github.com/jrick/logrotate/rotator"
2024-08-27 00:59:52 +02:00
"github.com/klauspost/compress/zstd"
2019-09-20 16:01:31 +02:00
)
// RotatingLogWriter is a wrapper around the LogWriter that supports log file
// rotation.
type RotatingLogWriter struct {
// pipe is the write-end pipe for writing to the log rotator.
pipe *io.PipeWriter
2019-09-20 16:01:31 +02:00
rotator *rotator.Rotator
2019-09-20 16:01:31 +02:00
}
// NewRotatingLogWriter creates a new file rotating log writer.
//
// NOTE: `InitLogRotator` must be called to set up log rotation after creating
// the writer.
func NewRotatingLogWriter() *RotatingLogWriter {
return &RotatingLogWriter{}
2019-09-20 16:01:31 +02:00
}
// InitLogRotator initializes the log file rotator to write logs to logFile and
// create roll files in the same directory. It should be called as early on
// startup and possible and must be closed on shutdown by calling `Close`.
2024-08-27 00:59:52 +02:00
func (r *RotatingLogWriter) InitLogRotator(logFile, logCompressor string,
maxLogFileSize int, maxLogFiles int) error {
2019-09-20 16:01:31 +02:00
logDir, _ := filepath.Split(logFile)
err := os.MkdirAll(logDir, 0700)
if err != nil {
return fmt.Errorf("failed to create log directory: %w", err)
2019-09-20 16:01:31 +02:00
}
r.rotator, err = rotator.New(
2019-09-20 16:01:31 +02:00
logFile, int64(maxLogFileSize*1024), false, maxLogFiles,
)
if err != nil {
return fmt.Errorf("failed to create file rotator: %w", err)
2019-09-20 16:01:31 +02:00
}
2024-08-27 00:59:52 +02:00
// Reject unknown compressors.
if !SuportedLogCompressor(logCompressor) {
return fmt.Errorf("unknown log compressor: %v", logCompressor)
}
var c rotator.Compressor
switch logCompressor {
case Gzip:
c = gzip.NewWriter(nil)
case Zstd:
c, err = zstd.NewWriter(nil)
if err != nil {
return fmt.Errorf("failed to create zstd compressor: "+
"%w", err)
}
}
// Apply the compressor and its file suffix to the log rotator.
r.rotator.SetCompressor(c, logCompressors[logCompressor])
2024-08-27 00:59:52 +02:00
2019-09-20 16:01:31 +02:00
// Run rotator as a goroutine now but make sure we catch any errors
// that happen in case something with the rotation goes wrong during
// runtime (like running out of disk space or not being allowed to
// create a new logfile for whatever reason).
pr, pw := io.Pipe()
go func() {
err := r.rotator.Run(pr)
2019-09-20 16:01:31 +02:00
if err != nil {
_, _ = fmt.Fprintf(os.Stderr,
"failed to run file rotator: %v\n", err)
}
}()
r.pipe = pw
2019-09-20 16:01:31 +02:00
return nil
}
// Write writes the byte slice to the log rotator, if present.
func (r *RotatingLogWriter) Write(b []byte) (int, error) {
if r.rotator != nil {
return r.rotator.Write(b)
}
return len(b), nil
}
2019-09-20 16:01:31 +02:00
// Close closes the underlying log rotator if it has already been created.
func (r *RotatingLogWriter) Close() error {
if r.rotator != nil {
return r.rotator.Close()
2019-09-20 16:01:31 +02:00
}
return nil
2019-09-20 16:01:31 +02:00
}