logging/backend.go

149 lines
3.1 KiB
Go

package logging
import (
"fmt"
"io"
"os"
)
// Backend is the interface that specifies the methods that a backend must
// implement
type Backend interface {
Write(*Record) error
SetFormatter(*Formatter)
SetLevel(Level)
Level() Level
Reopen() error
}
//
// Backend to write in file-like objects
//
// FileBackend is a backend that writes to a file.
type FileBackend struct {
l io.Writer
formatter *Formatter
level Level
filepath string
}
// NewStdoutBackend creates a new backend to write the logs on the standard
// output
func NewStdoutBackend() (b *FileBackend) {
b = &FileBackend{
l: os.Stdout,
formatter: &defaultFormatter,
}
return
}
// NewStderrBackend creates a new backend to write the logs on the error output
func NewStderrBackend() (b *FileBackend) {
b = &FileBackend{
l: os.Stderr,
formatter: &defaultFormatter,
}
return
}
// NewFileBackend creates a new backend to write the logs in a given file
func NewFileBackend(filename string) (*FileBackend, error) {
fd, err := os.OpenFile(filename, os.O_WRONLY|os.O_APPEND|os.O_CREATE, 0644) //nolint: gosec
if err != nil {
return nil, fmt.Errorf("Cannot open log file %s: %w", filename, err)
}
b := &FileBackend{
l: fd,
formatter: &defaultFormatter,
filepath: filename,
}
return b, nil
}
// NewIoBackend creates a new backend to write the logs in a given io.Writer
func NewIoBackend(buf io.Writer) (b *FileBackend) {
return &FileBackend{
l: buf,
formatter: &defaultFormatter,
}
}
func (b FileBackend) Write(r *Record) error {
text := (*b.formatter)(r)
_, err := io.WriteString(b.l, text)
return err
}
// SetLevel changes the log level of the backend
func (b *FileBackend) SetLevel(l Level) {
b.level = l
}
// Level returns the log level set for this backend
func (b *FileBackend) Level() Level {
return b.level
}
// SetFormatter defines the formatter for this backend
func (b *FileBackend) SetFormatter(f *Formatter) {
b.formatter = f
}
// Reopen closes and reopens the file it writes to. It should be used after log
// rotation
func (b *FileBackend) Reopen() error {
if b.filepath == "" {
return nil
}
if c, ok := b.l.(io.Closer); ok {
if err := c.Close(); err != nil {
return err
}
}
fd, err := os.OpenFile(b.filepath, os.O_WRONLY|os.O_APPEND|os.O_CREATE, 0644) //nolint: gosec
if err != nil {
return fmt.Errorf("Cannot open log file %s: %w", b.filepath, err)
}
b.l = fd
return nil
}
//
// Noop Backend
//
// NoopBackend does nothing and discards all log entries without writing them anywhere
type NoopBackend struct{}
// NewNoopBackend creates a noop backend
func NewNoopBackend() (Backend, error) {
return &NoopBackend{}, nil
}
// Write is a noop
func (nb *NoopBackend) Write(r *Record) error {
return nil
}
// SetFormatter is a noop
func (nb *NoopBackend) SetFormatter(f *Formatter) {}
// SetLevel is a noop
func (nb *NoopBackend) SetLevel(level Level) {}
// Level always returns DefeultLevel
func (nb *NoopBackend) Level() Level {
return DefaultLevel
}
// Reopen is a noop
func (nb *NoopBackend) Reopen() error {
return nil
}