mirror of
https://github.com/zrepl/zrepl.git
synced 2024-11-22 16:34:32 +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 = ["."]
|
packages = ["."]
|
||||||
revision = "7cafcd837844e784b526369c9bce262804aebc60"
|
revision = "7cafcd837844e784b526369c9bce262804aebc60"
|
||||||
|
|
||||||
|
[[projects]]
|
||||||
|
name = "github.com/mattn/go-isatty"
|
||||||
|
packages = ["."]
|
||||||
|
revision = "0360b2af4f38e8d38c7fce2a9f4e702702d73a39"
|
||||||
|
version = "v0.0.3"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
branch = "master"
|
branch = "master"
|
||||||
name = "github.com/mitchellh/mapstructure"
|
name = "github.com/mitchellh/mapstructure"
|
||||||
@ -91,9 +97,15 @@
|
|||||||
revision = "69483b4bd14f5845b5a1e55bca19e954e827f1d0"
|
revision = "69483b4bd14f5845b5a1e55bca19e954e827f1d0"
|
||||||
version = "v1.1.4"
|
version = "v1.1.4"
|
||||||
|
|
||||||
|
[[projects]]
|
||||||
|
branch = "master"
|
||||||
|
name = "golang.org/x/sys"
|
||||||
|
packages = ["unix"]
|
||||||
|
revision = "bf42f188b9bc6f2cf5b8ee5a912ef1aedd0eba4c"
|
||||||
|
|
||||||
[solve-meta]
|
[solve-meta]
|
||||||
analyzer-name = "dep"
|
analyzer-name = "dep"
|
||||||
analyzer-version = 1
|
analyzer-version = 1
|
||||||
inputs-digest = "d654c5e91ee04baf1a373bb241b94ab41d3838fb69a56e91fe54cc8b962eab56"
|
inputs-digest = "b2174984fa0452d4469597063f891904b70081586b239262690cf1b6477a3116"
|
||||||
solver-name = "gps-cdcl"
|
solver-name = "gps-cdcl"
|
||||||
solver-version = 1
|
solver-version = 1
|
||||||
|
@ -3,6 +3,7 @@ package cmd
|
|||||||
import (
|
import (
|
||||||
"crypto/tls"
|
"crypto/tls"
|
||||||
"crypto/x509"
|
"crypto/x509"
|
||||||
|
"github.com/mattn/go-isatty"
|
||||||
"github.com/mitchellh/mapstructure"
|
"github.com/mitchellh/mapstructure"
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
"github.com/zrepl/zrepl/logger"
|
"github.com/zrepl/zrepl/logger"
|
||||||
@ -15,14 +16,15 @@ type LoggingConfig struct {
|
|||||||
Outlets logger.Outlets
|
Outlets logger.Outlets
|
||||||
}
|
}
|
||||||
|
|
||||||
type SetNoMetadataFormatter interface {
|
type MetadataFlags int64
|
||||||
SetNoMetadata(noMetadata bool)
|
|
||||||
}
|
|
||||||
|
|
||||||
type OutletCommon struct {
|
const (
|
||||||
MinLevel logger.Level
|
MetadataTime MetadataFlags = 1 << iota
|
||||||
Formatter EntryFormatter
|
MetadataLevel
|
||||||
}
|
|
||||||
|
MetadataNone MetadataFlags = 0
|
||||||
|
MetadataAll MetadataFlags = ^0
|
||||||
|
)
|
||||||
|
|
||||||
func parseLogging(i interface{}) (c *LoggingConfig, err error) {
|
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
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
common := &OutletCommon{}
|
minLevel, err := logger.ParseLevel(in.Level)
|
||||||
common.MinLevel, err = logger.ParseLevel(in.Level)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
err = errors.Wrap(err, "cannot parse 'level' field")
|
err = errors.Wrap(err, "cannot parse 'level' field")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
common.Formatter, err = parseLogFormat(in.Format)
|
formatter, err := parseLogFormat(in.Format)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
err = errors.Wrap(err, "cannot parse")
|
err = errors.Wrap(err, "cannot parse")
|
||||||
return
|
return
|
||||||
@ -123,29 +124,45 @@ func parseOutlet(i interface{}) (o logger.Outlet, level logger.Level, err error)
|
|||||||
|
|
||||||
switch in.Outlet {
|
switch in.Outlet {
|
||||||
case "stdout":
|
case "stdout":
|
||||||
o, err = parseStdoutOutlet(i, common)
|
o, err = parseStdoutOutlet(i, formatter)
|
||||||
case "tcp":
|
case "tcp":
|
||||||
o, err = parseTCPOutlet(i, common)
|
o, err = parseTCPOutlet(i, formatter)
|
||||||
case "syslog":
|
case "syslog":
|
||||||
o, err = parseSyslogOutlet(i, common)
|
o, err = parseSyslogOutlet(i, formatter)
|
||||||
default:
|
default:
|
||||||
err = errors.Errorf("unknown outlet type '%s'", in.Outlet)
|
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{
|
return WriterOutlet{
|
||||||
common.Formatter,
|
formatter,
|
||||||
os.Stdout,
|
os.Stdout,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func parseTCPOutlet(i interface{}, common *OutletCommon) (out *TCPOutlet, err error) {
|
func parseTCPOutlet(i interface{}, formatter EntryFormatter) (out *TCPOutlet, err error) {
|
||||||
|
|
||||||
out = &TCPOutlet{}
|
out = &TCPOutlet{}
|
||||||
out.Formatter = common.Formatter
|
out.Formatter = formatter
|
||||||
|
out.Formatter.SetMetadataFlags(MetadataAll)
|
||||||
|
|
||||||
var in struct {
|
var in struct {
|
||||||
Net string
|
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 {
|
var in struct {
|
||||||
RetryInterval string `mapstructure:"retry_interval"`
|
RetryInterval string `mapstructure:"retry_interval"`
|
||||||
@ -216,10 +233,8 @@ func parseSyslogOutlet(i interface{}, common *OutletCommon) (out *SyslogOutlet,
|
|||||||
}
|
}
|
||||||
|
|
||||||
out = &SyslogOutlet{}
|
out = &SyslogOutlet{}
|
||||||
out.Formatter = common.Formatter
|
out.Formatter = formatter
|
||||||
if f, ok := out.Formatter.(SetNoMetadataFormatter); ok {
|
out.Formatter.SetMetadataFlags(MetadataNone)
|
||||||
f.SetNoMetadata(true)
|
|
||||||
}
|
|
||||||
|
|
||||||
out.RetryInterval = 0 // default to 0 as we assume local syslog will just work
|
out.RetryInterval = 0 // default to 0 as we assume local syslog will just work
|
||||||
if in.RetryInterval != "" {
|
if in.RetryInterval != "" {
|
||||||
|
@ -11,6 +11,7 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type EntryFormatter interface {
|
type EntryFormatter interface {
|
||||||
|
SetMetadataFlags(flags MetadataFlags)
|
||||||
Format(e *logger.Entry) ([]byte, error)
|
Format(e *logger.Entry) ([]byte, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -32,25 +33,28 @@ const (
|
|||||||
|
|
||||||
type NoFormatter struct{}
|
type NoFormatter struct{}
|
||||||
|
|
||||||
|
func (f NoFormatter) SetMetadataFlags(flags MetadataFlags) {}
|
||||||
|
|
||||||
func (f NoFormatter) Format(e *logger.Entry) ([]byte, error) {
|
func (f NoFormatter) Format(e *logger.Entry) ([]byte, error) {
|
||||||
return []byte(e.Message), nil
|
return []byte(e.Message), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
type HumanFormatter struct {
|
type HumanFormatter struct {
|
||||||
NoMetadata bool
|
metadataFlags MetadataFlags
|
||||||
}
|
}
|
||||||
|
|
||||||
var _ SetNoMetadataFormatter = &HumanFormatter{}
|
func (f *HumanFormatter) SetMetadataFlags(flags MetadataFlags) {
|
||||||
|
f.metadataFlags = flags
|
||||||
func (f *HumanFormatter) SetNoMetadata(noMetadata bool) {
|
|
||||||
f.NoMetadata = noMetadata
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f *HumanFormatter) Format(e *logger.Entry) (out []byte, err error) {
|
func (f *HumanFormatter) Format(e *logger.Entry) (out []byte, err error) {
|
||||||
|
|
||||||
var line bytes.Buffer
|
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())
|
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
|
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) {
|
func (f *JSONFormatter) Format(e *logger.Entry) ([]byte, error) {
|
||||||
data := make(logger.Fields, len(e.Fields)+3)
|
data := make(logger.Fields, len(e.Fields)+3)
|
||||||
@ -128,21 +138,21 @@ func (f *JSONFormatter) Format(e *logger.Entry) ([]byte, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type LogfmtFormatter struct {
|
type LogfmtFormatter struct {
|
||||||
NoMetadata bool
|
metadataFlags MetadataFlags
|
||||||
}
|
}
|
||||||
|
|
||||||
var _ SetNoMetadataFormatter = &LogfmtFormatter{}
|
func (f *LogfmtFormatter) SetMetadataFlags(flags MetadataFlags) {
|
||||||
|
f.metadataFlags = flags
|
||||||
func (f *LogfmtFormatter) SetNoMetadata(noMetadata bool) {
|
|
||||||
f.NoMetadata = noMetadata
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f *LogfmtFormatter) Format(e *logger.Entry) ([]byte, error) {
|
func (f *LogfmtFormatter) Format(e *logger.Entry) ([]byte, error) {
|
||||||
var buf bytes.Buffer
|
var buf bytes.Buffer
|
||||||
enc := logfmt.NewEncoder(&buf)
|
enc := logfmt.NewEncoder(&buf)
|
||||||
|
|
||||||
if !f.NoMetadata {
|
if f.metadataFlags&MetadataTime != 0 {
|
||||||
enc.EncodeKeyval(FieldTime, e.Time)
|
enc.EncodeKeyval(FieldTime, e.Time)
|
||||||
|
}
|
||||||
|
if f.metadataFlags&MetadataLevel != 0 {
|
||||||
enc.EncodeKeyval(FieldLevel, e.Level)
|
enc.EncodeKeyval(FieldLevel, e.Level)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -115,8 +115,11 @@ Formats
|
|||||||
- minimum :ref:`log level <logging-levels>`
|
- minimum :ref:`log level <logging-levels>`
|
||||||
* - ``format``
|
* - ``format``
|
||||||
- output :ref:`format <logging-formats>`
|
- 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.
|
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.
|
Can only be specified once.
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user