368 lines
9.8 KiB
Go
368 lines
9.8 KiB
Go
|
// 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 implements logging via logrus.
|
||
|
// Implementation forked from github.com/prometheus/common
|
||
|
|
||
|
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)
|
||
|
}
|