log.go
  1  // Copyright 2015 The Prometheus Authors
  2  // Licensed under the Apache License, Version 2.0 (the "License");
  3  // you may not use this file except in compliance with the License.
  4  // You may obtain a copy of the License at
  5  //
  6  // http://www.apache.org/licenses/LICENSE-2.0
  7  //
  8  // Unless required by applicable law or agreed to in writing, software
  9  // distributed under the License is distributed on an "AS IS" BASIS,
 10  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 11  // See the License for the specific language governing permissions and
 12  // limitations under the License.
 13  
 14  package log
 15  
 16  import (
 17  	"fmt"
 18  	"io"
 19  	"io/ioutil"
 20  	"log"
 21  	"net/url"
 22  	"os"
 23  	"runtime"
 24  	"strconv"
 25  	"strings"
 26  
 27  	"github.com/sirupsen/logrus"
 28  	"gopkg.in/alecthomas/kingpin.v2"
 29  )
 30  
 31  // setSyslogFormatter is nil if the target architecture does not support syslog.
 32  var setSyslogFormatter func(logger, string, string) error
 33  
 34  // setEventlogFormatter is nil if the target OS does not support Eventlog (i.e., is not Windows).
 35  var setEventlogFormatter func(logger, string, bool) error
 36  
 37  func setJSONFormatter() {
 38  	origLogger.Formatter = &logrus.JSONFormatter{}
 39  }
 40  
 41  type loggerSettings struct {
 42  	level  string
 43  	format string
 44  }
 45  
 46  func (s *loggerSettings) apply(ctx *kingpin.ParseContext) error {
 47  	err := baseLogger.SetLevel(s.level)
 48  	if err != nil {
 49  		return err
 50  	}
 51  	err = baseLogger.SetFormat(s.format)
 52  	return err
 53  }
 54  
 55  // AddFlags adds the flags used by this package to the Kingpin application.
 56  // To use the default Kingpin application, call AddFlags(kingpin.CommandLine)
 57  func AddFlags(a *kingpin.Application) {
 58  	s := loggerSettings{}
 59  	a.Flag("log.level", "Only log messages with the given severity or above. Valid levels: [debug, info, warn, error, fatal]").
 60  		Default(origLogger.Level.String()).
 61  		StringVar(&s.level)
 62  	defaultFormat := url.URL{Scheme: "logger", Opaque: "stderr"}
 63  	a.Flag("log.format", `Set the log target and format. Example: "logger:syslog?appname=bob&local=7" or "logger:stdout?json=true"`).
 64  		Default(defaultFormat.String()).
 65  		StringVar(&s.format)
 66  	a.Action(s.apply)
 67  }
 68  
 69  // Logger is the interface for loggers used in the Prometheus components.
 70  type Logger interface {
 71  	Debug(...interface{})
 72  	Debugln(...interface{})
 73  	Debugf(string, ...interface{})
 74  
 75  	Info(...interface{})
 76  	Infoln(...interface{})
 77  	Infof(string, ...interface{})
 78  
 79  	Warn(...interface{})
 80  	Warnln(...interface{})
 81  	Warnf(string, ...interface{})
 82  
 83  	Error(...interface{})
 84  	Errorln(...interface{})
 85  	Errorf(string, ...interface{})
 86  
 87  	Fatal(...interface{})
 88  	Fatalln(...interface{})
 89  	Fatalf(string, ...interface{})
 90  
 91  	With(key string, value interface{}) Logger
 92  
 93  	SetFormat(string) error
 94  	SetLevel(string) error
 95  }
 96  
 97  type logger struct {
 98  	entry *logrus.Entry
 99  }
