telegraf/logger/logger.go

183 lines
4.4 KiB
Go
Raw Normal View History

package logger
import (
2019-05-04 01:25:28 +08:00
"errors"
"io"
"log"
"os"
2017-04-13 01:41:26 +08:00
"regexp"
"strings"
"time"
"github.com/influxdata/telegraf/config"
2019-05-04 01:25:28 +08:00
"github.com/influxdata/telegraf/internal/rotate"
"github.com/influxdata/wlog"
)
2017-04-13 01:41:26 +08:00
var prefixRegex = regexp.MustCompile("^[DIWE]!")
const (
LogTargetFile = "file"
LogTargetStderr = "stderr"
)
2019-05-04 01:25:28 +08:00
// LogConfig contains the log configuration settings
type LogConfig struct {
// will set the log level to DEBUG
Debug bool
//will set the log level to ERROR
Quiet bool
//stderr, stdout, file or eventlog (Windows only)
LogTarget string
2019-05-04 01:25:28 +08:00
// will direct the logging output to a file. Empty string is
// interpreted as stderr. If there is an error opening the file the
// logger will fallback to stderr
Logfile string
// will rotate when current file at the specified time interval
RotationInterval config.Duration
2019-05-04 01:25:28 +08:00
// will rotate when current file size exceeds this parameter.
RotationMaxSize config.Size
2019-05-04 01:25:28 +08:00
// maximum rotated files to keep (older ones will be deleted)
RotationMaxArchives int
// pick a timezone to use when logging. or type 'local' for local time.
LogWithTimezone string
2019-05-04 01:25:28 +08:00
}
type LoggerCreator interface {
CreateLogger(cfg LogConfig) (io.Writer, error)
}
var loggerRegistry map[string]LoggerCreator
func registerLogger(name string, loggerCreator LoggerCreator) {
if loggerRegistry == nil {
loggerRegistry = make(map[string]LoggerCreator)
}
loggerRegistry[name] = loggerCreator
}
type telegrafLog struct {
2019-05-04 01:25:28 +08:00
writer io.Writer
internalWriter io.Writer
timezone *time.Location
}
func (t *telegrafLog) Write(b []byte) (n int, err error) {
2017-04-13 01:41:26 +08:00
var line []byte
timeToPrint := time.Now().In(t.timezone)
2017-04-13 01:41:26 +08:00
if !prefixRegex.Match(b) {
line = append([]byte(timeToPrint.Format(time.RFC3339)+" I! "), b...)
2017-04-13 01:41:26 +08:00
} else {
line = append([]byte(timeToPrint.Format(time.RFC3339)+" "), b...)
2017-04-13 01:41:26 +08:00
}
2017-04-13 01:41:26 +08:00
return t.writer.Write(line)
}
2019-05-04 01:25:28 +08:00
func (t *telegrafLog) Close() error {
2021-03-26 01:57:01 +08:00
stdErrWriter := os.Stderr
// avoid closing stderr
if t.internalWriter == stdErrWriter {
return nil
}
closer, isCloser := t.internalWriter.(io.Closer)
if !isCloser {
return errors.New("the underlying writer cannot be closed")
}
return closer.Close()
}
// newTelegrafWriter returns a logging-wrapped writer.
func newTelegrafWriter(w io.Writer, c LogConfig) (io.Writer, error) {
timezoneName := c.LogWithTimezone
if strings.ToLower(timezoneName) == "local" {
timezoneName = "Local"
}
tz, err := time.LoadLocation(timezoneName)
if err != nil {
return nil, errors.New("error while setting logging timezone: " + err.Error())
}
return &telegrafLog{
writer: wlog.NewWriter(w),
internalWriter: w,
timezone: tz,
}, nil
2019-05-04 01:25:28 +08:00
}
// SetupLogging configures the logging output.
func SetupLogging(cfg LogConfig) {
newLogWriter(cfg)
2019-05-04 01:25:28 +08:00
}
type telegrafLogCreator struct {
}
func (t *telegrafLogCreator) CreateLogger(cfg LogConfig) (io.Writer, error) {
var writer, defaultWriter io.Writer
defaultWriter = os.Stderr
switch cfg.LogTarget {
case LogTargetFile:
if cfg.Logfile != "" {
var err error
if writer, err = rotate.NewFileWriter(cfg.Logfile, time.Duration(cfg.RotationInterval), int64(cfg.RotationMaxSize), cfg.RotationMaxArchives); err != nil {
log.Printf("E! Unable to open %s (%s), using stderr", cfg.Logfile, err)
writer = defaultWriter
}
} else {
writer = defaultWriter
}
case LogTargetStderr, "":
writer = defaultWriter
default:
log.Printf("E! Unsupported logtarget: %s, using stderr", cfg.LogTarget)
writer = defaultWriter
}
return newTelegrafWriter(writer, cfg)
}
// Keep track what is actually set as a log output, because log package doesn't provide a getter.
// It allows closing previous writer if re-set and have possibility to test what is actually set
var actualLogger io.Writer
func newLogWriter(cfg LogConfig) io.Writer {
log.SetFlags(0)
if cfg.Debug {
wlog.SetLevel(wlog.DEBUG)
}
if cfg.Quiet {
wlog.SetLevel(wlog.ERROR)
}
if !cfg.Debug && !cfg.Quiet {
wlog.SetLevel(wlog.INFO)
}
var logWriter io.Writer
if logCreator, ok := loggerRegistry[cfg.LogTarget]; ok {
logWriter, _ = logCreator.CreateLogger(cfg)
}
if logWriter == nil {
logWriter, _ = (&telegrafLogCreator{}).CreateLogger(cfg)
}
if closer, isCloser := actualLogger.(io.Closer); isCloser {
closer.Close()
}
log.SetOutput(logWriter)
actualLogger = logWriter
return logWriter
}
func init() {
tlc := &telegrafLogCreator{}
registerLogger("", tlc)
registerLogger(LogTargetStderr, tlc)
registerLogger(LogTargetFile, tlc)
}