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
14package log
15
16import (
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.
32var setSyslogFormatter func(logger, string, string) error
33
34// setEventlogFormatter is nil if the target OS does not support Eventlog (i.e., is not Windows).
35var setEventlogFormatter func(logger, string, bool) error
36
37func setJSONFormatter() {
38	origLogger.Formatter = &logrus.JSONFormatter{}
39}
40
41type loggerSettings struct {
42	level  string
43	format string
44}
45
46func (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)
57func 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.
70type 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
97type logger struct {
98	entry *logrus.Entry
99}
100
101func (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.
106func (l logger) Debug(args ...interface{}) {
107	l.sourced().Debug(args...)
108}
109
110// Debug logs a message at level Debug on the standard logger.
111func (l logger) Debugln(args ...interface{}) {
112	l.sourced().Debugln(args...)
113}
114
115// Debugf logs a message at level Debug on the standard logger.
116func (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.
121func (l logger) Info(args ...interface{}) {
122	l.sourced().Info(args...)
123}
124
125// Info logs a message at level Info on the standard logger.
126func (l logger) Infoln(args ...interface{}) {
127	l.sourced().Infoln(args...)
128}
129
130// Infof logs a message at level Info on the standard logger.
131func (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.
136func (l logger) Warn(args ...interface{}) {
137	l.sourced().Warn(args...)
138}
139
140// Warn logs a message at level Warn on the standard logger.
141func (l logger) Warnln(args ...interface{}) {
142	l.sourced().Warnln(args...)
143}
144
145// Warnf logs a message at level Warn on the standard logger.
146func (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.
151func (l logger) Error(args ...interface{}) {
152	l.sourced().Error(args...)
153}
154
155// Error logs a message at level Error on the standard logger.
156func (l logger) Errorln(args ...interface{}) {
157	l.sourced().Errorln(args...)
158}
159
160// Errorf logs a message at level Error on the standard logger.
161func (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.
166func (l logger) Fatal(args ...interface{}) {
167	l.sourced().Fatal(args...)
168}
169
170// Fatal logs a message at level Fatal on the standard logger.
171func (l logger) Fatalln(args ...interface{}) {
172	l.sourced().Fatalln(args...)
173}
174
175// Fatalf logs a message at level Fatal on the standard logger.
176func (l logger) Fatalf(format string, args ...interface{}) {
177	l.sourced().Fatalf(format, args...)
178}
179
180func (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
190func (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.
234func (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
246var origLogger = logrus.New()
247var baseLogger = logger{entry: logrus.NewEntry(origLogger)}
248
249// Base returns the default Logger logging to
250func Base() Logger {
251	return baseLogger
252}
253
254// NewLogger returns a new Logger logging to out.
255func 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.
262func 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.
269func 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.
274func Debug(args ...interface{}) {
275	baseLogger.sourced().Debug(args...)
276}
277
278// Debugln logs a message at level Debug on the standard logger.
279func Debugln(args ...interface{}) {
280	baseLogger.sourced().Debugln(args...)
281}
282
283// Debugf logs a message at level Debug on the standard logger.
284func 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.
289func Info(args ...interface{}) {
290	baseLogger.sourced().Info(args...)
291}
292
293// Infoln logs a message at level Info on the standard logger.
294func Infoln(args ...interface{}) {
295	baseLogger.sourced().Infoln(args...)
296}
297
298// Infof logs a message at level Info on the standard logger.
299func 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.
304func Warn(args ...interface{}) {
305	baseLogger.sourced().Warn(args...)
306}
307
308// Warnln logs a message at level Warn on the standard logger.
309func Warnln(args ...interface{}) {
310	baseLogger.sourced().Warnln(args...)
311}
312
313// Warnf logs a message at level Warn on the standard logger.
314func 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.
319func Error(args ...interface{}) {
320	baseLogger.sourced().Error(args...)
321}
322
323// Errorln logs a message at level Error on the standard logger.
324func Errorln(args ...interface{}) {
325	baseLogger.sourced().Errorln(args...)
326}
327
328// Errorf logs a message at level Error on the standard logger.
329func 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.
334func Fatal(args ...interface{}) {
335	baseLogger.sourced().Fatal(args...)
336}
337
338// Fatalln logs a message at level Fatal on the standard logger.
339func Fatalln(args ...interface{}) {
340	baseLogger.sourced().Fatalln(args...)
341}
342
343// Fatalf logs a message at level Fatal on the standard logger.
344func Fatalf(format string, args ...interface{}) {
345	baseLogger.sourced().Fatalf(format, args...)
346}
347
348// AddHook adds hook to Prometheus' original logger.
349func AddHook(hook logrus.Hook) {
350	origLogger.Hooks.Add(hook)
351}
352
353type errorLogWriter struct{}
354
355func (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.
362func NewErrorLogger() *log.Logger {
363	return log.New(&errorLogWriter{}, "", 0)
364}
365