mirror of
https://github.com/zrepl/zrepl.git
synced 2024-11-22 00:13:52 +01:00
logging: stdout outlet: include time in output if tty or forced through config
This commit is contained in:
parent
ed68bffea5
commit
476348689a
14
Gopkg.lock
generated
14
Gopkg.lock
generated
@ -55,6 +55,12 @@
|
||||
packages = ["."]
|
||||
revision = "7cafcd837844e784b526369c9bce262804aebc60"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/mattn/go-isatty"
|
||||
packages = ["."]
|
||||
revision = "0360b2af4f38e8d38c7fce2a9f4e702702d73a39"
|
||||
version = "v0.0.3"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
name = "github.com/mitchellh/mapstructure"
|
||||
@ -91,9 +97,15 @@
|
||||
revision = "69483b4bd14f5845b5a1e55bca19e954e827f1d0"
|
||||
version = "v1.1.4"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
name = "golang.org/x/sys"
|
||||
packages = ["unix"]
|
||||
revision = "bf42f188b9bc6f2cf5b8ee5a912ef1aedd0eba4c"
|
||||
|
||||
[solve-meta]
|
||||
analyzer-name = "dep"
|
||||
analyzer-version = 1
|
||||
inputs-digest = "d654c5e91ee04baf1a373bb241b94ab41d3838fb69a56e91fe54cc8b962eab56"
|
||||
inputs-digest = "b2174984fa0452d4469597063f891904b70081586b239262690cf1b6477a3116"
|
||||
solver-name = "gps-cdcl"
|
||||
solver-version = 1
|
||||
|
@ -3,6 +3,7 @@ package cmd
|
||||
import (
|
||||
"crypto/tls"
|
||||
"crypto/x509"
|
||||
"github.com/mattn/go-isatty"
|
||||
"github.com/mitchellh/mapstructure"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/zrepl/zrepl/logger"
|
||||
@ -15,14 +16,15 @@ type LoggingConfig struct {
|
||||
Outlets logger.Outlets
|
||||
}
|
||||
|
||||
type SetNoMetadataFormatter interface {
|
||||
SetNoMetadata(noMetadata bool)
|
||||
}
|
||||
type MetadataFlags int64
|
||||
|
||||
type OutletCommon struct {
|
||||
MinLevel logger.Level
|
||||
Formatter EntryFormatter
|
||||
}
|
||||
const (
|
||||
MetadataTime MetadataFlags = 1 << iota
|
||||
MetadataLevel
|
||||
|
||||
MetadataNone MetadataFlags = 0
|
||||
MetadataAll MetadataFlags = ^0
|
||||
)
|
||||
|
||||
func parseLogging(i interface{}) (c *LoggingConfig, err error) {
|
||||
|
||||
@ -109,13 +111,12 @@ func parseOutlet(i interface{}) (o logger.Outlet, level logger.Level, err error)
|
||||
return
|
||||
}
|
||||
|
||||
common := &OutletCommon{}
|
||||
common.MinLevel, err = logger.ParseLevel(in.Level)
|
||||
minLevel, err := logger.ParseLevel(in.Level)
|
||||
if err != nil {
|
||||
err = errors.Wrap(err, "cannot parse 'level' field")
|
||||
return
|
||||
}
|
||||
common.Formatter, err = parseLogFormat(in.Format)
|
||||
formatter, err := parseLogFormat(in.Format)
|
||||
if err != nil {
|
||||
err = errors.Wrap(err, "cannot parse")
|
||||
return
|
||||
@ -123,29 +124,45 @@ func parseOutlet(i interface{}) (o logger.Outlet, level logger.Level, err error)
|
||||
|
||||
switch in.Outlet {
|
||||
case "stdout":
|
||||
o, err = parseStdoutOutlet(i, common)
|
||||
o, err = parseStdoutOutlet(i, formatter)
|
||||
case "tcp":
|
||||
o, err = parseTCPOutlet(i, common)
|
||||
o, err = parseTCPOutlet(i, formatter)
|
||||
case "syslog":
|
||||
o, err = parseSyslogOutlet(i, common)
|
||||
o, err = parseSyslogOutlet(i, formatter)
|
||||
default:
|
||||
err = errors.Errorf("unknown outlet type '%s'", in.Outlet)
|
||||
}
|
||||
return o, common.MinLevel, err
|
||||
return o, minLevel, err
|
||||
|
||||
}
|
||||
|
||||
func parseStdoutOutlet(i interface{}, common *OutletCommon) (WriterOutlet, error) {
|
||||
func parseStdoutOutlet(i interface{}, formatter EntryFormatter) (WriterOutlet, error) {
|
||||
|
||||
var in struct {
|
||||
Date bool
|
||||
}
|
||||
if err := mapstructure.Decode(i, &in); err != nil {
|
||||
return WriterOutlet{}, errors.Wrap(err, "invalid structure for stdout outlet")
|
||||
}
|
||||
|
||||
flags := MetadataAll
|
||||
writer := os.Stdout
|
||||
if !isatty.IsTerminal(writer.Fd()) && !in.Date {
|
||||
flags &= ^MetadataTime
|
||||
}
|
||||
|
||||
formatter.SetMetadataFlags(flags)
|
||||
return WriterOutlet{
|
||||
common.Formatter,
|
||||
formatter,
|
||||
os.Stdout,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func parseTCPOutlet(i interface{}, common *OutletCommon) (out *TCPOutlet, err error) {
|
||||
func parseTCPOutlet(i interface{}, formatter EntryFormatter) (out *TCPOutlet, err error) {
|
||||
|
||||
out = &TCPOutlet{}
|
||||
out.Formatter = common.Formatter
|
||||
out.Formatter = formatter
|
||||
out.Formatter.SetMetadataFlags(MetadataAll)
|
||||
|
||||
var in struct {
|
||||
Net string
|
||||
@ -206,7 +223,7 @@ func parseTCPOutlet(i interface{}, common *OutletCommon) (out *TCPOutlet, err er
|
||||
|
||||
}
|
||||
|
||||
func parseSyslogOutlet(i interface{}, common *OutletCommon) (out *SyslogOutlet, err error) {
|
||||
func parseSyslogOutlet(i interface{}, formatter EntryFormatter) (out *SyslogOutlet, err error) {
|
||||
|
||||
var in struct {
|
||||
RetryInterval string `mapstructure:"retry_interval"`
|
||||
@ -216,10 +233,8 @@ func parseSyslogOutlet(i interface{}, common *OutletCommon) (out *SyslogOutlet,
|
||||
}
|
||||
|
||||
out = &SyslogOutlet{}
|
||||
out.Formatter = common.Formatter
|
||||
if f, ok := out.Formatter.(SetNoMetadataFormatter); ok {
|
||||
f.SetNoMetadata(true)
|
||||
}
|
||||
out.Formatter = formatter
|
||||
out.Formatter.SetMetadataFlags(MetadataNone)
|
||||
|
||||
out.RetryInterval = 0 // default to 0 as we assume local syslog will just work
|
||||
if in.RetryInterval != "" {
|
||||
|
@ -11,6 +11,7 @@ import (
|
||||
)
|
||||
|
||||
type EntryFormatter interface {
|
||||
SetMetadataFlags(flags MetadataFlags)
|
||||
Format(e *logger.Entry) ([]byte, error)
|
||||
}
|
||||
|
||||
@ -32,25 +33,28 @@ const (
|
||||
|
||||
type NoFormatter struct{}
|
||||
|
||||
func (f NoFormatter) SetMetadataFlags(flags MetadataFlags) {}
|
||||
|
||||
func (f NoFormatter) Format(e *logger.Entry) ([]byte, error) {
|
||||
return []byte(e.Message), nil
|
||||
}
|
||||
|
||||
type HumanFormatter struct {
|
||||
NoMetadata bool
|
||||
metadataFlags MetadataFlags
|
||||
}
|
||||
|
||||
var _ SetNoMetadataFormatter = &HumanFormatter{}
|
||||
|
||||
func (f *HumanFormatter) SetNoMetadata(noMetadata bool) {
|
||||
f.NoMetadata = noMetadata
|
||||
func (f *HumanFormatter) SetMetadataFlags(flags MetadataFlags) {
|
||||
f.metadataFlags = flags
|
||||
}
|
||||
|
||||
func (f *HumanFormatter) Format(e *logger.Entry) (out []byte, err error) {
|
||||
|
||||
var line bytes.Buffer
|
||||
|
||||
if !f.NoMetadata {
|
||||
if f.metadataFlags&MetadataTime != 0 {
|
||||
fmt.Fprintf(&line, "%s ", e.Time.Format(time.RFC3339))
|
||||
}
|
||||
if f.metadataFlags&MetadataLevel != 0 {
|
||||
fmt.Fprintf(&line, "[%s]", e.Level.Short())
|
||||
}
|
||||
|
||||
@ -100,7 +104,13 @@ func (f *HumanFormatter) Format(e *logger.Entry) (out []byte, err error) {
|
||||
return line.Bytes(), nil
|
||||
}
|
||||
|
||||
type JSONFormatter struct{}
|
||||
type JSONFormatter struct {
|
||||
metadataFlags MetadataFlags
|
||||
}
|
||||
|
||||
func (f *JSONFormatter) SetMetadataFlags(flags MetadataFlags) {
|
||||
f.metadataFlags = flags
|
||||
}
|
||||
|
||||
func (f *JSONFormatter) Format(e *logger.Entry) ([]byte, error) {
|
||||
data := make(logger.Fields, len(e.Fields)+3)
|
||||
@ -128,21 +138,21 @@ func (f *JSONFormatter) Format(e *logger.Entry) ([]byte, error) {
|
||||
}
|
||||
|
||||
type LogfmtFormatter struct {
|
||||
NoMetadata bool
|
||||
metadataFlags MetadataFlags
|
||||
}
|
||||
|
||||
var _ SetNoMetadataFormatter = &LogfmtFormatter{}
|
||||
|
||||
func (f *LogfmtFormatter) SetNoMetadata(noMetadata bool) {
|
||||
f.NoMetadata = noMetadata
|
||||
func (f *LogfmtFormatter) SetMetadataFlags(flags MetadataFlags) {
|
||||
f.metadataFlags = flags
|
||||
}
|
||||
|
||||
func (f *LogfmtFormatter) Format(e *logger.Entry) ([]byte, error) {
|
||||
var buf bytes.Buffer
|
||||
enc := logfmt.NewEncoder(&buf)
|
||||
|
||||
if !f.NoMetadata {
|
||||
if f.metadataFlags&MetadataTime != 0 {
|
||||
enc.EncodeKeyval(FieldTime, e.Time)
|
||||
}
|
||||
if f.metadataFlags&MetadataLevel != 0 {
|
||||
enc.EncodeKeyval(FieldLevel, e.Level)
|
||||
}
|
||||
|
||||
|
@ -115,8 +115,11 @@ Formats
|
||||
- minimum :ref:`log level <logging-levels>`
|
||||
* - ``format``
|
||||
- output :ref:`format <logging-formats>`
|
||||
* - ``time``
|
||||
- always include time in output (``true`` or ``false``)
|
||||
|
||||
Writes all log entries with minimum level ``level`` formatted by ``format`` to stdout.
|
||||
If stdout is a tty, interactive usage is assumed and the current time is included in the output.
|
||||
|
||||
Can only be specified once.
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user