Merge pull request #9056 from influxdata/js-configure-logging

Add logging configuration to the main configuration file
pull/9445/head
Jonathan A. Sternberg 2018-02-14 14:39:42 -05:00 committed by GitHub
commit dd21fa15fd
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 142 additions and 19 deletions

View File

@ -3,7 +3,7 @@ v1.5.0 [unreleased]
### Breaking changes
- The default logging format has been changed. See [#9055](https://github.com/influxdata/influxdb/pull/9055) for details.
- The default logging format has been changed. See [#9055](https://github.com/influxdata/influxdb/pull/9055) and [#9066](https://github.com/influxdata/influxdb/pull/9056) for details.
### Features

2
Godeps
View File

@ -18,7 +18,9 @@ github.com/influxdata/influxql 7c0f432656229c2084ee825680ef39a2228ccdb3
github.com/influxdata/usage-client 6d3895376368aa52a3a81d2a16e90f0f52371967
github.com/influxdata/yamux 1f58ded512de5feabbe30b60c7d33a7a896c5f16
github.com/influxdata/yarpc 036268cdec22b7074cd6d50cc6d7315c667063c7
github.com/jsternberg/zap-logfmt 5ea53862c7fa897f44ae0b3004283308c0b0c9d1
github.com/jwilder/encoding 27894731927e49b0a9023f00312be26733744815
github.com/mattn/go-isatty 6ca4dbf54d38eea1a992b3c722a76a5d1c4cb25c
github.com/matttproud/golang_protobuf_extensions c12348ce28de40eed0136aa2b644d0ee0650e56c
github.com/opentracing/opentracing-go 1361b9cd60be79c4c3a7fa9841b3c132e40066a7
github.com/paulbellamy/ratecounter 5a11f585a31379765c190c033b6ad39956584447

View File

@ -22,6 +22,7 @@
- github.com/influxdata/yamux [MOZILLA PUBLIC LICENSE](https://github.com/influxdata/yamux/blob/master/LICENSE)
- github.com/influxdata/yarpc [MIT LICENSE](https://github.com/influxdata/yarpc/blob/master/LICENSE)
- github.com/jwilder/encoding [MIT LICENSE](https://github.com/jwilder/encoding/blob/master/LICENSE)
- github.com/mattn/go-isatty [MIT LICENSE](https://github.com/mattn/go-isatty/blob/master/LICENSE)
- github.com/matttproud/golang_protobuf_extensions [APACHE LICENSE](https://github.com/matttproud/golang_protobuf_extensions/blob/master/LICENSE)
- github.com/opentracing/opentracing-go [MIT LICENSE](https://github.com/opentracing/opentracing-go/blob/master/LICENSE)
- github.com/paulbellamy/ratecounter [MIT LICENSE](https://github.com/paulbellamy/ratecounter/blob/master/LICENSE)

View File

@ -16,8 +16,6 @@ import (
"github.com/influxdata/influxdb/cmd/influxd/help"
"github.com/influxdata/influxdb/cmd/influxd/restore"
"github.com/influxdata/influxdb/cmd/influxd/run"
"github.com/influxdata/influxdb/logger"
"go.uber.org/zap"
)
// These variables are populated via the Go linker.
@ -52,8 +50,6 @@ func main() {
// Main represents the program execution.
type Main struct {
Logger *zap.Logger
Stdin io.Reader
Stdout io.Writer
Stderr io.Writer
@ -62,7 +58,6 @@ type Main struct {
// NewMain return a new instance of Main.
func NewMain() *Main {
return &Main{
Logger: logger.New(os.Stderr),
Stdin: os.Stdin,
Stdout: os.Stdout,
Stderr: os.Stderr,
@ -82,7 +77,6 @@ func (m *Main) Run(args ...string) error {
cmd.Version = version
cmd.Commit = commit
cmd.Branch = branch
cmd.Logger = m.Logger
if err := cmd.Run(args...); err != nil {
return fmt.Errorf("run: %s", err)
@ -90,23 +84,23 @@ func (m *Main) Run(args ...string) error {
signalCh := make(chan os.Signal, 1)
signal.Notify(signalCh, os.Interrupt, syscall.SIGTERM)
m.Logger.Info("Listening for signals")
cmd.Logger.Info("Listening for signals")
// Block until one of the signals above is received
<-signalCh
m.Logger.Info("Signal received, initializing clean shutdown...")
cmd.Logger.Info("Signal received, initializing clean shutdown...")
go cmd.Close()
// Block again until another signal is received, a shutdown timeout elapses,
// or the Command is gracefully closed
m.Logger.Info("Waiting for clean shutdown...")
cmd.Logger.Info("Waiting for clean shutdown...")
select {
case <-signalCh:
m.Logger.Info("second signal received, initializing hard shutdown")
cmd.Logger.Info("second signal received, initializing hard shutdown")
case <-time.After(time.Second * 30):
m.Logger.Info("time limit reached, initializing hard shutdown")
cmd.Logger.Info("time limit reached, initializing hard shutdown")
case <-cmd.Closed:
m.Logger.Info("server shutdown completed")
cmd.Logger.Info("server shutdown completed")
}
// goodbye.

View File

@ -13,6 +13,7 @@ import (
"strconv"
"time"
"github.com/influxdata/influxdb/logger"
"go.uber.org/zap"
)
@ -70,14 +71,43 @@ func (cmd *Command) Run(args ...string) error {
return err
}
// Attempt to parse the config once in advance. If this fails, use the
// default logging configuration.
var (
suppressLogo bool
logErr error
)
if config, err := cmd.ParseConfig(options.GetConfigPath()); err == nil {
suppressLogo = config.Logging.SuppressLogo
if l, err := config.Logging.New(cmd.Stderr); err == nil {
cmd.Logger = l
} else {
logErr = err
}
} else {
logErr = err
}
// We were unable to read the configuration file. Use the default logging format.
if logErr != nil {
cmd.Logger = logger.New(cmd.Stderr)
}
// Print sweet InfluxDB logo.
fmt.Fprint(cmd.Stdout, logo)
if !suppressLogo {
fmt.Fprint(cmd.Stdout, logo)
}
// Mark start-up in log.
cmd.Logger.Info(fmt.Sprintf("InfluxDB starting, version %s, branch %s, commit %s",
cmd.Version, cmd.Branch, cmd.Commit))
cmd.Logger.Info(fmt.Sprintf("Go version %s, GOMAXPROCS set to %d", runtime.Version(), runtime.GOMAXPROCS(0)))
// If there was an error on startup when creating the logger, output it now.
if logErr != nil {
cmd.Logger.Error("Unable to configure logger", zap.Error(logErr))
}
// Write the PID file.
if err := cmd.writePIDFile(options.PIDFile); err != nil {
return fmt.Errorf("write pid file: %s", err)

View File

@ -15,6 +15,7 @@ import (
"github.com/BurntSushi/toml"
"github.com/influxdata/influxdb/coordinator"
"github.com/influxdata/influxdb/logger"
"github.com/influxdata/influxdb/monitor"
"github.com/influxdata/influxdb/monitor/diagnostics"
"github.com/influxdata/influxdb/services/collectd"
@ -49,6 +50,7 @@ type Config struct {
Monitor monitor.Config `toml:"monitor"`
Subscriber subscriber.Config `toml:"subscriber"`
HTTPD httpd.Config `toml:"http"`
Logging logger.Config `toml:"logging"`
Storage storage.Config `toml:"ifql"`
GraphiteInputs []graphite.Config `toml:"graphite"`
CollectdInputs []collectd.Config `toml:"collectd"`
@ -75,6 +77,7 @@ func NewConfig() *Config {
c.Monitor = monitor.NewConfig()
c.Subscriber = subscriber.NewConfig()
c.HTTPD = httpd.NewConfig()
c.Logging = logger.NewConfig()
c.Storage = storage.NewConfig()
c.GraphiteInputs = []graphite.Config{graphite.NewConfig()}

View File

@ -270,6 +270,24 @@
# bind-address = ":8082"
###
### [logging]
###
### Controls how the logger emits logs to the output.
###
[logging]
# Determines which log encoder to use for logs. Available options
# are logfmt, console, and json. console is a more user-friendly
# output format, but not as easily machine-readable.
# format = "logfmt"
# Determines which level of logs will be emitted.
# level = "info"
# Suppresses the logo output that is printed when the program is started.
# suppress-logo = false
###
### [subscriber]
###

18
logger/config.go Normal file
View File

@ -0,0 +1,18 @@
package logger
import (
"go.uber.org/zap/zapcore"
)
type Config struct {
Format string `toml:"format"`
Level zapcore.Level `toml:"level"`
SuppressLogo bool `toml:"suppress-logo"`
}
// NewConfig returns a new instance of Config with defaults.
func NewConfig() Config {
return Config{
Format: "auto",
}
}

View File

@ -1,14 +1,66 @@
package logger
import (
"fmt"
"io"
"time"
"github.com/jsternberg/zap-logfmt"
isatty "github.com/mattn/go-isatty"
"go.uber.org/zap"
"go.uber.org/zap/zapcore"
)
func New(w io.Writer) *zap.Logger {
config := NewConfig()
l, _ := config.New(w)
return l
}
func (c *Config) New(defaultOutput io.Writer) (*zap.Logger, error) {
w := defaultOutput
format := c.Format
if format == "console" {
// Disallow the console logger if the output is not a terminal.
return nil, fmt.Errorf("unknown logging format: %s", format)
}
// If the format is empty or auto, then set the format depending
// on whether or not a terminal is present.
if format == "" || format == "auto" {
if isTerminal(w) {
format = "console"
} else {
format = "logfmt"
}
}
encoder, err := newEncoder(format)
if err != nil {
return nil, err
}
return zap.New(zapcore.NewCore(
encoder,
zapcore.Lock(zapcore.AddSync(w)),
c.Level,
)), nil
}
func newEncoder(format string) (zapcore.Encoder, error) {
config := newEncoderConfig()
switch format {
case "json":
return zapcore.NewJSONEncoder(config), nil
case "console":
return zapcore.NewConsoleEncoder(config), nil
case "logfmt":
return zaplogfmt.NewEncoder(config), nil
default:
return nil, fmt.Errorf("unknown logging format: %s", format)
}
}
func newEncoderConfig() zapcore.EncoderConfig {
config := zap.NewProductionEncoderConfig()
config.EncodeTime = func(ts time.Time, encoder zapcore.PrimitiveArrayEncoder) {
encoder.AppendString(ts.UTC().Format(time.RFC3339))
@ -16,9 +68,14 @@ func New(w io.Writer) *zap.Logger {
config.EncodeDuration = func(d time.Duration, encoder zapcore.PrimitiveArrayEncoder) {
encoder.AppendString(d.String())
}
return zap.New(zapcore.NewCore(
zapcore.NewConsoleEncoder(config),
zapcore.Lock(zapcore.AddSync(w)),
zapcore.DebugLevel,
))
return config
}
func isTerminal(w io.Writer) bool {
if f, ok := w.(interface {
Fd() uintptr
}); ok {
return isatty.IsTerminal(f.Fd())
}
return false
}