Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

chore(logging): Implement early logging #15629

Merged
merged 11 commits into from
Jul 26, 2024
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 2 additions & 3 deletions agent/accumulator_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ package agent
import (
"bytes"
"errors"
"log"
"os"
"testing"
"time"
Expand Down Expand Up @@ -49,8 +48,8 @@ func TestAddFields(t *testing.T) {

func TestAccAddError(t *testing.T) {
errBuf := bytes.NewBuffer(nil)
log.SetOutput(errBuf)
defer log.SetOutput(os.Stderr)
logger.RedirectLogging(errBuf)
defer logger.RedirectLogging(os.Stderr)

metrics := make(chan telegraf.Metric, 10)
defer close(metrics)
Expand Down
5 changes: 0 additions & 5 deletions cmd/telegraf/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -137,11 +137,6 @@ func runApp(args []string, outputBuffer io.Writer, pprof Server, c TelegrafConfi
return fmt.Errorf("unknown command %q", cCtx.Args().First())
}

err := logger.SetupLogging(&logger.Config{})
if err != nil {
return err
}

// Deprecated: Use execd instead
// Load external plugins, if requested.
if cCtx.String("plugin-directory") != "" {
Expand Down
4 changes: 2 additions & 2 deletions config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -458,11 +458,11 @@ func (c *Config) LoadConfig(path string) error {

data, _, err := LoadConfigFileWithRetries(path, c.Agent.ConfigURLRetryAttempts)
if err != nil {
return fmt.Errorf("error loading config file %s: %w", path, err)
return fmt.Errorf("loading config file %s failed: %w", path, err)
}

if err = c.LoadConfigData(data); err != nil {
return fmt.Errorf("error loading config file %s: %w", path, err)
return fmt.Errorf("loading config file %s failed: %w", path, err)
}

return nil
Expand Down
6 changes: 3 additions & 3 deletions config/config_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -497,7 +497,7 @@ func TestConfig_BadOrdering(t *testing.T) {
require.Error(t, err, "bad ordering")
require.Equal(
t,
"error loading config file ./testdata/non_slice_slice.toml: error parsing http array, line 4: cannot unmarshal TOML array into string (need slice)",
"loading config file ./testdata/non_slice_slice.toml failed: error parsing http array, line 4: cannot unmarshal TOML array into string (need slice)",
err.Error(),
)
}
Expand Down Expand Up @@ -541,11 +541,11 @@ func TestConfig_URLLikeFileName(t *testing.T) {
// The error file not found error message is different on Windows
require.Equal(
t,
"error loading config file http:##www.example.com.conf: open http:##www.example.com.conf: The system cannot find the file specified.",
"loading config file http:##www.example.com.conf failed: open http:##www.example.com.conf: The system cannot find the file specified.",
err.Error(),
)
} else {
require.Equal(t, "error loading config file http:##www.example.com.conf: open http:##www.example.com.conf: no such file or directory", err.Error())
require.Equal(t, "loading config file http:##www.example.com.conf failed: open http:##www.example.com.conf: no such file or directory", err.Error())
}
}

Expand Down
2 changes: 1 addition & 1 deletion config/internal_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -383,7 +383,7 @@ func TestURLRetries3Fails(t *testing.T) {
}))
defer ts.Close()

expected := fmt.Sprintf("error loading config file %s: failed to fetch HTTP config: 404 Not Found", ts.URL)
expected := fmt.Sprintf("loading config file %s failed: failed to fetch HTTP config: 404 Not Found", ts.URL)

c := NewConfig()
err := c.LoadConfig(ts.URL)
Expand Down
1 change: 0 additions & 1 deletion docs/LICENSE_OF_DEPENDENCIES.md
Original file line number Diff line number Diff line change
Expand Up @@ -212,7 +212,6 @@ following works:
- github.com/influxdata/line-protocol [MIT License](https://github.com/influxdata/line-protocol/blob/v2/LICENSE)
- github.com/influxdata/tail [MIT License](https://github.com/influxdata/tail/blob/master/LICENSE.txt)
- github.com/influxdata/toml [MIT License](https://github.com/influxdata/toml/blob/master/LICENSE)
- github.com/influxdata/wlog [MIT License](https://github.com/influxdata/wlog/blob/master/LICENSE)
- github.com/intel/iaevents [Apache License 2.0](https://github.com/intel/iaevents/blob/main/LICENSE)
- github.com/intel/powertelemetry [Apache License 2.0](https://github.com/intel/powertelemetry/blob/main/LICENSE)
- github.com/jackc/chunkreader [MIT License](https://github.com/jackc/chunkreader/blob/master/LICENSE)
Expand Down
1 change: 0 additions & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,6 @@ require (
github.com/influxdata/line-protocol/v2 v2.2.1
github.com/influxdata/tail v1.0.1-0.20221130111531-19b97bffd978
github.com/influxdata/toml v0.0.0-20190415235208-270119a8ce65
github.com/influxdata/wlog v0.0.0-20160411224016-7c63b0a71ef8
github.com/intel/iaevents v1.1.0
github.com/intel/powertelemetry v1.0.1
github.com/jackc/pgconn v1.14.3
Expand Down
2 changes: 0 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -1621,8 +1621,6 @@ github.com/influxdata/tail v1.0.1-0.20221130111531-19b97bffd978 h1:SaKzm7QUHJcHO
github.com/influxdata/tail v1.0.1-0.20221130111531-19b97bffd978/go.mod h1:VeiWgI3qaGdJWust2fP27a6J+koITo/1c/UhxeOxgaM=
github.com/influxdata/toml v0.0.0-20190415235208-270119a8ce65 h1:vvyMtD5LTJc1W9sQKjDkAWdcg0478CszSdzlHtiAXCY=
github.com/influxdata/toml v0.0.0-20190415235208-270119a8ce65/go.mod h1:zApaNFpP/bTpQItGZNNUMISDMDAnTXu9UqJ4yT3ocz8=
github.com/influxdata/wlog v0.0.0-20160411224016-7c63b0a71ef8 h1:W2IgzRCb0L9VzMujq/QuTaZUKcH8096jWwP519mHN6Q=
github.com/influxdata/wlog v0.0.0-20160411224016-7c63b0a71ef8/go.mod h1:/2NMgWB1DHM1ti/gqhOlg+LJeBVk6FqR5aVGYY0hlwI=
github.com/intel/iaevents v1.1.0 h1:FzxMBfXk/apG2EUXUCfaq3gUQ+q+TgZ1HNMjjUILUGE=
github.com/intel/iaevents v1.1.0/go.mod h1:CyUUzXw0lHRCsmyyF7Pwco9Y7NiTNQUUlcJ7RJAazKs=
github.com/intel/powertelemetry v1.0.1 h1:a35pZbqOnJlEYGEPXM+YKtetu6D6dJD4Jb4GS4Zetxs=
Expand Down
38 changes: 26 additions & 12 deletions logger.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,19 @@ package telegraf
// LogLevel denotes the level for logging
type LogLevel int

const (
// None means nothing is logged
None LogLevel = iota
// Error will log error messages
Error
// Warn will log error messages and warnings
Warn
// Info will log error messages, warnings and information messages
Info
// Debug will log all of the above and debugging messages issued by plugins
Debug
)

func (e LogLevel) String() string {
switch e {
case Error:
Expand All @@ -17,18 +30,19 @@ func (e LogLevel) String() string {
return "NONE"
}

const (
// None means nothing is logged
None LogLevel = iota
// Error will log error messages
Error
// Warn will log error messages and warnings
Warn
// Info will log error messages, warnings and information messages
Info
// Debug will log all of the above and debugging messages issued by plugins
Debug
)
func (e LogLevel) Indicator() string {
switch e {
case Error:
return "E!"
case Warn:
return "W!"
case Info:
return "I!"
case Debug:
return "D!"
}
return "U!"
}

// Logger defines an plugin-related interface for logging.
type Logger interface {
Expand Down
168 changes: 68 additions & 100 deletions logger/default_logger.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package logger

import (
"errors"
"fmt"
"io"
"log"
"os"
Expand All @@ -10,7 +11,6 @@ import (

"github.com/influxdata/telegraf"
"github.com/influxdata/telegraf/internal/rotate"
"github.com/influxdata/wlog"
)

const (
Expand All @@ -19,141 +19,110 @@ const (
)

type defaultLogger struct {
Category string
Name string
Alias string
LogLevel telegraf.LogLevel

prefix string
onError []func()

writer io.Writer
internalWriter io.Writer
timezone *time.Location
}

func (t *defaultLogger) Write(b []byte) (n int, err error) {
var line []byte
timeToPrint := time.Now().In(t.timezone)

if !prefixRegex.Match(b) {
line = append([]byte(timeToPrint.Format(time.RFC3339)+" I! "), b...)
} else {
line = append([]byte(timeToPrint.Format(time.RFC3339)+" "), b...)
}

return t.writer.Write(line)
logger *log.Logger
level telegraf.LogLevel
timezone *time.Location
}

// NewLogger creates a new logger instance
func (t *defaultLogger) New(category, name, alias string) telegraf.Logger {
var prefix string
if category != "" {
prefix = "[" + category
if name != "" {
prefix += "." + name
}
if alias != "" {
prefix += "::" + alias
}
prefix += "] "
func (l *defaultLogger) New(tag string) telegraf.Logger {
prefix := l.prefix
if prefix != "" && tag != "" {
prefix += "." + tag
} else {
prefix = tag
}

return &defaultLogger{
Category: category,
Name: name,
Alias: alias,
LogLevel: t.LogLevel,
prefix: prefix,
writer: t.writer,
internalWriter: t.internalWriter,
timezone: t.timezone,
prefix: prefix,
level: l.level,
logger: l.logger,
timezone: l.timezone,
}
}

func (t *defaultLogger) Close() error {
// avoid closing stderr
if t.internalWriter == os.Stderr {
func (l *defaultLogger) Close() error {
writer := l.logger.Writer()

// Close the writer if possible and avoid closing stderr
if writer == os.Stderr {
return nil
}

closer, isCloser := t.internalWriter.(io.Closer)
if !isCloser {
return errors.New("the underlying writer cannot be closed")
if closer, ok := writer.(io.Closer); ok {
return closer.Close()
}
return closer.Close()

return errors.New("the underlying writer cannot be closed")
}

// OnErr defines a callback that triggers only when errors are about to be written to the log
func (t *defaultLogger) RegisterErrorCallback(f func()) {
t.onError = append(t.onError, f)
// Register a callback triggered when errors are about to be written to the log
func (l *defaultLogger) RegisterErrorCallback(f func()) {
l.onError = append(l.onError, f)
}

func (t *defaultLogger) Level() telegraf.LogLevel {
return t.LogLevel
func (l *defaultLogger) SetOutput(w io.Writer) {
l.logger.SetOutput(w)
}

// Errorf logs an error message, patterned after log.Printf.
func (t *defaultLogger) Errorf(format string, args ...interface{}) {
log.Printf("E! "+t.prefix+format, args...)
for _, f := range t.onError {
f()
}
func (l *defaultLogger) Level() telegraf.LogLevel {
return l.level
}

// Error logging including callbacks
func (l *defaultLogger) Errorf(format string, args ...interface{}) {
l.Error(fmt.Sprintf(format, args...))
}

// Error logs an error message, patterned after log.Print.
func (t *defaultLogger) Error(args ...interface{}) {
for _, f := range t.onError {
func (l *defaultLogger) Error(args ...interface{}) {
l.Print(telegraf.Error, time.Now(), args...)
for _, f := range l.onError {
f()
}
log.Print(append([]interface{}{"E! " + t.prefix}, args...)...)
}

// Debugf logs a debug message, patterned after log.Printf.
func (t *defaultLogger) Debugf(format string, args ...interface{}) {
log.Printf("D! "+t.prefix+" "+format, args...)
// Warning logging
func (l *defaultLogger) Warnf(format string, args ...interface{}) {
l.Warn(fmt.Sprintf(format, args...))
}

// Debug logs a debug message, patterned after log.Print.
func (t *defaultLogger) Debug(args ...interface{}) {
log.Print(append([]interface{}{"D! " + t.prefix}, args...)...)
func (l *defaultLogger) Warn(args ...interface{}) {
l.Print(telegraf.Warn, time.Now(), args...)
}

// Warnf logs a warning message, patterned after log.Printf.
func (t *defaultLogger) Warnf(format string, args ...interface{}) {
log.Printf("W! "+t.prefix+format, args...)
// Info logging
func (l *defaultLogger) Infof(format string, args ...interface{}) {
l.Info(fmt.Sprintf(format, args...))
}

// Warn logs a warning message, patterned after log.Print.
func (t *defaultLogger) Warn(args ...interface{}) {
log.Print(append([]interface{}{"W! " + t.prefix}, args...)...)
func (l *defaultLogger) Info(args ...interface{}) {
l.Print(telegraf.Info, time.Now(), args...)
}

// Infof logs an information message, patterned after log.Printf.
func (t *defaultLogger) Infof(format string, args ...interface{}) {
log.Printf("I! "+t.prefix+format, args...)
// Debug logging, this is suppressed on console
func (l *defaultLogger) Debugf(format string, args ...interface{}) {
l.Debug(fmt.Sprintf(format, args...))
}

// Info logs an information message, patterned after log.Print.
func (t *defaultLogger) Info(args ...interface{}) {
log.Print(append([]interface{}{"I! " + t.prefix}, args...)...)
func (l *defaultLogger) Debug(args ...interface{}) {
l.Print(telegraf.Debug, time.Now(), args...)
}

func createDefaultLogger(cfg *Config) (logger, error) {
log.SetFlags(0)

// Set the log-level
switch cfg.logLevel {
case telegraf.Error:
wlog.SetLevel(wlog.ERROR)
case telegraf.Warn:
wlog.SetLevel(wlog.WARN)
case telegraf.Info:
wlog.SetLevel(wlog.INFO)
case telegraf.Debug:
wlog.SetLevel(wlog.DEBUG)
func (l *defaultLogger) Print(level telegraf.LogLevel, ts time.Time, args ...interface{}) {
// Skip all messages with insufficient log-levels
if level > l.level {
return
}
var prefix string
if l.prefix != "" {
prefix = "[" + l.prefix + "] "
}
msg := append([]interface{}{ts.In(l.timezone).Format(time.RFC3339), " ", level.Indicator(), " ", prefix}, args...)
l.logger.Print(msg...)
}

func createDefaultLogger(cfg *Config) (logger, error) {
// Setup the writer target
var writer io.Writer = os.Stderr
if cfg.LogTarget == "file" && cfg.Logfile != "" {
Expand Down Expand Up @@ -181,12 +150,11 @@ func createDefaultLogger(cfg *Config) (logger, error) {

// Setup the logger
l := &defaultLogger{
writer: wlog.NewWriter(writer),
internalWriter: writer,
timezone: tz,
level: cfg.logLevel,
logger: log.New(writer, "", 0),
timezone: tz,
}

log.SetOutput(l)
return l, nil
}

Expand Down
Loading
Loading