Add in process log rotation (#5778)

This commit is contained in:
javicrespo
2019-05-03 19:25:28 +02:00
committed by Daniel Nelson
parent bae7f59bbf
commit bcf7516a23
7 changed files with 428 additions and 32 deletions

View File

@@ -1,12 +1,15 @@
package logger
import (
"errors"
"io"
"log"
"os"
"regexp"
"time"
"github.com/influxdata/telegraf/internal"
"github.com/influxdata/telegraf/internal/rotate"
"github.com/influxdata/wlog"
)
@@ -15,12 +18,32 @@ var prefixRegex = regexp.MustCompile("^[DIWE]!")
// newTelegrafWriter returns a logging-wrapped writer.
func newTelegrafWriter(w io.Writer) io.Writer {
return &telegrafLog{
writer: wlog.NewWriter(w),
writer: wlog.NewWriter(w),
internalWriter: w,
}
}
// 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
// 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 internal.Duration
// will rotate when current file size exceeds this parameter.
RotationMaxSize internal.Size
// maximum rotated files to keep (older ones will be deleted)
RotationMaxArchives int
}
type telegrafLog struct {
writer io.Writer
writer io.Writer
internalWriter io.Writer
}
func (t *telegrafLog) Write(b []byte) (n int, err error) {
@@ -33,31 +56,40 @@ func (t *telegrafLog) Write(b []byte) (n int, err error) {
return t.writer.Write(line)
}
func (t *telegrafLog) Close() error {
closer, isCloser := t.internalWriter.(io.Closer)
if !isCloser {
return errors.New("the underlying writer cannot be closed")
}
return closer.Close()
}
// SetupLogging configures the logging output.
// debug will set the log level to DEBUG
// quiet will set the log level to ERROR
// logfile 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.
func SetupLogging(debug, quiet bool, logfile string) {
func SetupLogging(config LogConfig) {
newLogWriter(config)
}
func newLogWriter(config LogConfig) io.Writer {
log.SetFlags(0)
if debug {
if config.Debug {
wlog.SetLevel(wlog.DEBUG)
}
if quiet {
if config.Quiet {
wlog.SetLevel(wlog.ERROR)
}
var oFile *os.File
if logfile != "" {
var writer io.Writer
if config.Logfile != "" {
var err error
if oFile, err = os.OpenFile(logfile, os.O_CREATE|os.O_APPEND|os.O_WRONLY, os.ModeAppend|0644); err != nil {
log.Printf("E! Unable to open %s (%s), using stderr", logfile, err)
oFile = os.Stderr
if writer, err = rotate.NewFileWriter(config.Logfile, config.RotationInterval.Duration, config.RotationMaxSize.Size, config.RotationMaxArchives); err != nil {
log.Printf("E! Unable to open %s (%s), using stderr", config.Logfile, err)
writer = os.Stderr
}
} else {
oFile = os.Stderr
writer = os.Stderr
}
log.SetOutput(newTelegrafWriter(oFile))
telegrafLog := newTelegrafWriter(writer)
log.SetOutput(telegrafLog)
return telegrafLog
}

View File

@@ -2,12 +2,16 @@ package logger
import (
"bytes"
"io"
"io/ioutil"
"log"
"os"
"path/filepath"
"testing"
"github.com/influxdata/telegraf/internal"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
func TestWriteLogToFile(t *testing.T) {
@@ -15,7 +19,8 @@ func TestWriteLogToFile(t *testing.T) {
assert.NoError(t, err)
defer func() { os.Remove(tmpfile.Name()) }()
SetupLogging(false, false, tmpfile.Name())
config := createBasicLogConfig(tmpfile.Name())
SetupLogging(config)
log.Printf("I! TEST")
log.Printf("D! TEST") // <- should be ignored
@@ -28,8 +33,9 @@ func TestDebugWriteLogToFile(t *testing.T) {
tmpfile, err := ioutil.TempFile("", "")
assert.NoError(t, err)
defer func() { os.Remove(tmpfile.Name()) }()
SetupLogging(true, false, tmpfile.Name())
config := createBasicLogConfig(tmpfile.Name())
config.Debug = true
SetupLogging(config)
log.Printf("D! TEST")
f, err := ioutil.ReadFile(tmpfile.Name())
@@ -41,8 +47,9 @@ func TestErrorWriteLogToFile(t *testing.T) {
tmpfile, err := ioutil.TempFile("", "")
assert.NoError(t, err)
defer func() { os.Remove(tmpfile.Name()) }()
SetupLogging(false, true, tmpfile.Name())
config := createBasicLogConfig(tmpfile.Name())
config.Quiet = true
SetupLogging(config)
log.Printf("E! TEST")
log.Printf("I! TEST") // <- should be ignored
@@ -55,8 +62,9 @@ func TestAddDefaultLogLevel(t *testing.T) {
tmpfile, err := ioutil.TempFile("", "")
assert.NoError(t, err)
defer func() { os.Remove(tmpfile.Name()) }()
SetupLogging(true, false, tmpfile.Name())
config := createBasicLogConfig(tmpfile.Name())
config.Debug = true
SetupLogging(config)
log.Printf("TEST")
f, err := ioutil.ReadFile(tmpfile.Name())
@@ -68,8 +76,9 @@ func TestWriteToTruncatedFile(t *testing.T) {
tmpfile, err := ioutil.TempFile("", "")
assert.NoError(t, err)
defer func() { os.Remove(tmpfile.Name()) }()
SetupLogging(true, false, tmpfile.Name())
config := createBasicLogConfig(tmpfile.Name())
config.Debug = true
SetupLogging(config)
log.Printf("TEST")
f, err := ioutil.ReadFile(tmpfile.Name())
@@ -87,6 +96,23 @@ func TestWriteToTruncatedFile(t *testing.T) {
assert.Equal(t, f[19:], []byte("Z I! SHOULD BE FIRST\n"))
}
func TestWriteToFileInRotation(t *testing.T) {
tempDir, err := ioutil.TempDir("", "LogRotation")
require.NoError(t, err)
config := createBasicLogConfig(filepath.Join(tempDir, "test.log"))
config.RotationMaxSize = internal.Size{Size: int64(30)}
writer := newLogWriter(config)
// Close the writer here, otherwise the temp folder cannot be deleted because the current log file is in use.
closer, isCloser := writer.(io.Closer)
assert.True(t, isCloser)
defer func() { closer.Close(); os.RemoveAll(tempDir) }()
log.Printf("I! TEST 1") // Writes 31 bytes, will rotate
log.Printf("I! TEST") // Writes 29 byes, no rotation expected
files, _ := ioutil.ReadDir(tempDir)
assert.Equal(t, 2, len(files))
}
func BenchmarkTelegrafLogWrite(b *testing.B) {
var msg = []byte("test")
var buf bytes.Buffer
@@ -96,3 +122,10 @@ func BenchmarkTelegrafLogWrite(b *testing.B) {
w.Write(msg)
}
}
func createBasicLogConfig(filename string) LogConfig {
return LogConfig{
Logfile: filename,
RotationMaxArchives: -1,
}
}