2018-11-14 10:18:03 +01:00
package log
import (
"context"
"fmt"
"io"
"os"
"github.com/sirupsen/logrus"
)
type contextKey int
const (
loggerKey contextKey = iota
)
2020-05-11 12:06:07 +02:00
// Logger the Traefik logger.
2018-11-14 10:18:03 +01:00
type Logger interface {
logrus . FieldLogger
2023-11-17 01:50:06 +01:00
WriterLevel ( level logrus . Level ) * io . PipeWriter
2018-11-14 10:18:03 +01:00
}
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 ( )
}
2020-05-11 12:06:07 +02:00
// Str adds a string field.
2018-11-14 10:18:03 +01:00
func Str ( key , value string ) func ( logrus . Fields ) {
return func ( fields logrus . Fields ) {
fields [ key ] = value
}
}
2020-05-11 12:06:07 +02:00
// With Adds fields.
2018-11-14 10:18:03 +01:00
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 )
}
2020-05-11 12:06:07 +02:00
// FromContext Gets the logger from context.
2018-11-14 10:18:03 +01:00
func FromContext ( ctx context . Context ) Logger {
if ctx == nil {
panic ( "nil context" )
}
logger , ok := ctx . Value ( loggerKey ) . ( Logger )
if ! ok {
logger = mainLogger
}
return logger
}
2020-05-11 12:06:07 +02:00
// WithoutContext Gets the main logger.
2018-11-14 10:18:03 +01:00
func WithoutContext ( ) Logger {
return mainLogger
}
2020-05-11 12:06:07 +02:00
// OpenFile opens the log file using the specified path.
2018-11-14 10:18:03 +01:00
func OpenFile ( path string ) error {
logFilePath = path
var err error
2020-07-07 14:42:03 +02:00
logFile , err = os . OpenFile ( logFilePath , os . O_RDWR | os . O_CREATE | os . O_APPEND , 0 o666 )
2018-11-14 10:18:03 +01:00
if err != nil {
return err
}
SetOutput ( logFile )
return nil
}
2020-05-11 12:06:07 +02:00
// CloseFile closes the log and sets the Output to stdout.
2018-11-14 10:18:03 +01:00
func CloseFile ( ) error {
logrus . SetOutput ( os . Stdout )
if logFile != nil {
return logFile . Close ( )
}
return nil
}
2020-05-11 12:06:07 +02:00
// 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.
2018-11-14 10:18:03 +01:00
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 {
2020-11-06 09:26:03 +01:00
return fmt . Errorf ( "error opening log file: %w" , err )
2018-11-14 10:18:03 +01:00
}
return nil
}