common/loggers: Add color to ERROR and WARN
authorBjørn Erik Pedersen <bjorn.erik.pedersen@gmail.com>
Wed, 24 Oct 2018 16:32:30 +0000 (18:32 +0200)
committerBjørn Erik Pedersen <bjorn.erik.pedersen@gmail.com>
Sun, 28 Oct 2018 13:16:23 +0000 (14:16 +0100)
Fixes #4414

common/loggers/loggers.go
common/loggers/loggers_test.go [new file with mode: 0644]
common/terminal/colors.go

index 428a9f79c00beb6e1d649ccb659d758a689ff500..37f50a6c041999accaf70574ea0c369af6fedf0b 100644 (file)
@@ -80,7 +80,10 @@ func NewErrorLogger() *Logger {
        return newBasicLogger(jww.LevelError)
 }
 
-var ansiColorRe = regexp.MustCompile("(?s)\\033\\[\\d*(;\\d*)*m")
+var (
+       ansiColorRe = regexp.MustCompile("(?s)\\033\\[\\d*(;\\d*)*m")
+       errorRe     = regexp.MustCompile("(ERROR|FATAL|WARN)")
+)
 
 type ansiCleaner struct {
        w io.Writer
@@ -90,12 +93,40 @@ func (a ansiCleaner) Write(p []byte) (n int, err error) {
        return a.w.Write(ansiColorRe.ReplaceAll(p, []byte("")))
 }
 
+type labelColorizer struct {
+       w io.Writer
+}
+
+func (a labelColorizer) Write(p []byte) (n int, err error) {
+       replaced := errorRe.ReplaceAllStringFunc(string(p), func(m string) string {
+               switch m {
+               case "ERROR", "FATAL":
+                       return terminal.Error(m)
+               case "WARN":
+                       return terminal.Warning(m)
+               default:
+                       return m
+               }
+       })
+       // io.MultiWriter will abort if we return a bigger write count than input
+       // bytes, so we lie a little.
+       _, err = a.w.Write([]byte(replaced))
+       return len(p), err
+
+}
+
 func newLogger(stdoutThreshold, logThreshold jww.Threshold, outHandle, logHandle io.Writer, saveErrors bool) *Logger {
+       isTerm := terminal.IsTerminal(os.Stdout)
        errorCounter := &jww.Counter{}
-       if logHandle != ioutil.Discard && terminal.IsTerminal(os.Stdout) {
+       if logHandle != ioutil.Discard && isTerm {
                // Remove any Ansi coloring from log output
                logHandle = ansiCleaner{w: logHandle}
        }
+
+       if isTerm {
+               outHandle = labelColorizer{w: outHandle}
+       }
+
        listeners := []jww.LogListener{jww.LogCounter(errorCounter, jww.LevelError)}
        var errorBuff *bytes.Buffer
        if saveErrors {
diff --git a/common/loggers/loggers_test.go b/common/loggers/loggers_test.go
new file mode 100644 (file)
index 0000000..3737ddc
--- /dev/null
@@ -0,0 +1,32 @@
+// Copyright 2018 The Hugo Authors. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package loggers
+
+import (
+       "testing"
+
+       "github.com/stretchr/testify/require"
+)
+
+func TestLogger(t *testing.T) {
+       assert := require.New(t)
+       l := NewWarningLogger()
+
+       l.ERROR.Println("One error")
+       l.ERROR.Println("Two error")
+       l.WARN.Println("A warning")
+
+       assert.Equal(uint64(2), l.ErrorCounter.Count())
+
+}
index 691173ea8104a752f0acc6ce32f5c002da978586..a02d016d9837af9f803d1b519e5fa3e963129cbb 100644 (file)
@@ -23,7 +23,9 @@ import (
 )
 
 const (
-       noticeColor = "\033[1;36m%s\033[0m"
+       errorColor   = "\033[1;31m%s\033[0m"
+       warningColor = "\033[0;33m%s\033[0m"
+       noticeColor  = "\033[1;36m%s\033[0m"
 )
 
 // IsTerminal return true if the file descriptor is terminal and the TERM
@@ -38,6 +40,16 @@ func Notice(s string) string {
        return colorize(s, noticeColor)
 }
 
+// Error colorizes the string in a colour that grabs attention.
+func Error(s string) string {
+       return colorize(s, errorColor)
+}
+
+// Warning colorizes the string in a colour that warns.
+func Warning(s string) string {
+       return colorize(s, warningColor)
+}
+
 // colorize s in color.
 func colorize(s, color string) string {
        s = fmt.Sprintf(color, doublePercent(s))