Просмотр исходного кода

lib/logger: Strip control characters from log output (fixes #5428) (#5434)

Jakob Borg 7 лет назад
Родитель
Сommit
5503175854
2 измененных файлов с 62 добавлено и 1 удалено
  1. 21 1
      lib/logger/logger.go
  2. 41 0
      lib/logger/logger_test.go

+ 21 - 1
lib/logger/logger.go

@@ -70,7 +70,7 @@ type logger struct {
 var DefaultLogger = New()
 
 func New() Logger {
-	return newLogger(os.Stdout)
+	return newLogger(controlStripper{os.Stdout})
 }
 
 func newLogger(w io.Writer) Logger {
@@ -376,3 +376,23 @@ func (r *recorder) append(l LogLevel, msg string) {
 		r.lines = append(r.lines, Line{time.Now(), "...", l})
 	}
 }
+
+// controlStripper is a Writer that replaces control characters
+// with spaces.
+type controlStripper struct {
+	io.Writer
+}
+
+func (s controlStripper) Write(data []byte) (int, error) {
+	for i, b := range data {
+		if b == '\n' || b == '\r' {
+			// Newlines are OK
+			continue
+		}
+		if b < 32 {
+			// Characters below 32 are control characters
+			data[i] = ' '
+		}
+	}
+	return s.Writer.Write(data)
+}

+ 41 - 0
lib/logger/logger_test.go

@@ -6,6 +6,7 @@ package logger
 import (
 	"bytes"
 	"fmt"
+	"io/ioutil"
 	"log"
 	"strings"
 	"testing"
@@ -166,3 +167,43 @@ func TestStackLevel(t *testing.T) {
 		t.Error("Should identify this file as the source (bad level?)")
 	}
 }
+
+func TestControlStripper(t *testing.T) {
+	b := new(bytes.Buffer)
+	l := newLogger(controlStripper{b})
+
+	l.Infoln("testing\x07testing\ntesting")
+	res := b.String()
+
+	if !strings.Contains(res, "testing testing\ntesting") {
+		t.Logf("%q", res)
+		t.Error("Control character should become space")
+	}
+	if strings.Contains(res, "\x07") {
+		t.Logf("%q", res)
+		t.Error("Control character should be removed")
+	}
+}
+
+func BenchmarkLog(b *testing.B) {
+	l := newLogger(controlStripper{ioutil.Discard})
+	benchmarkLogger(b, l)
+}
+
+func BenchmarkLogNoStripper(b *testing.B) {
+	l := newLogger(ioutil.Discard)
+	benchmarkLogger(b, l)
+}
+
+func benchmarkLogger(b *testing.B, l Logger) {
+	l.SetFlags(log.Lshortfile | log.Lmicroseconds)
+	l.SetPrefix("ABCDEFG")
+
+	for i := 0; i < b.N; i++ {
+		l.Infoln("This is a somewhat representative log line")
+		l.Infof("This is a log line with a couple of formatted things: %d %q", 42, "a file name maybe, who knows?")
+	}
+
+	b.ReportAllocs()
+	b.SetBytes(2) // log entries per iteration
+}