// 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" "net/url" "os" "runtime" "strings" "github.com/Sirupsen/logrus" ) type levelFlag struct{} // String implements flag.Value. func (f levelFlag) String() string { return origLogger.Level.String() } // 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 func setJSONFormatter() { origLogger.Formatter = &logrus.JSONFormatter{} } type logFormatFlag struct{ uri string } // String implements flag.Value. func (f logFormatFlag) String() string { return f.uri } // Set implements flag.Value. func (f logFormatFlag) Set(format string) error { f.uri = format 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 "stdout": origLogger.Out = os.Stdout case "stderr": origLogger.Out = os.Stderr default: return fmt.Errorf("unsupported logger %s", u.Opaque) } return nil } func init() { // In order for these flags to take effect, the user of the package must call // flag.Parse() before logging anything. flag.Var(levelFlag{}, "log.level", "Only log messages with the given severity or above. Valid levels: [debug, info, warn, error, fatal].") flag.Var(logFormatFlag{}, "log.format", "If set use a syslog logger or JSON logging. Example: logger:syslog?appname=bob&local=7 or logger:stdout?json=true. Defaults to stderr.") } 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)} func Base() Logger { return baseLogger } 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...) } // Debug 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...) } // Info 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...) } // Warn 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...) } // Error 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...) } // Fatal 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...) }