// 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 ( "flag" "fmt" "io" "io/ioutil" "log" "net/url" "os" "runtime" "strconv" "strings" "github.com/Sirupsen/logrus" ) type levelFlag string // String implements flag.Value. func (f levelFlag) String() string { return fmt.Sprintf("%q", string(f)) } // Set implements flag.Value. func (f levelFlag) Set(level string) error { l, err := logrus.ParseLevel(level) if err != nil { return err } origLogger.Level = l return nil } // setSyslogFormatter is nil if the target architecture does not support syslog. var setSyslogFormatter func(string, string) error // setEventlogFormatter is nil if the target OS does not support Eventlog (i.e., is not Windows). var setEventlogFormatter func(string, bool) error func setJSONFormatter() { origLogger.Formatter = &logrus.JSONFormatter{} } type logFormatFlag url.URL // String implements flag.Value. func (f logFormatFlag) String() string { u := url.URL(f) return fmt.Sprintf("%q", u.String()) } // Set implements flag.Value. func (f logFormatFlag) Set(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(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(name, debugAsInfo) case "stdout": origLogger.Out = os.Stdout case "stderr": origLogger.Out = os.Stderr default: return fmt.Errorf("unsupported logger %q", u.Opaque) } return nil } func init() { AddFlags(flag.CommandLine) } // AddFlags adds the flags used by this package to the given FlagSet. That's // useful if working with a custom FlagSet. The init function of this package // adds the flags to flag.CommandLine anyway. Thus, it's usually enough to call // flag.Parse() to make the logging flags take effect. func AddFlags(fs *flag.FlagSet) { fs.Var( levelFlag(origLogger.Level.String()), "log.level", "Only log messages with the given severity or above. Valid levels: [debug, info, warn, error, fatal]", ) fs.Var( logFormatFlag(url.URL{Scheme: "logger", Opaque: "stderr"}), "log.format", `Set the log target and format. Example: "logger:syslog?appname=bob&local=7" or "logger:stdout?json=true"`, ) } // 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 } 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...) } // 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...) } 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) }