diff --git a/log/json_logger.go b/log/json_logger.go index 66094b4dd..1886d5374 100644 --- a/log/json_logger.go +++ b/log/json_logger.go @@ -10,14 +10,29 @@ import ( type jsonLogger struct { io.Writer + escapeHTML bool } // NewJSONLogger returns a Logger that encodes keyvals to the Writer as a // single JSON object. Each log event produces no more than one call to // w.Write. The passed Writer must be safe for concurrent use by multiple // goroutines if the returned Logger will be used concurrently. -func NewJSONLogger(w io.Writer) Logger { - return &jsonLogger{w} +func NewJSONLogger(w io.Writer, options ...JSONLoggerOption) Logger { + l := &jsonLogger{ + Writer: w, + } + for _, option := range options { + option(l) + } + return l +} + +// JSONLoggerOption sets a parameter for json logger +type JSONLoggerOption func(*jsonLogger) + +// SetEscapeHTML escape &, <, > inside JSON quoted strings. +func SetEscapeHTML(v bool) JSONLoggerOption { + return func(j *jsonLogger) { j.escapeHTML = v } } func (l *jsonLogger) Log(keyvals ...interface{}) error { @@ -31,7 +46,9 @@ func (l *jsonLogger) Log(keyvals ...interface{}) error { } merge(m, k, v) } - return json.NewEncoder(l.Writer).Encode(m) + enc := json.NewEncoder(l.Writer) + enc.SetEscapeHTML(l.escapeHTML) + return enc.Encode(m) } func merge(dst map[string]interface{}, k, v interface{}) { diff --git a/log/json_logger_test.go b/log/json_logger_test.go index e3e309090..bae8c5f1b 100644 --- a/log/json_logger_test.go +++ b/log/json_logger_test.go @@ -73,6 +73,26 @@ func TestJSONLoggerNilErrorValue(t *testing.T) { } } +func TestJSONLoggerWithSetHTMLEscapeOption(t *testing.T) { + t.Parallel() + + buf := &bytes.Buffer{} + for b, want := range map[bool]string{ + false: `{"a":"<&>"}` + "\n", + true: `{"a":"\u003c\u0026\u003e"}` + "\n", + } { + buf.Reset() + logger := log.NewJSONLogger(buf, log.SetEscapeHTML(b)) + if err := logger.Log("a", "<&>"); err != nil { + t.Fatal(err) + } + if have := buf.String(); want != have { + t.Errorf("\nwant %#v\nhave %#v", want, have) + } + } + +} + // aller implements json.Marshaler, encoding.TextMarshaler, and fmt.Stringer. type aller struct{}