Merge pull request #484 from bbrks/text-formatter-quote-config

Text formatter quote configuration
This commit is contained in:
Simon Eskildsen 2017-02-15 11:41:55 -05:00 committed by GitHub
commit 67bca5dc4f
2 changed files with 50 additions and 18 deletions

View File

@ -49,9 +49,26 @@ type TextFormatter struct {
// be desired.
DisableSorting bool
// QuoteEmptyFields will wrap empty fields in quotes if true
QuoteEmptyFields bool
// QuoteCharacter can be set to the override the default quoting character "
// with something else. For example: ', or `.
QuoteCharacter string
// Whether the logger's out is to a terminal
isTerminal bool
terminalOnce sync.Once
sync.Once
}
func (f *TextFormatter) init(entry *Entry) {
if len(f.QuoteCharacter) == 0 {
f.QuoteCharacter = "\""
}
if entry.Logger != nil {
f.isTerminal = IsTerminal(entry.Logger.Out)
}
}
func (f *TextFormatter) Format(entry *Entry) ([]byte, error) {
@ -72,11 +89,7 @@ func (f *TextFormatter) Format(entry *Entry) ([]byte, error) {
prefixFieldClashes(entry.Data)
f.terminalOnce.Do(func() {
if entry.Logger != nil {
f.isTerminal = IsTerminal(entry.Logger.Out)
}
})
f.Do(func() { f.init(entry) })
isColored := (f.ForceColors || f.isTerminal) && !f.DisableColors
@ -132,7 +145,10 @@ func (f *TextFormatter) printColored(b *bytes.Buffer, entry *Entry, keys []strin
}
}
func needsQuoting(text string) bool {
func (f *TextFormatter) needsQuoting(text string) bool {
if f.QuoteEmptyFields && len(text) == 0 {
return true
}
for _, ch := range text {
if !((ch >= 'a' && ch <= 'z') ||
(ch >= 'A' && ch <= 'Z') ||
@ -155,17 +171,17 @@ func (f *TextFormatter) appendKeyValue(b *bytes.Buffer, key string, value interf
func (f *TextFormatter) appendValue(b *bytes.Buffer, value interface{}) {
switch value := value.(type) {
case string:
if !needsQuoting(value) {
if !f.needsQuoting(value) {
b.WriteString(value)
} else {
fmt.Fprintf(b, "%q", value)
fmt.Fprintf(b, "%s%v%s", f.QuoteCharacter, value, f.QuoteCharacter)
}
case error:
errmsg := value.Error()
if !needsQuoting(errmsg) {
if !f.needsQuoting(errmsg) {
b.WriteString(errmsg)
} else {
fmt.Fprintf(b, "%q", errmsg)
fmt.Fprintf(b, "%s%v%s", f.QuoteCharacter, errmsg, f.QuoteCharacter)
}
default:
fmt.Fprint(b, value)

View File

@ -3,9 +3,9 @@ package logrus
import (
"bytes"
"errors"
"strings"
"testing"
"time"
"strings"
)
func TestQuoting(t *testing.T) {
@ -14,7 +14,7 @@ func TestQuoting(t *testing.T) {
checkQuoting := func(q bool, value interface{}) {
b, _ := tf.Format(WithField("test", value))
idx := bytes.Index(b, ([]byte)("test="))
cont := bytes.Contains(b[idx+5:], []byte{'"'})
cont := bytes.Contains(b[idx+5:], []byte(tf.QuoteCharacter))
if cont != q {
if q {
t.Errorf("quoting expected for: %#v", value)
@ -24,6 +24,7 @@ func TestQuoting(t *testing.T) {
}
}
checkQuoting(false, "")
checkQuoting(false, "abcd")
checkQuoting(false, "v1.0")
checkQuoting(false, "1234567890")
@ -32,6 +33,24 @@ func TestQuoting(t *testing.T) {
checkQuoting(true, "x,y")
checkQuoting(false, errors.New("invalid"))
checkQuoting(true, errors.New("invalid argument"))
// Test for custom quote character.
tf.QuoteCharacter = "`"
checkQuoting(false, "")
checkQuoting(false, "abcd")
checkQuoting(true, "/foobar")
checkQuoting(true, errors.New("invalid argument"))
// Test for multi-character quotes.
tf.QuoteCharacter = "§~±"
checkQuoting(false, "abcd")
checkQuoting(true, errors.New("invalid argument"))
// Test for quoting empty fields.
tf.QuoteEmptyFields = true
checkQuoting(true, "")
checkQuoting(false, "abcd")
checkQuoting(true, errors.New("invalid argument"))
}
func TestTimestampFormat(t *testing.T) {
@ -40,10 +59,7 @@ func TestTimestampFormat(t *testing.T) {
customStr, _ := customFormatter.Format(WithField("test", "test"))
timeStart := bytes.Index(customStr, ([]byte)("time="))
timeEnd := bytes.Index(customStr, ([]byte)("level="))
timeStr := customStr[timeStart+5 : timeEnd-1]
if timeStr[0] == '"' && timeStr[len(timeStr)-1] == '"' {
timeStr = timeStr[1 : len(timeStr)-1]
}
timeStr := customStr[timeStart+5+len(customFormatter.QuoteCharacter) : timeEnd-1-len(customFormatter.QuoteCharacter)]
if format == "" {
format = time.RFC3339
}