Open kevinburke opened 8 years ago
cc @ChrisHines
Benchmarks also fail to complete:
goroutine 15 [running]:
panic(0x1a7680, 0xc4200145b0)
/Users/kevin/go/src/runtime/panic.go:500 +0x1a1
github.com/inconshreveable/log15.logfmt(0xc420058070, 0xc42002bde8, 0x6, 0x6, 0x0)
/Users/kevin/code/go/src/github.com/inconshreveable/log15/format.go:100 +0x128
github.com/inconshreveable/log15.LogfmtFormat.func1(0xc420096000, 0x19a500, 0x576a1401, 0x2db9e8)
/Users/kevin/code/go/src/github.com/inconshreveable/log15/format.go:92 +0x2ee
github.com/inconshreveable/log15.formatFunc.Format(0x1f1ac0, 0xc420096000, 0x2c1460, 0x3dff7, 0x2c87b8)
/Users/kevin/code/go/src/github.com/inconshreveable/log15/format.go:35 +0x30
github.com/inconshreveable/log15.BenchmarkLogfmtNoCtx(0xc4200aa140)
/Users/kevin/code/go/src/github.com/inconshreveable/log15/bench_test.go:58 +0x15f
testing.(*B).runN(0xc4200aa140, 0x1)
/Users/kevin/go/src/testing/benchmark.go:139 +0xaa
testing.(*B).run1.func1(0xc4200aa140)
/Users/kevin/go/src/testing/benchmark.go:208 +0x5a
created by testing.(*B).run1
/Users/kevin/go/src/testing/benchmark.go:209 +0x7f
exit status 2
The four benchmarks that ran didn't show much better perf, but they might not be representative :(
Master:
BenchmarkStreamNoCtx-4 500000 3537 ns/op
BenchmarkDiscard-4 2000000 819 ns/op
BenchmarkCallerFileHandler-4 1000000 1925 ns/op
BenchmarkCallerFuncHandler-4 1000000 1700 ns/op
Best run on the branch:
BenchmarkStreamNoCtx-4 300000 3881 ns/op
BenchmarkDiscard-4 2000000 837 ns/op
BenchmarkCallerFileHandler-4 1000000 1910 ns/op
BenchmarkCallerFuncHandler-4 1000000 1680 ns/op
To help performance you'll likely want to use a sync.Pool
of logfmt.Encoder
s similar to what we recently added in https://github.com/go-kit/kit/pull/253.
The use of "null" instead of "nil" for nil
values is intentionally modeled after JSON. Since values are escaped with the same logic as JSON strings it seems natural to do the same for empty values. There is no official logfmt spec, but I leaned heavily on the parsing behavior of github.com/kr/logfmt and the discussion here https://gist.github.com/kr/0e8d5ee4b954ce604bb2. The latter is where you will see examples of "null" values.
github.com/go-logfmt/logfmt
checks for values that implement encoding/TextMarshaler
first and then fmt.Stringer
, so time.Time
values get formatted by their MarshalText
method which uses the time.RFC3339Nano
format. A different format can be used by wrapping time.Time
values in a type that implements MarshalText
the way you want or by formatting the time.Time
to a string before passing it to EncodeKeyvals
.
What was the error message for the benchmark panic? I am having trouble figuring out what happened from the stack trace alone.
@ChrisHines sorry - it's complaining that this leads to an invalid key:
r := Record{
Time: time.Now(),
Lvl: LvlInfo,
Msg: "test message",
Ctx: []interface{}{},
}
logfmt := LogfmtFormat()
for i := 0; i < b.N; i++ {
logfmt.Format(&r)
}
I suppose I can edit the code to not attempt to encode an empty array.
Er, never mind, it's complaining because the key is the empty string:
encoding []interface {}{"", time.Time{sec:63602209626, nsec:716296270, loc:(*time.Location)(0x2c1460)}, "", 3, "", "test message"}
panic: invalid key
The other thing I think the old way supported was putting ANSI escape sequences in. I suppose we can hide the go-logfmt/logfmt
call in one side of this conditional:
// XXX: we should probably check that all of your key bytes aren't invalid
if color > 0 {
fmt.Fprintf(buf, "\x1b[%dm%s\x1b[0m=%s", color, k, v)
} else {
buf.WriteString(k)
buf.WriteByte('=')
buf.WriteString(v)
}
Any chance we can put up a PR? Happy to help get this merged.
Where are we specifying an empty string key? It seems reasonable for go-logfmt to panic on that. I'm not a big fan of go-logfmt formatting time.Time to 9 decimal places, but that's a thing we can fix on our side. Yeah, we use ANSI escape sequences for color formatting in the terminal format, so we'll need to figure that out.
I much prefer nil
over null
because that's what we call it in Go, but I'm ambivalent. We could also normalize this before the call too.
I did some work to switch the
logfmt
code to use github.com/go-logfmt/logfmt. The following tests fail (usesnil
instead of null):and this one (formats the time.Time to 9 digits after the second, instead of to the second)
The diff is here: https://github.com/inconshreveable/log15/compare/master...kevinburke:use-logfmt?expand=1