| // Copyright 2015 The Prometheus Authors |
| // Licensed under the Apache License, Version 2.0 (the "License"); |
| // you may not use this file except in compliance with the License. |
| // You may obtain a copy of the License at |
| // |
| // http://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, software |
| // distributed under the License is distributed on an "AS IS" BASIS, |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| // See the License for the specific language governing permissions and |
| // limitations under the License. |
| |
| package log |
| |
| import ( |
| "fmt" |
| "io" |
| "io/ioutil" |
| "log" |
| "net/url" |
| "os" |
| "runtime" |
| "strconv" |
| "strings" |
| |
| "github.com/sirupsen/logrus" |
| "gopkg.in/alecthomas/kingpin.v2" |
| ) |
| |
| // setSyslogFormatter is nil if the target architecture does not support syslog. |
| var setSyslogFormatter func(logger, string, string) error |
| |
| // setEventlogFormatter is nil if the target OS does not support Eventlog (i.e., is not Windows). |
| var setEventlogFormatter func(logger, string, bool) error |
| |
| func setJSONFormatter() { |
| origLogger.Formatter = &logrus.JSONFormatter{} |
| } |
| |
| type loggerSettings struct { |
| level string |
| format string |
| } |
| |
| func (s *loggerSettings) apply(ctx *kingpin.ParseContext) error { |
| err := baseLogger.SetLevel(s.level) |
| if err != nil { |
| return err |
| } |
| err = baseLogger.SetFormat(s.format) |
| return err |
| } |
| |
| // AddFlags adds the flags used by this package to the Kingpin application. |
| // To use the default Kingpin application, call AddFlags(kingpin.CommandLine) |
| func AddFlags(a *kingpin.Application) { |
| s := loggerSettings{} |
| a.Flag("log.level", "Only log messages with the given severity or above. Valid levels: [debug, info, warn, error, fatal]"). |
| Default(origLogger.Level.String()). |
| StringVar(&s.level) |
| defaultFormat := url.URL{Scheme: "logger", Opaque: "stderr"} |
| a.Flag("log.format", `Set the log target and format. Example: "logger:syslog?appname=bob&local=7" or "logger:stdout?json=true"`). |
| Default(defaultFormat.String()). |
| StringVar(&s.format) |
| a.Action(s.apply) |
| } |
| |
| // Logger is the interface for loggers used in the Prometheus components. |
| type Logger interface { |
| Debug(...interface{}) |
| Debugln(...interface{}) |
| Debugf(string, ...interface{}) |
| |
| Info(...interface{}) |
| Infoln(...interface{}) |
| Infof(string, ...interface{}) |
| |
| Warn(...interface{}) |
| Warnln(...interface{}) |
| Warnf(string, ...interface{}) |
| |
| Error(...interface{}) |
| Errorln(...interface{}) |
| Errorf(string, ...interface{}) |
| |
| Fatal(...interface{}) |
| Fatalln(...interface{}) |
| Fatalf(string, ...interface{}) |
| |
| With(key string, value interface{}) Logger |
| |
| SetFormat(string) error |
| SetLevel(string) error |
| } |
| |
| type logger struct { |
| entry *logrus.Entry |
| } |
| |
| func (l logger) With(key string, value interface{}) Logger { |
| return logger{l.entry.WithField(key, value)} |
| } |
| |
| // Debug logs a message at level Debug on the standard logger. |
| func (l logger) Debug(args ...interface{}) { |
| l.sourced().Debug(args...) |
| } |
| |
| // Debug logs a message at level Debug on the standard logger. |
| func (l logger) Debugln(args ...interface{}) { |
| l.sourced().Debugln(args...) |
| } |
| |
| // Debugf logs a message at level Debug on the standard logger. |
| func (l logger) Debugf(format string, args ...interface{}) { |
| l.sourced().Debugf(format, args...) |
| } |
| |
| // Info logs a message at level Info on the standard logger. |
| func (l logger) Info(args ...interface{}) { |
| l.sourced().Info(args...) |
| } |
| |
| // Info logs a message at level Info on the standard logger. |
| func (l logger) Infoln(args ...interface{}) { |
| l.sourced().Infoln(args...) |
| } |
| |
| // Infof logs a message at level Info on the standard logger. |
| func (l logger) Infof(format string, args ...interface{}) { |
| l.sourced().Infof(format, args...) |
| } |
| |
| // Warn logs a message at level Warn on the standard logger. |
| func (l logger) Warn(args ...interface{}) { |
| l.sourced().Warn(args...) |
| } |
| |
| // Warn logs a message at level Warn on the standard logger. |
| func (l logger) Warnln(args ...interface{}) { |
| l.sourced().Warnln(args...) |
| } |
| |
| // Warnf logs a message at level Warn on the standard logger. |
| func (l logger) Warnf(format string, args ...interface{}) { |
| l.sourced().Warnf(format, args...) |
| } |
| |
| // Error logs a message at level Error on the standard logger. |
| func (l logger) Error(args ...interface{}) { |
| l.sourced().Error(args...) |
| } |
| |
| // Error logs a message at level Error on the standard logger. |
| func (l logger) Errorln(args ...interface{}) { |
| l.sourced().Errorln(args...) |
| } |
| |
| // Errorf logs a message at level Error on the standard logger. |
| func (l logger) Errorf(format string, args ...interface{}) { |
| l.sourced().Errorf(format, args...) |
| } |
| |
| // Fatal logs a message at level Fatal on the standard logger. |
| func (l logger) Fatal(args ...interface{}) { |
| l.sourced().Fatal(args...) |
| } |
| |
| // Fatal logs a message at level Fatal on the standard logger. |
| func (l logger) Fatalln(args ...interface{}) { |
| l.sourced().Fatalln(args...) |
| } |
| |
| // Fatalf logs a message at level Fatal on the standard logger. |
| func (l logger) Fatalf(format string, args ...interface{}) { |
| l.sourced().Fatalf(format, args...) |
| } |
| |
| func (l logger) SetLevel(level string) error { |
| lvl, err := logrus.ParseLevel(level) |
| if err != nil { |
| return err |
| } |
| |
| l.entry.Logger.Level = lvl |
| return nil |
| } |
| |
| func (l logger) SetFormat(format string) error { |
| u, err := url.Parse(format) |
| if err != nil { |
| return err |
| } |
| if u.Scheme != "logger" { |
| return fmt.Errorf("invalid scheme %s", u.Scheme) |
| } |
| jsonq := u.Query().Get("json") |
| if jsonq == "true" { |
| setJSONFormatter() |
| } |
| |
| switch u.Opaque { |
| case "syslog": |
| if setSyslogFormatter == nil { |
| return fmt.Errorf("system does not support syslog") |
| } |
| appname := u.Query().Get("appname") |
| facility := u.Query().Get("local") |
| return setSyslogFormatter(l, appname, facility) |
| case "eventlog": |
| if setEventlogFormatter == nil { |
| return fmt.Errorf("system does not support eventlog") |
| } |
| name := u.Query().Get("name") |
| debugAsInfo := false |
| debugAsInfoRaw := u.Query().Get("debugAsInfo") |
| if parsedDebugAsInfo, err := strconv.ParseBool(debugAsInfoRaw); err == nil { |
| debugAsInfo = parsedDebugAsInfo |
| } |
| return setEventlogFormatter(l, name, debugAsInfo) |
| case "stdout": |
| l.entry.Logger.Out = os.Stdout |
| case "stderr": |
| l.entry.Logger.Out = os.Stderr |
| default: |
| return fmt.Errorf("unsupported logger %q", u.Opaque) |
| } |
| return nil |
| } |
| |
| // sourced adds a source field to the logger that contains |
| // the file name and line where the logging happened. |
| func (l logger) sourced() *logrus.Entry { |
| _, file, line, ok := runtime.Caller(2) |
| if !ok { |
| file = "<???>" |
| line = 1 |
| } else { |
| slash := strings.LastIndex(file, "/") |
| file = file[slash+1:] |
| } |
| return l.entry.WithField("source", fmt.Sprintf("%s:%d", file, line)) |
| } |
| |
| var origLogger = logrus.New() |
| var baseLogger = logger{entry: logrus.NewEntry(origLogger)} |
| |
| // Base returns the default Logger logging to |
| func Base() Logger { |
| return baseLogger |
| } |
| |
| // NewLogger returns a new Logger logging to out. |
| func NewLogger(w io.Writer) Logger { |
| l := logrus.New() |
| l.Out = w |
| return logger{entry: logrus.NewEntry(l)} |
| } |
| |
| // NewNopLogger returns a logger that discards all log messages. |
| func NewNopLogger() Logger { |
| l := logrus.New() |
| l.Out = ioutil.Discard |
| return logger{entry: logrus.NewEntry(l)} |
| } |
| |
| // With adds a field to the logger. |
| func With(key string, value interface{}) Logger { |
| return baseLogger.With(key, value) |
| } |
| |
| // Debug logs a message at level Debug on the standard logger. |
| func Debug(args ...interface{}) { |
| baseLogger.sourced().Debug(args...) |
| } |
| |
| // Debugln logs a message at level Debug on the standard logger. |
| func Debugln(args ...interface{}) { |
| baseLogger.sourced().Debugln(args...) |
| } |
| |
| // Debugf logs a message at level Debug on the standard logger. |
| func Debugf(format string, args ...interface{}) { |
| baseLogger.sourced().Debugf(format, args...) |
| } |
| |
| // Info logs a message at level Info on the standard logger. |
| func Info(args ...interface{}) { |
| baseLogger.sourced().Info(args...) |
| } |
| |
| // Infoln logs a message at level Info on the standard logger. |
| func Infoln(args ...interface{}) { |
| baseLogger.sourced().Infoln(args...) |
| } |
| |
| // Infof logs a message at level Info on the standard logger. |
| func Infof(format string, args ...interface{}) { |
| baseLogger.sourced().Infof(format, args...) |
| } |
| |
| // Warn logs a message at level Warn on the standard logger. |
| func Warn(args ...interface{}) { |
| baseLogger.sourced().Warn(args...) |
| } |
| |
| // Warnln logs a message at level Warn on the standard logger. |
| func Warnln(args ...interface{}) { |
| baseLogger.sourced().Warnln(args...) |
| } |
| |
| // Warnf logs a message at level Warn on the standard logger. |
| func Warnf(format string, args ...interface{}) { |
| baseLogger.sourced().Warnf(format, args...) |
| } |
| |
| // Error logs a message at level Error on the standard logger. |
| func Error(args ...interface{}) { |
| baseLogger.sourced().Error(args...) |
| } |
| |
| // Errorln logs a message at level Error on the standard logger. |
| func Errorln(args ...interface{}) { |
| baseLogger.sourced().Errorln(args...) |
| } |
| |
| // Errorf logs a message at level Error on the standard logger. |
| func Errorf(format string, args ...interface{}) { |
| baseLogger.sourced().Errorf(format, args...) |
| } |
| |
| // Fatal logs a message at level Fatal on the standard logger. |
| func Fatal(args ...interface{}) { |
| baseLogger.sourced().Fatal(args...) |
| } |
| |
| // Fatalln logs a message at level Fatal on the standard logger. |
| func Fatalln(args ...interface{}) { |
| baseLogger.sourced().Fatalln(args...) |
| } |
| |
| // Fatalf logs a message at level Fatal on the standard logger. |
| func Fatalf(format string, args ...interface{}) { |
| baseLogger.sourced().Fatalf(format, args...) |
| } |
| |
| // AddHook adds hook to Prometheus' original logger. |
| func AddHook(hook logrus.Hook) { |
| origLogger.Hooks.Add(hook) |
| } |
| |
| type errorLogWriter struct{} |
| |
| func (errorLogWriter) Write(b []byte) (int, error) { |
| baseLogger.sourced().Error(string(b)) |
| return len(b), nil |
| } |
| |
| // NewErrorLogger returns a log.Logger that is meant to be used |
| // in the ErrorLog field of an http.Server to log HTTP server errors. |
| func NewErrorLogger() *log.Logger { |
| return log.New(&errorLogWriter{}, "", 0) |
| } |