traefik/pkg/log/log.go
2020-11-06 09:26:03 +01:00

145 lines
2.7 KiB
Go

package log
import (
"context"
"fmt"
"io"
"os"
"github.com/sirupsen/logrus"
)
type contextKey int
const (
loggerKey contextKey = iota
)
// Logger the Traefik logger.
type Logger interface {
logrus.FieldLogger
WriterLevel(logrus.Level) *io.PipeWriter
}
var (
mainLogger Logger
logFilePath string
logFile *os.File
)
func init() {
mainLogger = logrus.StandardLogger()
logrus.SetOutput(os.Stdout)
}
// SetLogger sets the logger.
func SetLogger(l Logger) {
mainLogger = l
}
// SetOutput sets the standard logger output.
func SetOutput(out io.Writer) {
logrus.SetOutput(out)
}
// SetFormatter sets the standard logger formatter.
func SetFormatter(formatter logrus.Formatter) {
logrus.SetFormatter(formatter)
}
// SetLevel sets the standard logger level.
func SetLevel(level logrus.Level) {
logrus.SetLevel(level)
}
// GetLevel returns the standard logger level.
func GetLevel() logrus.Level {
return logrus.GetLevel()
}
// Str adds a string field.
func Str(key, value string) func(logrus.Fields) {
return func(fields logrus.Fields) {
fields[key] = value
}
}
// With Adds fields.
func With(ctx context.Context, opts ...func(logrus.Fields)) context.Context {
logger := FromContext(ctx)
fields := make(logrus.Fields)
for _, opt := range opts {
opt(fields)
}
logger = logger.WithFields(fields)
return context.WithValue(ctx, loggerKey, logger)
}
// FromContext Gets the logger from context.
func FromContext(ctx context.Context) Logger {
if ctx == nil {
panic("nil context")
}
logger, ok := ctx.Value(loggerKey).(Logger)
if !ok {
logger = mainLogger
}
return logger
}
// WithoutContext Gets the main logger.
func WithoutContext() Logger {
return mainLogger
}
// OpenFile opens the log file using the specified path.
func OpenFile(path string) error {
logFilePath = path
var err error
logFile, err = os.OpenFile(logFilePath, os.O_RDWR|os.O_CREATE|os.O_APPEND, 0o666)
if err != nil {
return err
}
SetOutput(logFile)
return nil
}
// CloseFile closes the log and sets the Output to stdout.
func CloseFile() error {
logrus.SetOutput(os.Stdout)
if logFile != nil {
return logFile.Close()
}
return nil
}
// RotateFile closes and reopens the log file to allow for rotation by an external source.
// If the log isn't backed by a file then it does nothing.
func RotateFile() error {
logger := FromContext(context.Background())
if logFile == nil && logFilePath == "" {
logger.Debug("Traefik log is not writing to a file, ignoring rotate request")
return nil
}
if logFile != nil {
defer func(f *os.File) {
_ = f.Close()
}(logFile)
}
if err := OpenFile(logFilePath); err != nil {
return fmt.Errorf("error opening log file: %w", err)
}
return nil
}