Skip to content

Commit a0601e6

Browse files
author
Evan Phoenix
authored
Merge pull request #87 from hashicorp/b-multiline-improve
Improve rendering of empty strings and multiline values
2 parents c2b3341 + c102b1c commit a0601e6

File tree

3 files changed

+70
-17
lines changed

3 files changed

+70
-17
lines changed

interceptlogger_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -234,7 +234,7 @@ func TestInterceptLogger(t *testing.T) {
234234
output := buf.String()
235235
dataIdx := strings.IndexByte(output, ' ')
236236
rest := output[dataIdx+1:]
237-
assert.Equal(t, "[DEBUG] with_test.sub_logger.http: test1: parent=logger path=/some/test/path args=[test, test]\n", rest)
237+
assert.Equal(t, "[DEBUG] with_test.sub_logger.http: test1: parent=logger path=/some/test/path args=[\"test\", \"test\"]\n", rest)
238238
})
239239

240240
t.Run("derived standard loggers send output to sinks", func(t *testing.T) {

intlogger.go

Lines changed: 44 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -261,6 +261,9 @@ func (l *intLogger) logPlain(t time.Time, name string, level Level, msg string,
261261
switch st := args[i+1].(type) {
262262
case string:
263263
val = st
264+
if st == "" {
265+
val = `""`
266+
}
264267
case int:
265268
val = strconv.FormatInt(int64(st), 10)
266269
case int64:
@@ -302,20 +305,32 @@ func (l *intLogger) logPlain(t time.Time, name string, level Level, msg string,
302305
}
303306
}
304307

305-
l.writer.WriteByte(' ')
308+
var key string
309+
306310
switch st := args[i].(type) {
307311
case string:
308-
l.writer.WriteString(st)
312+
key = st
309313
default:
310-
l.writer.WriteString(fmt.Sprintf("%s", st))
314+
key = fmt.Sprintf("%s", st)
311315
}
312-
l.writer.WriteByte('=')
313316

314-
if !raw && strings.ContainsAny(val, " \t\n\r") {
317+
if strings.Contains(val, "\n") {
318+
l.writer.WriteString("\n ")
319+
l.writer.WriteString(key)
320+
l.writer.WriteString("=\n")
321+
writeIndent(l.writer, val, " | ")
322+
l.writer.WriteString(" ")
323+
} else if !raw && strings.ContainsAny(val, " \t") {
324+
l.writer.WriteByte(' ')
325+
l.writer.WriteString(key)
326+
l.writer.WriteByte('=')
315327
l.writer.WriteByte('"')
316328
l.writer.WriteString(val)
317329
l.writer.WriteByte('"')
318330
} else {
331+
l.writer.WriteByte(' ')
332+
l.writer.WriteString(key)
333+
l.writer.WriteByte('=')
319334
l.writer.WriteString(val)
320335
}
321336
}
@@ -329,6 +344,25 @@ func (l *intLogger) logPlain(t time.Time, name string, level Level, msg string,
329344
}
330345
}
331346

347+
func writeIndent(w *writer, str string, indent string) {
348+
for {
349+
nl := strings.IndexByte(str, "\n"[0])
350+
if nl == -1 {
351+
if str != "" {
352+
w.WriteString(indent)
353+
w.WriteString(str)
354+
w.WriteString("\n")
355+
}
356+
return
357+
}
358+
359+
w.WriteString(indent)
360+
w.WriteString(str[:nl])
361+
w.WriteString("\n")
362+
str = str[nl+1:]
363+
}
364+
}
365+
332366
func (l *intLogger) renderSlice(v reflect.Value) string {
333367
var buf bytes.Buffer
334368

@@ -345,22 +379,19 @@ func (l *intLogger) renderSlice(v reflect.Value) string {
345379

346380
switch sv.Kind() {
347381
case reflect.String:
348-
val = sv.String()
382+
val = strconv.Quote(sv.String())
349383
case reflect.Int, reflect.Int16, reflect.Int32, reflect.Int64:
350384
val = strconv.FormatInt(sv.Int(), 10)
351385
case reflect.Uint, reflect.Uint16, reflect.Uint32, reflect.Uint64:
352386
val = strconv.FormatUint(sv.Uint(), 10)
353387
default:
354388
val = fmt.Sprintf("%v", sv.Interface())
389+
if strings.ContainsAny(val, " \t\n\r") {
390+
val = strconv.Quote(val)
391+
}
355392
}
356393

357-
if strings.ContainsAny(val, " \t\n\r") {
358-
buf.WriteByte('"')
359-
buf.WriteString(val)
360-
buf.WriteByte('"')
361-
} else {
362-
buf.WriteString(val)
363-
}
394+
buf.WriteString(val)
364395
}
365396

366397
buf.WriteRune(']')

logger_test.go

Lines changed: 25 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,7 @@ func TestLogger(t *testing.T) {
8686
assert.Equal(t, "[INFO] test: this is test: who=programmer why=[testing, dev, 1, 5, \"[3 4]\"]\n", rest)
8787
})
8888

89-
t.Run("renders values in slices with quotes if needed", func(t *testing.T) {
89+
t.Run("renders values in slices with quotes", func(t *testing.T) {
9090
var buf bytes.Buffer
9191

9292
logger := New(&LoggerOptions{
@@ -100,7 +100,29 @@ func TestLogger(t *testing.T) {
100100
dataIdx := strings.IndexByte(str, ' ')
101101
rest := str[dataIdx+1:]
102102

103-
assert.Equal(t, "[INFO] test: this is test: who=programmer why=[\"testing & qa\", dev]\n", rest)
103+
assert.Equal(t, "[INFO] test: this is test: who=programmer why=[\"testing & qa\", \"dev\"]\n", rest)
104+
})
105+
106+
t.Run("formats multiline values nicely", func(t *testing.T) {
107+
var buf bytes.Buffer
108+
109+
logger := New(&LoggerOptions{
110+
Name: "test",
111+
Output: &buf,
112+
})
113+
114+
logger.Info("this is test", "who", "programmer", "why", "testing\nand other\npretty cool things")
115+
116+
str := buf.String()
117+
dataIdx := strings.IndexByte(str, ' ')
118+
rest := str[dataIdx+1:]
119+
120+
expected := `[INFO] test: this is test: who=programmer
121+
why=
122+
| testing
123+
| and other
124+
| pretty cool things` + "\n \n"
125+
assert.Equal(t, expected, rest)
104126
})
105127

106128
t.Run("outputs stack traces", func(t *testing.T) {
@@ -151,7 +173,7 @@ func TestLogger(t *testing.T) {
151173
rest := str[dataIdx+1:]
152174

153175
// This test will break if you move this around, it's line dependent, just fyi
154-
assert.Equal(t, "[INFO] go-hclog/logger_test.go:147: test: this is test: who=programmer why=\"testing is fun\"\n", rest)
176+
assert.Equal(t, "[INFO] go-hclog/logger_test.go:169: test: this is test: who=programmer why=\"testing is fun\"\n", rest)
155177
})
156178

157179
t.Run("prefixes the name", func(t *testing.T) {

0 commit comments

Comments
 (0)