100  
101  func (l logger) With(key string, value interface{}) Logger {
102  	return logger{l.entry.WithField(key, value)}
103  }
104  
105  // Debug logs a message at level Debug on the standard logger.
106  func (l logger) Debug(args ...interface{}) {
107  	l.sourced().Debug(args...)
108  }
109  
110  // Debug logs a message at level Debug on the standard logger.
111  func (l logger) Debugln(args ...interface{}) {
112  	l.sourced().Debugln(args...)
113  }
114  
115  // Debugf logs a message at level Debug on the standard logger.
116  func (l logger) Debugf(format string, args ...interface{}) {
117  	l.sourced().Debugf(format, args...)
118  }
119  
120  // Info logs a message at level Info on the standard logger.
121  func (l logger) Info(args ...interface{}) {
122  	l.sourced().Info(args...)
123  }
124  
125  // Info logs a message at level Info on the standard logger.
126  func (l logger) Infoln(args ...interface{}) {
127  	l.sourced().Infoln(args...)
128  }
129  
130  // Infof logs a message at level Info on the standard logger.
131  func (l logger) Infof(format string, args ...interface{}) {
132  	l.sourced().Infof(format, args...)
133  }
134  
135  // Warn logs a message at level Warn on the standard logger.
136  func (l logger) Warn(args ...interface{}) {
137  	l.sourced().Warn(args...)
138  }
139  
140  // Warn logs a message at level Warn on the standard logger.
141  func (l logger) Warnln(args ...interface{}) {
142  	l.sourced().Warnln(args...)
143  }
144  
145  // Warnf logs a message at level Warn on the standard logger.
146  func (l logger) Warnf(format string, args ...interface{}) {
147  	l.sourced().Warnf(format, args...)
148  }
149  
150  // Error logs a message at level Error on the standard logger.
151  func (l logger) Error(args ...interface{}) {
152  	l.sourced().Error(args...)
153  }
154  
155  // Error logs a message at level Error on the standard logger.
156  func (l logger) Errorln(args ...interface{}) {
157  	l.sourced().Errorln(args...)
158  }
159  
160  // Errorf logs a message at level Error on the standard logger.
161  func (l logger) Errorf(format string, args ...interface{}) {
162  	l.sourced().Errorf(format, args...)
163  }
164  
165  // Fatal logs a message at level Fatal on the standard logger.
166  func (l logger) Fatal(args ...interface{}) {
167  	l.sourced().Fatal(args...)
168  }
169  
170  // Fatal logs a message at level Fatal on the standard logger.
171  func (l logger) Fatalln(args ...interface{}) {
172  	l.sourced().Fatalln(args...)
173  }
174  
175  // Fatalf logs a message at level Fatal on the standard logger.
176  func (l logger) Fatalf(format string, args ...interface{}) {
177  	l.sourced().Fatalf(format, args...)
178  }
179  
180  func (l logger) SetLevel(level string) error {
181  	lvl, err := logrus.ParseLevel(level)
182  	if err != nil {
183  		return err
184  	}
185  
186  	l.entry.Logger.Level = lvl
187  	return nil
188  }
189  
190  func (l logger) SetFormat(format string) error {
191  	u, err := url.Parse(format)
192  	if err != nil {
193  		return err
194  	}
195  	if u.Scheme != "logger" {
196  		return fmt.Errorf("invalid scheme %s", u.Scheme)
197  	}
198  	jsonq := u.Query().Get("json")
199  	if jsonq == "true" {
200  		setJSONFormatter()
201  	}
202  
203  	switch u.Opaque {
204  	case "syslog":
205  		if setSyslogFormatter == nil {
206  			return fmt.Errorf("system does not support syslog")
207  		}
208  		appname := u.Query().Get("appname")
209  		facility := u.Query().Get("local")
210  		return setSyslogFormatter(l, appname, facility)
211  	case "eventlog":
212  		if setEventlogFormatter == nil {
213  			return fmt.Errorf("system does not support eventlog")
214  		}
215  		name := u.Query().Get("name")
216  		debugAsInfo := false
217  		debugAsInfoRaw := u.Query().Get("debugAsInfo")
218  		if parsedDebugAsInfo, err := strconv.ParseBool(debugAsInfoRaw); err == nil {
219  			debugAsInfo = parsedDebugAsInfo
220  		}
221  		return setEventlogFormatter(l, name, debugAsInfo)
222  	case "stdout":
223  		l.entry.Logger.Out = os.Stdout
224  	case "stderr":
225  		l.entry.Logger.Out = os.Stderr
226  	default:
227  		return fmt.Errorf("unsupported logger %q", u.Opaque)
228  	}
229  	return nil
230  }
231  
232  // sourced adds a source field to the logger that contains
233  // the file name and line where the logging happened.
234  func (l logger) sourced() *logrus.Entry {
235  	_, file, line, ok := runtime.Caller(2)
236  	if !ok {
237  		file = "<???>"
238  		line = 1
239  	} else {
240  		slash := strings.LastIndex(file, "/")
241  		file = file[slash+1:]
242  	}
243  	return l.entry.WithField("source", fmt.Sprintf("%s:%d", file, line))
244  }
245  
246  var origLogger = logrus.New()
247  var baseLogger = logger{entry: logrus.NewEntry(origLogger)}
248  
249  // Base returns the default Logger logging to
250  func Base() Logger {
251  	return baseLogger
252  }
253  
254  // NewLogger returns a new Logger logging to out.
255  func NewLogger(w io.Writer) Logger {
256  	l := logrus.New()
257  	l.Out = w
258  	return logger{entry: logrus.NewEntry(l)}
259  }
260  
261  // NewNopLogger returns a logger that discards all log messages.
262  func NewNopLogger() Logger {
263  	l := logrus.New()
264  	l.Out = ioutil.Discard
265  	return logger{entry: logrus.NewEntry(l)}
266  }
267  
268  // With adds a field to the logger.
269  func With(key string, value interface{}) Logger {
270  	return baseLogger.With(key, value)
271  }
272  
273  // Debug logs a message at level Debug on the standard logger.
274  func Debug(args ...interface{}) {
275  	baseLogger.sourced().Debug(args...)
276  }
277  
278  // Debugln logs a message at level Debug on the standard logger.
279  func Debugln(args ...interface{}) {
280  	baseLogger.sourced().Debugln(args...)
281  }
282  
283  // Debugf logs a message at level Debug on the standard logger.
284  func Debugf(format string, args ...interface{}) {
285  	baseLogger.sourced().Debugf(format, args...)
286  }
287  
288  // Info logs a message at level Info on the standard logger.
289  func Info(args ...interface{}) {
290  	baseLogger.sourced().Info(args...)
291  }
292  
293  // Infoln logs a message at level Info on the standard logger.
294  func Infoln(args ...interface{}) {
295  	baseLogger.sourced().Infoln(args...)
296  }
297  
298  // Infof logs a message at level Info on the standard logger.
299  func Infof(format string, args ...interface{}) {
300  	baseLogger.sourced().Infof(format, args...)
301  }
302  
303  // Warn logs a message at level Warn on the standard logger.
304  func Warn(args ...interface{}) {
305  	baseLogger.sourced().Warn(args...)
306  }
307  
308  // Warnln logs a message at level Warn on the standard logger.
309  func Warnln(args ...interface{}) {
310  	baseLogger.sourced().Warnln(args...)
311  }
312  
313  // Warnf logs a message at level Warn on the standard logger.
314  func Warnf(format string, args ...interface{}) {
315  	baseLogger.sourced().Warnf(format, args...)
316  }
317  
318  // Error logs a message at level Error on the standard logger.
319  func Error(args ...interface{}) {
320  	baseLogger.sourced().Error(args...)
321  }
322  
323  // Errorln logs a message at level Error on the standard logger.
324  func Errorln(args ...interface{}) {
325  	baseLogger.sourced().Errorln(args...)
326  }
327  
328  // Errorf logs a message at level Error on the standard logger.
329  func Errorf(format string, args ...interface{}) {
330  	baseLogger.sourced().Errorf(format, args...)
331  }
332  
333  // Fatal logs a message at level Fatal on the standard logger.
334  func Fatal(args ...interface{}) {
335  	baseLogger.sourced().Fatal(args...)
336  }
337  
338  // Fatalln logs a message at level Fatal on the standard logger.
339  func Fatalln(args ...interface{}) {
340  	baseLogger.sourced().Fatalln(args...)
341  }
342  
343  // Fatalf logs a message at level Fatal on the standard logger.
344  func Fatalf(format string, args ...interface{}) {
345  	baseLogger.sourced().Fatalf(format, args...)
346  }
347  
348  // AddHook adds hook to Prometheus' original logger.
349  func AddHook(hook logrus.Hook) {
350  	origLogger.Hooks.Add(hook)
351  }
352  
353  type errorLogWriter struct{}
354  
355  func (errorLogWriter) Write(b []byte) (int, error) {
356  	baseLogger.sourced().Error(string(b))
357  	return len(b), nil
358  }
359  
360  // NewErrorLogger returns a log.Logger that is meant to be used
361  // in the ErrorLog field of an http.Server to log HTTP server errors.
362  func NewErrorLogger() *log.Logger {
363  	return log.New(&errorLogWriter{}, "", 0)
364  }