colorized stdout logger if stdout is tty

This commit is contained in:
Christian Schwarz 2018-08-30 13:30:18 +02:00
parent b5957aca37
commit 1690339440
6 changed files with 51 additions and 9 deletions

17
Gopkg.lock generated
View File

@ -17,6 +17,14 @@
revision = "346938d642f2ec3594ed81d874461961cd0faa76" revision = "346938d642f2ec3594ed81d874461961cd0faa76"
version = "v1.1.0" version = "v1.1.0"
[[projects]]
digest = "1:e988ed0ca0d81f4d28772760c02ee95084961311291bdfefc1b04617c178b722"
name = "github.com/fatih/color"
packages = ["."]
pruneopts = ""
revision = "5b77d2a35fb0ede96d138fc9a99f5c9b6aef11b4"
version = "v1.7.0"
[[projects]] [[projects]]
branch = "master" branch = "master"
digest = "1:5d0a2385edf4ba44f3b7b76bc0436ceb8f62bf55aa5d540a9eb9ec6c58d86809" digest = "1:5d0a2385edf4ba44f3b7b76bc0436ceb8f62bf55aa5d540a9eb9ec6c58d86809"
@ -81,6 +89,14 @@
pruneopts = "" pruneopts = ""
revision = "7cafcd837844e784b526369c9bce262804aebc60" revision = "7cafcd837844e784b526369c9bce262804aebc60"
[[projects]]
digest = "1:9ea83adf8e96d6304f394d40436f2eb44c1dc3250d223b74088cc253a6cd0a1c"
name = "github.com/mattn/go-colorable"
packages = ["."]
pruneopts = ""
revision = "167de6bfdfba052fa6b2d3664c8f5272e23c9072"
version = "v0.0.9"
[[projects]] [[projects]]
digest = "1:78229b46ddb7434f881390029bd1af7661294af31f6802e0e1bedaad4ab0af3c" digest = "1:78229b46ddb7434f881390029bd1af7661294af31f6802e0e1bedaad4ab0af3c"
name = "github.com/mattn/go-isatty" name = "github.com/mattn/go-isatty"
@ -255,6 +271,7 @@
analyzer-name = "dep" analyzer-name = "dep"
analyzer-version = 1 analyzer-version = 1
input-imports = [ input-imports = [
"github.com/fatih/color",
"github.com/go-logfmt/logfmt", "github.com/go-logfmt/logfmt",
"github.com/go-yaml/yaml", "github.com/go-yaml/yaml",
"github.com/golang/protobuf/proto", "github.com/golang/protobuf/proto",

View File

@ -66,4 +66,7 @@ ignored = [ "github.com/inconshreveable/mousetrap" ]
[[constraint]] [[constraint]]
name = "github.com/nsf/termbox-go" name = "github.com/nsf/termbox-go"
branch = "master" branch = "master"
[[constraint]]
name = "github.com/fatih/color"
version = "1.7.0"

View File

@ -197,6 +197,7 @@ type LoggingOutletCommon struct {
type StdoutLoggingOutlet struct { type StdoutLoggingOutlet struct {
LoggingOutletCommon `yaml:",inline"` LoggingOutletCommon `yaml:",inline"`
Time bool `yaml:"time,default=true"` Time bool `yaml:"time,default=true"`
Color bool `yaml:"color,default=true""`
} }
type SyslogLoggingOutlet struct { type SyslogLoggingOutlet struct {

View File

@ -8,12 +8,12 @@ import (
"github.com/pkg/errors" "github.com/pkg/errors"
"github.com/problame/go-streamrpc" "github.com/problame/go-streamrpc"
"github.com/zrepl/zrepl/config" "github.com/zrepl/zrepl/config"
"github.com/zrepl/zrepl/daemon/pruner"
"github.com/zrepl/zrepl/endpoint" "github.com/zrepl/zrepl/endpoint"
"github.com/zrepl/zrepl/logger" "github.com/zrepl/zrepl/logger"
"github.com/zrepl/zrepl/replication" "github.com/zrepl/zrepl/replication"
"github.com/zrepl/zrepl/tlsconf" "github.com/zrepl/zrepl/tlsconf"
"os" "os"
"github.com/zrepl/zrepl/daemon/pruner"
) )
func OutletsFromConfig(in []config.LoggingOutletEnum) (*logger.Outlets, error) { func OutletsFromConfig(in []config.LoggingOutletEnum) (*logger.Outlets, error) {
@ -145,6 +145,9 @@ func parseStdoutOutlet(in *config.StdoutLoggingOutlet, formatter EntryFormatter)
if !isatty.IsTerminal(writer.Fd()) && !in.Time { if !isatty.IsTerminal(writer.Fd()) && !in.Time {
flags &= ^MetadataTime flags &= ^MetadataTime
} }
if isatty.IsTerminal(writer.Fd()) && !in.Color {
flags &= ^MetadataColor
}
formatter.SetMetadataFlags(flags) formatter.SetMetadataFlags(flags)
return WriterOutlet{ return WriterOutlet{

View File

@ -4,6 +4,7 @@ import (
"bytes" "bytes"
"encoding/json" "encoding/json"
"fmt" "fmt"
"github.com/fatih/color"
"github.com/go-logfmt/logfmt" "github.com/go-logfmt/logfmt"
"github.com/pkg/errors" "github.com/pkg/errors"
"github.com/zrepl/zrepl/logger" "github.com/zrepl/zrepl/logger"
@ -26,6 +27,7 @@ type MetadataFlags int64
const ( const (
MetadataTime MetadataFlags = 1 << iota MetadataTime MetadataFlags = 1 << iota
MetadataLevel MetadataLevel
MetadataColor
MetadataNone MetadataFlags = 0 MetadataNone MetadataFlags = 0
MetadataAll MetadataFlags = ^0 MetadataAll MetadataFlags = ^0
@ -69,12 +71,16 @@ func (f *HumanFormatter) ignored(field string) bool {
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
col := color.New()
if f.metadataFlags&MetadataColor != 0 {
col = e.Color()
}
if f.metadataFlags&MetadataTime != 0 { if f.metadataFlags&MetadataTime != 0 {
fmt.Fprintf(&line, "%s ", e.Time.Format(HumanFormatterDateFormat)) fmt.Fprintf(&line, "%s ", e.Time.Format(HumanFormatterDateFormat))
} }
if f.metadataFlags&MetadataLevel != 0 { if f.metadataFlags&MetadataLevel != 0 {
fmt.Fprintf(&line, "[%s]", e.Level.Short()) fmt.Fprintf(&line, "[%s]", col.Sprint(e.Level.Short()))
} }
prefixFields := []string{JobField, SubsysField} prefixFields := []string{JobField, SubsysField}
@ -85,7 +91,7 @@ func (f *HumanFormatter) Format(e *logger.Entry) (out []byte, err error) {
continue continue
} }
if !f.ignored(field) { if !f.ignored(field) {
fmt.Fprintf(&line, "[%s]", val) fmt.Fprintf(&line, "[%s]", col.Sprint(val))
prefixed[field] = true prefixed[field] = true
} }
} }
@ -96,15 +102,11 @@ func (f *HumanFormatter) Format(e *logger.Entry) (out []byte, err error) {
fmt.Fprint(&line, e.Message) fmt.Fprint(&line, e.Message)
if len(e.Fields)-len(prefixed) > 0 { if len(e.Fields)-len(prefixed) > 0 {
fmt.Fprint(&line, " ")
enc := logfmt.NewEncoder(&line)
for field, value := range e.Fields { for field, value := range e.Fields {
if prefixed[field] || f.ignored(field) { if prefixed[field] || f.ignored(field) {
continue continue
} }
if err := logfmtTryEncodeKeyval(enc, field, value); err != nil { fmt.Fprintf(&line, " %s=%q", col.Sprint(field), fmt.Sprint(value))
return nil, err
}
} }
} }

View File

@ -4,6 +4,7 @@ import (
"bytes" "bytes"
"encoding/json" "encoding/json"
"fmt" "fmt"
"github.com/fatih/color"
"github.com/pkg/errors" "github.com/pkg/errors"
"sync" "sync"
"time" "time"
@ -105,6 +106,21 @@ type Entry struct {
Fields Fields Fields Fields
} }
func (e Entry) Color() *color.Color {
c := color.New()
switch e.Level {
case Debug:
c.Add(color.FgHiBlue)
case Info:
c.Add(color.FgHiGreen)
case Warn:
c.Add(color.FgHiYellow)
case Error:
c.Add(color.FgHiRed)
}
return c
}
// An outlet receives log entries produced by the Logger and writes them to some destination. // An outlet receives log entries produced by the Logger and writes them to some destination.
type Outlet interface { type Outlet interface {
// Write the entry to the destination. // Write the entry to the destination.