open-consul/logging/logger.go
Matt Keeler 2c7844d220
Implement Client Agent Auto Config
There are a couple of things in here.

First, just like auto encrypt, any Cluster.AutoConfig RPC will implicitly use the less secure RPC mechanism.

This drastically modifies how the Consul Agent starts up and moves most of the responsibilities (other than signal handling) from the cli command and into the Agent.
2020-06-17 16:49:46 -04:00

140 lines
3.8 KiB
Go

package logging
import (
"fmt"
"io"
"path/filepath"
"time"
"github.com/hashicorp/go-hclog"
gsyslog "github.com/hashicorp/go-syslog"
)
// Config is used to set up logging.
type Config struct {
// LogLevel is the minimum level to be logged.
LogLevel string
// LogJSON controls outputing logs in a JSON format.
LogJSON bool
// Name is the name the returned logger will use to prefix log lines.
Name string
// EnableSyslog controls forwarding to syslog.
EnableSyslog bool
// SyslogFacility is the destination for syslog forwarding.
SyslogFacility string
//LogFilePath is the path to write the logs to the user specified file.
LogFilePath string
//LogRotateDuration is the user specified time to rotate logs
LogRotateDuration time.Duration
//LogRotateBytes is the user specified byte limit to rotate logs
LogRotateBytes int
//LogRotateMaxFiles is the maximum number of past archived log files to keep
LogRotateMaxFiles int
}
const (
// defaultRotateDuration is the default time taken by the agent to rotate logs
defaultRotateDuration = 24 * time.Hour
)
var (
logRotateDuration time.Duration
logRotateBytes int
)
type LogSetupErrorFn func(string)
// Setup is used to perform setup of several logging objects:
//
// * A hclog.Logger is used to perform filtering by log level and write to io.Writer.
// * A GatedWriter is used to buffer logs until startup UI operations are
// complete. After this is flushed then logs flow directly to output
// destinations.
// * An io.Writer is provided as the sink for all logs to flow to.
//
// The provided ui object will get any log messages related to setting up
// logging itself, and will also be hooked up to the gated logger. The final bool
// parameter indicates if logging was set up successfully.
func Setup(config *Config, writers []io.Writer) (hclog.InterceptLogger, io.Writer, error) {
if !ValidateLogLevel(config.LogLevel) {
return nil, nil, fmt.Errorf("Invalid log level: %s. Valid log levels are: %v",
config.LogLevel,
allowedLogLevels)
}
// Set up syslog if it's enabled.
var syslog io.Writer
if config.EnableSyslog {
retries := 12
delay := 5 * time.Second
for i := 0; i <= retries; i++ {
l, err := gsyslog.NewLogger(gsyslog.LOG_NOTICE, config.SyslogFacility, "consul")
if err == nil {
syslog = &SyslogWrapper{l}
break
}
if i == retries {
timeout := time.Duration(retries) * delay
return nil, nil, fmt.Errorf("Syslog setup did not succeed within timeout (%s).", timeout.String())
}
time.Sleep(delay)
}
}
if syslog != nil {
writers = append(writers, syslog)
}
// Create a file logger if the user has specified the path to the log file
if config.LogFilePath != "" {
dir, fileName := filepath.Split(config.LogFilePath)
// If a path is provided but has no fileName a default is provided.
if fileName == "" {
fileName = "consul.log"
}
// Try to enter the user specified log rotation duration first
if config.LogRotateDuration != 0 {
logRotateDuration = config.LogRotateDuration
} else {
// Default to 24 hrs if no rotation period is specified
logRotateDuration = defaultRotateDuration
}
// User specified byte limit for log rotation if one is provided
if config.LogRotateBytes != 0 {
logRotateBytes = config.LogRotateBytes
}
logFile := &LogFile{
fileName: fileName,
logPath: dir,
duration: logRotateDuration,
MaxBytes: logRotateBytes,
MaxFiles: config.LogRotateMaxFiles,
}
if err := logFile.openNew(); err != nil {
return nil, nil, fmt.Errorf("Failed to setup logging: %w", err)
}
writers = append(writers, logFile)
}
logOutput := io.MultiWriter(writers...)
logger := hclog.NewInterceptLogger(&hclog.LoggerOptions{
Level: LevelFromString(config.LogLevel),
Name: config.Name,
Output: logOutput,
JSONFormat: config.LogJSON,
})
return logger, logOutput, nil
}