diff --git a/Gopkg.lock b/Gopkg.lock index 5e7387e..cda2e51 100644 --- a/Gopkg.lock +++ b/Gopkg.lock @@ -17,6 +17,14 @@ revision = "346938d642f2ec3594ed81d874461961cd0faa76" version = "v1.1.0" +[[projects]] + digest = "1:e988ed0ca0d81f4d28772760c02ee95084961311291bdfefc1b04617c178b722" + name = "github.com/fatih/color" + packages = ["."] + pruneopts = "" + revision = "5b77d2a35fb0ede96d138fc9a99f5c9b6aef11b4" + version = "v1.7.0" + [[projects]] branch = "master" digest = "1:5d0a2385edf4ba44f3b7b76bc0436ceb8f62bf55aa5d540a9eb9ec6c58d86809" @@ -81,6 +89,14 @@ pruneopts = "" revision = "7cafcd837844e784b526369c9bce262804aebc60" +[[projects]] + digest = "1:9ea83adf8e96d6304f394d40436f2eb44c1dc3250d223b74088cc253a6cd0a1c" + name = "github.com/mattn/go-colorable" + packages = ["."] + pruneopts = "" + revision = "167de6bfdfba052fa6b2d3664c8f5272e23c9072" + version = "v0.0.9" + [[projects]] digest = "1:78229b46ddb7434f881390029bd1af7661294af31f6802e0e1bedaad4ab0af3c" name = "github.com/mattn/go-isatty" @@ -255,6 +271,7 @@ analyzer-name = "dep" analyzer-version = 1 input-imports = [ + "github.com/fatih/color", "github.com/go-logfmt/logfmt", "github.com/go-yaml/yaml", "github.com/golang/protobuf/proto", diff --git a/Gopkg.toml b/Gopkg.toml index 0e74efb..ecb2919 100644 --- a/Gopkg.toml +++ b/Gopkg.toml @@ -66,4 +66,7 @@ ignored = [ "github.com/inconshreveable/mousetrap" ] [[constraint]] name = "github.com/nsf/termbox-go" - branch = "master" \ No newline at end of file + branch = "master" +[[constraint]] + name = "github.com/fatih/color" + version = "1.7.0" diff --git a/config/config.go b/config/config.go index 2d618cf..93a7a29 100644 --- a/config/config.go +++ b/config/config.go @@ -197,6 +197,7 @@ type LoggingOutletCommon struct { type StdoutLoggingOutlet struct { LoggingOutletCommon `yaml:",inline"` Time bool `yaml:"time,default=true"` + Color bool `yaml:"color,default=true""` } type SyslogLoggingOutlet struct { diff --git a/daemon/logging/build_logging.go b/daemon/logging/build_logging.go index c6bea78..9d88d41 100644 --- a/daemon/logging/build_logging.go +++ b/daemon/logging/build_logging.go @@ -8,12 +8,12 @@ import ( "github.com/pkg/errors" "github.com/problame/go-streamrpc" "github.com/zrepl/zrepl/config" + "github.com/zrepl/zrepl/daemon/pruner" "github.com/zrepl/zrepl/endpoint" "github.com/zrepl/zrepl/logger" "github.com/zrepl/zrepl/replication" "github.com/zrepl/zrepl/tlsconf" "os" - "github.com/zrepl/zrepl/daemon/pruner" ) 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 { flags &= ^MetadataTime } + if isatty.IsTerminal(writer.Fd()) && !in.Color { + flags &= ^MetadataColor + } formatter.SetMetadataFlags(flags) return WriterOutlet{ diff --git a/daemon/logging/logging_formatters.go b/daemon/logging/logging_formatters.go index de79ee0..3f3a7a8 100644 --- a/daemon/logging/logging_formatters.go +++ b/daemon/logging/logging_formatters.go @@ -4,6 +4,7 @@ import ( "bytes" "encoding/json" "fmt" + "github.com/fatih/color" "github.com/go-logfmt/logfmt" "github.com/pkg/errors" "github.com/zrepl/zrepl/logger" @@ -26,6 +27,7 @@ type MetadataFlags int64 const ( MetadataTime MetadataFlags = 1 << iota MetadataLevel + MetadataColor MetadataNone 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) { var line bytes.Buffer + col := color.New() + if f.metadataFlags&MetadataColor != 0 { + col = e.Color() + } if f.metadataFlags&MetadataTime != 0 { fmt.Fprintf(&line, "%s ", e.Time.Format(HumanFormatterDateFormat)) } 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} @@ -85,7 +91,7 @@ func (f *HumanFormatter) Format(e *logger.Entry) (out []byte, err error) { continue } if !f.ignored(field) { - fmt.Fprintf(&line, "[%s]", val) + fmt.Fprintf(&line, "[%s]", col.Sprint(val)) prefixed[field] = true } } @@ -96,15 +102,11 @@ func (f *HumanFormatter) Format(e *logger.Entry) (out []byte, err error) { fmt.Fprint(&line, e.Message) if len(e.Fields)-len(prefixed) > 0 { - fmt.Fprint(&line, " ") - enc := logfmt.NewEncoder(&line) for field, value := range e.Fields { if prefixed[field] || f.ignored(field) { continue } - if err := logfmtTryEncodeKeyval(enc, field, value); err != nil { - return nil, err - } + fmt.Fprintf(&line, " %s=%q", col.Sprint(field), fmt.Sprint(value)) } } diff --git a/logger/datastructures.go b/logger/datastructures.go index d6460ee..782c8e9 100644 --- a/logger/datastructures.go +++ b/logger/datastructures.go @@ -4,6 +4,7 @@ import ( "bytes" "encoding/json" "fmt" + "github.com/fatih/color" "github.com/pkg/errors" "sync" "time" @@ -105,6 +106,21 @@ type Entry struct { 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. type Outlet interface { // Write the entry to the destination.