Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix log stdlibadapter when prefixed #1036

Merged
merged 4 commits into from Nov 25, 2020
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
46 changes: 43 additions & 3 deletions log/stdlib.go
@@ -1,6 +1,7 @@
package log

import (
"bytes"
"io"
"log"
"regexp"
Expand All @@ -26,9 +27,11 @@ func (w StdlibWriter) Write(p []byte) (int, error) {
// messages, and place them under relevant keys.
type StdlibAdapter struct {
Logger
timestampKey string
fileKey string
messageKey string
peterbourgon marked this conversation as resolved.
Show resolved Hide resolved
timestampKey string
fileKey string
messageKey string
prefix string
joinPrefixToMsg bool
}

// StdlibAdapterOption sets a parameter for the StdlibAdapter.
Expand All @@ -49,6 +52,21 @@ func MessageKey(key string) StdlibAdapterOption {
return func(a *StdlibAdapter) { a.messageKey = key }
}

// Prefix sets value of the prefix for the actual log message. By default,
// there's no prefix.
//
// When you create a stdlib Logger, you can define a log prefix like this:
//
// logger := log.New(w, "some prefix", log.LstdFlags)
//
// To correctly extract stdlib logger fields, you should set the same prefix
// by Prefix stdlib adapter option. Also you can set joinPrefixToMsg if you need
// to join the prefix to extracted message fields. For example, you can need it
// when using log.Lmsgprefix flag.
peterbourgon marked this conversation as resolved.
Show resolved Hide resolved
func Prefix(prefix string, joinPrefixToMsg bool) StdlibAdapterOption {
return func(a *StdlibAdapter) { a.prefix = prefix; a.joinPrefixToMsg = joinPrefixToMsg }
}

// NewStdlibAdapter returns a new StdlibAdapter wrapper around the passed
// logger. It's designed to be passed to log.SetOutput.
func NewStdlibAdapter(logger Logger, options ...StdlibAdapterOption) io.Writer {
Expand All @@ -65,6 +83,8 @@ func NewStdlibAdapter(logger Logger, options ...StdlibAdapterOption) io.Writer {
}

func (a StdlibAdapter) Write(p []byte) (int, error) {
p = a.handlePrefix(p)

result := subexps(p)
keyvals := []interface{}{}
var timestamp string
Expand All @@ -84,6 +104,7 @@ func (a StdlibAdapter) Write(p []byte) (int, error) {
keyvals = append(keyvals, a.fileKey, file)
}
if msg, ok := result["msg"]; ok {
msg = a.handleMessagePrefix(msg)
keyvals = append(keyvals, a.messageKey, msg)
}
if err := a.Logger.Log(keyvals...); err != nil {
Expand All @@ -92,6 +113,25 @@ func (a StdlibAdapter) Write(p []byte) (int, error) {
return len(p), nil
}

func (a StdlibAdapter) handlePrefix(p []byte) []byte {
if a.prefix != "" {
p = bytes.TrimPrefix(p, []byte(a.prefix))
}
return p
}

func (a StdlibAdapter) handleMessagePrefix(msg string) string {
if a.prefix == "" {
return msg
}

msg = strings.TrimPrefix(msg, a.prefix)
if a.joinPrefixToMsg {
msg = a.prefix + msg
}
return msg
}

const (
logRegexpDate = `(?P<date>[0-9]{4}/[0-9]{2}/[0-9]{2})?[ ]?`
logRegexpTime = `(?P<time>[0-9]{2}:[0-9]{2}:[0-9]{2}(\.[0-9]+)?)?[ ]?`
Expand Down
50 changes: 50 additions & 0 deletions log/stdlib_test.go
Expand Up @@ -72,6 +72,56 @@ func TestStdLibAdapterExtraction(t *testing.T) {
}
peterbourgon marked this conversation as resolved.
Show resolved Hide resolved
}

func TestStdLibAdapterPrefixedExtraction(t *testing.T) {
buf := &bytes.Buffer{}
logger := NewLogfmtLogger(buf)
writer := NewStdlibAdapter(logger, Prefix("some prefix ", false))
for input, want := range map[string]string{
"some prefix hello": "msg=hello\n",
"some prefix 2009/01/23: hello": "ts=2009/01/23 msg=hello\n",
"some prefix 2009/01/23 01:23:23: hello": "ts=\"2009/01/23 01:23:23\" msg=hello\n",
"some prefix 01:23:23: hello": "ts=01:23:23 msg=hello\n",
"some prefix 2009/01/23 01:23:23.123123: hello": "ts=\"2009/01/23 01:23:23.123123\" msg=hello\n",
"some prefix 2009/01/23 01:23:23.123123 /a/b/c/d.go:23: hello": "ts=\"2009/01/23 01:23:23.123123\" caller=/a/b/c/d.go:23 msg=hello\n",
"some prefix 01:23:23.123123 /a/b/c/d.go:23: hello": "ts=01:23:23.123123 caller=/a/b/c/d.go:23 msg=hello\n",
"some prefix 2009/01/23 01:23:23 /a/b/c/d.go:23: hello": "ts=\"2009/01/23 01:23:23\" caller=/a/b/c/d.go:23 msg=hello\n",
"some prefix 2009/01/23 /a/b/c/d.go:23: hello": "ts=2009/01/23 caller=/a/b/c/d.go:23 msg=hello\n",
"some prefix /a/b/c/d.go:23: hello": "caller=/a/b/c/d.go:23 msg=hello\n",
"/a/b/c/d.go:23: some prefix hello": "caller=/a/b/c/d.go:23 msg=hello\n",
} {
buf.Reset()
fmt.Fprint(writer, input)
if have := buf.String(); want != have {
t.Errorf("%q: want %#v, have %#v", input, want, have)
}
}
}

func TestStdLibAdapterPrefixedExtractionWithJoinToMessage(t *testing.T) {
buf := &bytes.Buffer{}
logger := NewLogfmtLogger(buf)
writer := NewStdlibAdapter(logger, Prefix("some prefix ", true))
for input, want := range map[string]string{
"some prefix hello": "msg=\"some prefix hello\"\n",
"some prefix 2009/01/23: hello": "ts=2009/01/23 msg=\"some prefix hello\"\n",
"some prefix 2009/01/23 01:23:23: hello": "ts=\"2009/01/23 01:23:23\" msg=\"some prefix hello\"\n",
"some prefix 01:23:23: hello": "ts=01:23:23 msg=\"some prefix hello\"\n",
"some prefix 2009/01/23 01:23:23.123123: hello": "ts=\"2009/01/23 01:23:23.123123\" msg=\"some prefix hello\"\n",
"some prefix 2009/01/23 01:23:23.123123 /a/b/c/d.go:23: hello": "ts=\"2009/01/23 01:23:23.123123\" caller=/a/b/c/d.go:23 msg=\"some prefix hello\"\n",
"some prefix 01:23:23.123123 /a/b/c/d.go:23: hello": "ts=01:23:23.123123 caller=/a/b/c/d.go:23 msg=\"some prefix hello\"\n",
"some prefix 2009/01/23 01:23:23 /a/b/c/d.go:23: hello": "ts=\"2009/01/23 01:23:23\" caller=/a/b/c/d.go:23 msg=\"some prefix hello\"\n",
"some prefix 2009/01/23 /a/b/c/d.go:23: hello": "ts=2009/01/23 caller=/a/b/c/d.go:23 msg=\"some prefix hello\"\n",
"some prefix /a/b/c/d.go:23: hello": "caller=/a/b/c/d.go:23 msg=\"some prefix hello\"\n",
"/a/b/c/d.go:23: some prefix hello": "caller=/a/b/c/d.go:23 msg=\"some prefix hello\"\n",
} {
buf.Reset()
fmt.Fprint(writer, input)
if have := buf.String(); want != have {
t.Errorf("%q: want %#v, have %#v", input, want, have)
}
}
}

func TestStdlibAdapterSubexps(t *testing.T) {
for input, wantMap := range map[string]map[string]string{
"hello world": {
Expand Down