2022-09-29 19:43:20 +00:00
|
|
|
package logging
|
|
|
|
|
|
|
|
import (
|
2022-10-05 09:37:52 +00:00
|
|
|
"context"
|
2022-09-29 19:43:20 +00:00
|
|
|
"errors"
|
|
|
|
"flag"
|
2022-10-19 13:12:55 +00:00
|
|
|
"io"
|
|
|
|
stdlog "log"
|
2022-09-29 19:43:20 +00:00
|
|
|
"os"
|
2022-10-19 13:12:55 +00:00
|
|
|
"strings"
|
2024-08-13 15:12:21 +00:00
|
|
|
"time"
|
2022-09-29 19:43:20 +00:00
|
|
|
|
|
|
|
"github.com/go-logr/logr"
|
2024-08-13 15:12:21 +00:00
|
|
|
"github.com/go-logr/zerologr"
|
|
|
|
"github.com/rs/zerolog"
|
2022-09-29 19:43:20 +00:00
|
|
|
"k8s.io/klog/v2"
|
|
|
|
"sigs.k8s.io/controller-runtime/pkg/log"
|
|
|
|
)
|
|
|
|
|
|
|
|
const (
|
|
|
|
// JSONFormat represents JSON logging mode.
|
|
|
|
JSONFormat = "json"
|
|
|
|
// TextFormat represents text logging mode.
|
|
|
|
// Default logging mode is TextFormat.
|
|
|
|
TextFormat = "text"
|
2022-10-18 14:42:43 +00:00
|
|
|
// LogLevelController is the log level to use for controllers plumbing.
|
2023-06-13 14:23:53 +00:00
|
|
|
LogLevelController = 1
|
2022-11-18 14:21:15 +00:00
|
|
|
// LogLevelClient is the log level to use for clients.
|
2023-06-13 14:23:53 +00:00
|
|
|
LogLevelClient = 1
|
2024-02-01 19:14:47 +00:00
|
|
|
// time formats
|
|
|
|
DefaultTime = "default"
|
|
|
|
ISO8601 = "iso8601"
|
|
|
|
RFC3339 = "rfc3339"
|
|
|
|
MILLIS = "millis"
|
|
|
|
NANOS = "nanos"
|
|
|
|
EPOCH = "epoch"
|
|
|
|
RFC3339NANO = "rfc3339nano"
|
2022-09-29 19:43:20 +00:00
|
|
|
)
|
|
|
|
|
2022-10-06 19:37:10 +00:00
|
|
|
// Initially, globalLog comes from controller-runtime/log with logger created earlier by controller-runtime.
|
|
|
|
// When logging.Setup is called, globalLog is switched to the real logger.
|
|
|
|
// Call depth of all loggers created before logging.Setup will not work, including package level loggers as they are created before main.
|
|
|
|
// All loggers created after logging.Setup won't be subject to the call depth limitation and will work if the underlying sink supports it.
|
2024-02-01 19:14:47 +00:00
|
|
|
|
|
|
|
var globalLog = log.Log // returns a Null log sink if SetLogger is not called.
|
2022-10-06 19:37:10 +00:00
|
|
|
|
2022-11-18 14:21:15 +00:00
|
|
|
func InitFlags(flags *flag.FlagSet) {
|
2022-09-29 19:43:20 +00:00
|
|
|
// clear flags initialized in static dependencies
|
|
|
|
if flag.CommandLine.Lookup("log_dir") != nil {
|
|
|
|
flag.CommandLine = flag.NewFlagSet(os.Args[0], flag.ExitOnError)
|
|
|
|
}
|
|
|
|
klog.InitFlags(flags)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Setup configures the logger with the supplied log format.
|
|
|
|
// It returns an error if the JSON logger could not be initialized or passed logFormat is not recognized.
|
2024-02-01 19:14:47 +00:00
|
|
|
func Setup(logFormat string, loggingTimestampFormat string, level int) error {
|
2024-08-15 13:49:50 +00:00
|
|
|
zerologr.SetMaxV(level)
|
2024-08-13 15:12:21 +00:00
|
|
|
|
|
|
|
var logger zerolog.Logger
|
2022-09-29 19:43:20 +00:00
|
|
|
switch logFormat {
|
|
|
|
case TextFormat:
|
2024-08-13 15:12:21 +00:00
|
|
|
output := zerolog.ConsoleWriter{Out: os.Stderr}
|
|
|
|
output.TimeFormat = resolveTimestampFormat(loggingTimestampFormat)
|
2024-08-16 14:08:55 +00:00
|
|
|
logger = zerolog.New(output).With().Timestamp().Caller().Logger()
|
2022-09-29 19:43:20 +00:00
|
|
|
case JSONFormat:
|
2024-08-13 15:12:21 +00:00
|
|
|
logger = zerolog.New(os.Stderr).With().Timestamp().Logger()
|
2022-09-30 06:13:13 +00:00
|
|
|
default:
|
|
|
|
return errors.New("log format not recognized, pass `text` for text mode or `json` to enable JSON logging")
|
2022-09-29 19:43:20 +00:00
|
|
|
}
|
2024-08-13 15:12:21 +00:00
|
|
|
|
|
|
|
globalLog = zerologr.New(&logger)
|
|
|
|
klog.SetLogger(globalLog.WithName("klog"))
|
|
|
|
log.SetLogger(globalLog)
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func resolveTimestampFormat(format string) string {
|
|
|
|
switch format {
|
2024-02-01 19:14:47 +00:00
|
|
|
case ISO8601:
|
2024-08-13 15:12:21 +00:00
|
|
|
return time.RFC3339
|
2024-02-01 19:14:47 +00:00
|
|
|
case RFC3339:
|
2024-08-13 15:12:21 +00:00
|
|
|
return time.RFC3339
|
2024-02-01 19:14:47 +00:00
|
|
|
case MILLIS:
|
2024-08-13 15:12:21 +00:00
|
|
|
return time.StampMilli
|
2024-02-01 19:14:47 +00:00
|
|
|
case NANOS:
|
2024-08-13 15:12:21 +00:00
|
|
|
return time.StampNano
|
2024-02-01 19:14:47 +00:00
|
|
|
case EPOCH:
|
2024-08-13 15:12:21 +00:00
|
|
|
return time.UnixDate
|
2024-02-01 19:14:47 +00:00
|
|
|
case RFC3339NANO:
|
2024-08-13 15:12:21 +00:00
|
|
|
return time.RFC3339Nano
|
2024-02-01 19:14:47 +00:00
|
|
|
default:
|
2024-08-13 15:12:21 +00:00
|
|
|
return time.RFC3339
|
2024-02-01 19:14:47 +00:00
|
|
|
}
|
2022-09-29 19:43:20 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// GlobalLogger returns a logr.Logger as configured in main.
|
|
|
|
func GlobalLogger() logr.Logger {
|
2022-10-06 19:37:10 +00:00
|
|
|
return globalLog
|
2022-09-29 19:43:20 +00:00
|
|
|
}
|
|
|
|
|
2022-10-18 14:42:43 +00:00
|
|
|
// ControllerLogger returns a logr.Logger to be used by controllers.
|
|
|
|
func ControllerLogger(name string) logr.Logger {
|
|
|
|
return globalLog.WithName(name).V(LogLevelController)
|
|
|
|
}
|
|
|
|
|
2022-11-18 14:21:15 +00:00
|
|
|
// ClientLogger returns a logr.Logger to be used by clients.
|
|
|
|
func ClientLogger(name string) logr.Logger {
|
|
|
|
return globalLog.WithName(name).V(LogLevelClient)
|
|
|
|
}
|
|
|
|
|
2022-09-29 19:43:20 +00:00
|
|
|
// WithName returns a new logr.Logger instance with the specified name element added to the Logger's name.
|
|
|
|
func WithName(name string) logr.Logger {
|
|
|
|
return GlobalLogger().WithName(name)
|
|
|
|
}
|
|
|
|
|
|
|
|
// WithValues returns a new logr.Logger instance with additional key/value pairs.
|
|
|
|
func WithValues(keysAndValues ...interface{}) logr.Logger {
|
|
|
|
return GlobalLogger().WithValues(keysAndValues...)
|
|
|
|
}
|
|
|
|
|
|
|
|
// V returns a new logr.Logger instance for a specific verbosity level.
|
|
|
|
func V(level int) logr.Logger {
|
|
|
|
return GlobalLogger().V(level)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Info logs a non-error message with the given key/value pairs.
|
|
|
|
func Info(msg string, keysAndValues ...interface{}) {
|
2022-10-06 19:37:10 +00:00
|
|
|
GlobalLogger().WithCallDepth(1).Info(msg, keysAndValues...)
|
2022-09-29 19:43:20 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Error logs an error, with the given message and key/value pairs.
|
|
|
|
func Error(err error, msg string, keysAndValues ...interface{}) {
|
2022-10-06 19:37:10 +00:00
|
|
|
GlobalLogger().WithCallDepth(1).Error(err, msg, keysAndValues...)
|
2022-09-29 19:43:20 +00:00
|
|
|
}
|
2022-10-05 09:37:52 +00:00
|
|
|
|
|
|
|
// FromContext returns a logger with predefined values from a context.Context.
|
|
|
|
func FromContext(ctx context.Context, keysAndValues ...interface{}) (logr.Logger, error) {
|
|
|
|
logger, err := logr.FromContext(ctx)
|
|
|
|
if err != nil {
|
|
|
|
return logger, err
|
|
|
|
}
|
|
|
|
return logger.WithValues(keysAndValues...), nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// IntoContext takes a context and sets the logger as one of its values.
|
|
|
|
// Use FromContext function to retrieve the logger.
|
|
|
|
func IntoContext(ctx context.Context, log logr.Logger) context.Context {
|
|
|
|
return logr.NewContext(ctx, log)
|
|
|
|
}
|
|
|
|
|
|
|
|
// IntoBackground calls IntoContext with the logger and a Background context.
|
|
|
|
func IntoBackground(log logr.Logger) context.Context {
|
|
|
|
return IntoContext(context.Background(), log)
|
|
|
|
}
|
|
|
|
|
|
|
|
// IntoTODO calls IntoContext with the logger and a TODO context.
|
|
|
|
func IntoTODO(log logr.Logger) context.Context {
|
|
|
|
return IntoContext(context.TODO(), log)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Background calls IntoContext with the global logger and a Background context.
|
|
|
|
func Background() context.Context {
|
|
|
|
return IntoContext(context.Background(), GlobalLogger())
|
|
|
|
}
|
|
|
|
|
|
|
|
// TODO calls IntoContext with the global logger and a TODO context.
|
|
|
|
func TODO() context.Context {
|
|
|
|
return IntoContext(context.TODO(), GlobalLogger())
|
|
|
|
}
|
2022-10-19 13:12:55 +00:00
|
|
|
|
|
|
|
type writerAdapter struct {
|
|
|
|
io.Writer
|
|
|
|
logger logr.Logger
|
|
|
|
}
|
|
|
|
|
|
|
|
func (a *writerAdapter) Write(p []byte) (int, error) {
|
|
|
|
a.logger.Info(strings.TrimSuffix(string(p), "\n"))
|
|
|
|
return len(p), nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func StdLogger(logger logr.Logger, prefix string) *stdlog.Logger {
|
|
|
|
return stdlog.New(&writerAdapter{logger: logger}, prefix, stdlog.LstdFlags)
|
|
|
|
}
|