shithub: hugo

Download patch

ref: 1c7b7b4ef293aa133e5b55f3ebb2d37d8839532f
parent: 1ad117cbe2903aa9d029f90750acf633eb2a51a2
author: Bjørn Erik Pedersen <[email protected]>
date: Wed Oct 24 14:32:30 EDT 2018

common/loggers: Add color to ERROR and WARN

Fixes #4414

--- a/common/loggers/loggers.go
+++ b/common/loggers/loggers.go
@@ -80,7 +80,10 @@
 	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 @@
 	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 {
--- /dev/null
+++ b/common/loggers/loggers_test.go
@@ -1,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())
+
+}
--- a/common/terminal/colors.go
+++ b/common/terminal/colors.go
@@ -23,7 +23,9 @@
 )
 
 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
@@ -36,6 +38,16 @@
 // Notice colorizes the string in a noticeable color.
 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.