1
0
mirror of https://github.com/rs/zerolog synced 2026-06-08 17:13:30 +00:00

Compare commits

..

5 Commits

Author SHA1 Message Date
Olivier Poitrey 9f1f25d2fa pkgerrors: quick refactoring for better readibility 2019-01-02 17:07:20 -08:00
Olivier Poitrey 6d2153805b Revert change on go.mod 2019-01-02 17:02:58 -08:00
Olivier Poitrey 2988c1e444 pkgerrors: remove fmt dep 2019-01-02 13:19:14 -08:00
Olivier Poitrey adb19ff852 Merge branch 'master' into stacktrace 2019-01-02 12:11:57 -08:00
Olivier Poitrey 3786fbfa73 Add support for stack trace extration of error fields 2018-02-11 17:55:34 -08:00
20 changed files with 81 additions and 467 deletions
-2
View File
@@ -4,8 +4,6 @@ go:
- "1.8"
- "1.9"
- "1.10"
- "1.11"
- "1.12"
- "master"
matrix:
allow_failures:
+15 -18
View File
@@ -53,7 +53,7 @@ func main() {
// UNIX Time is faster and smaller than most timestamps
// If you set zerolog.TimeFieldFormat to an empty string,
// logs will write with UNIX time
zerolog.TimeFieldFormat = zerolog.TimeFormatUnix
zerolog.TimeFieldFormat = ""
log.Print("hello world")
}
@@ -76,20 +76,15 @@ import (
)
func main() {
zerolog.TimeFieldFormat = zerolog.TimeFormatUnix
zerolog.TimeFieldFormat = ""
log.Debug().
Str("Scale", "833 cents").
Float64("Interval", 833.09).
Msg("Fibonacci is everywhere")
log.Debug().
Str("Name", "Tom").
Send()
}
// Output: {"level":"debug","Scale":"833 cents","Interval":833.09,"time":1562212768,"message":"Fibonacci is everywhere"}
// Output: {"level":"debug","Name":"Tom","time":1562212768}
// Output: {"time":1524104936,"level":"debug","Scale":"833 cents","Interval":833.09,"message":"Fibonacci is everywhere"}
```
> You'll note in the above example that when adding contextual fields, the fields are strongly typed. You can find the full list of supported fields [here](#standard-types)
@@ -107,7 +102,7 @@ import (
)
func main() {
zerolog.TimeFieldFormat = zerolog.TimeFormatUnix
zerolog.TimeFieldFormat = ""
log.Info().Msg("hello world")
}
@@ -143,7 +138,7 @@ import (
)
func main() {
zerolog.TimeFieldFormat = zerolog.TimeFormatUnix
zerolog.TimeFieldFormat = ""
debug := flag.Bool("debug", false, "sets log level to debug")
flag.Parse()
@@ -194,7 +189,7 @@ import (
)
func main() {
zerolog.TimeFieldFormat = zerolog.TimeFormatUnix
zerolog.TimeFieldFormat = ""
log.Log().
Str("foo", "bar").
@@ -220,7 +215,7 @@ func main() {
err := errors.New("A repo man spends his life getting into tense situations")
service := "myservice"
zerolog.TimeFieldFormat = zerolog.TimeFormatUnix
zerolog.TimeFieldFormat = ""
log.Fatal().
Err(err).
@@ -479,10 +474,12 @@ Some settings can be changed and will by applied to all loggers:
* `zerolog.LevelFieldName`: Can be set to customize level field name.
* `zerolog.MessageFieldName`: Can be set to customize message field name.
* `zerolog.ErrorFieldName`: Can be set to customize `Err` field name.
* `zerolog.TimeFieldFormat`: Can be set to customize `Time` field value formatting. If set with `zerolog.TimeFormatUnix`, `zerolog.TimeFormatUnixMs` or `zerolog.TimeFormatUnixMicro`, times are formated as UNIX timestamp.
* `zerolog.DurationFieldUnit`: Can be set to customize the unit for time.Duration type fields added by `Dur` (default: `time.Millisecond`).
* `zerolog.DurationFieldInteger`: If set to `true`, `Dur` fields are formatted as integers instead of floats (default: `false`).
* `zerolog.ErrorHandler`: Called whenever zerolog fails to write an event on its output. If not set, an error is printed on the stderr. This handler must be thread safe and non-blocking.
* `zerolog.TimeFieldFormat`: Can be set to customize `Time` field value formatting. If set with an empty string, times are formated as UNIX timestamp.
// DurationFieldUnit defines the unit for time.Duration type fields added
// using the Dur method.
* `DurationFieldUnit`: Sets the unit of the fields added by `Dur` (default: `time.Millisecond`).
* `DurationFieldInteger`: If set to true, `Dur` fields are formatted as integers instead of floats.
* `ErrorHandler`: Called whenever zerolog fails to write an event on its output. If not set, an error is printed on the stderr. This handler must be thread safe and non-blocking.
## Field Types
@@ -581,7 +578,7 @@ Log a static string, without any context or `printf`-style templating:
## Caveats
Note that zerolog does no de-duplication of fields. Using the same key multiple times creates multiple keys in final JSON:
Note that zerolog does de-duplication fields. Using the same key multiple times creates multiple keys in final JSON:
```go
logger := zerolog.New(os.Stderr).With().Timestamp().Logger()
@@ -591,4 +588,4 @@ logger.Info().
// Output: {"level":"info","time":1494567715,"time":1494567715,"message":"dup"}
```
In this case, many consumers will take the last value, but this is not guaranteed; check yours if in doubt.
However, its not a big deal as JSON accepts dup keys; the last one prevails.
+1 -1
View File
@@ -234,7 +234,7 @@ func BenchmarkLogFieldType(b *testing.B) {
func BenchmarkContextFieldType(b *testing.B) {
oldFormat := TimeFieldFormat
TimeFieldFormat = TimeFormatUnix
TimeFieldFormat = ""
defer func() { TimeFieldFormat = oldFormat }()
bools := []bool{true, false, true, false, true, false, true, false, true, false}
ints := []int{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}
+10 -26
View File
@@ -13,6 +13,11 @@ import (
"time"
)
const (
colorBold = iota + 1
colorFaint
)
const (
colorBlack = iota + 30
colorRed
@@ -22,9 +27,6 @@ const (
colorMagenta
colorCyan
colorWhite
colorBold = 1
colorDarkGray = 90
)
var (
@@ -295,20 +297,9 @@ func consoleDefaultFormatTimestamp(timeFormat string, noColor bool) Formatter {
t = ts.Format(timeFormat)
}
case json.Number:
i, err := tt.Int64()
if err != nil {
t = tt.String()
} else {
var sec, nsec int64 = i, 0
if TimeFieldFormat == TimeFormatUnixMs {
nsec = int64(time.Duration(i) * time.Millisecond)
sec = 0
}
ts := time.Unix(sec, nsec).UTC()
t = ts.Format(timeFormat)
}
t = tt.String()
}
return colorize(t, colorDarkGray, noColor)
return colorize(t, colorFaint, noColor)
}
}
@@ -333,11 +324,7 @@ func consoleDefaultFormatLevel(noColor bool) Formatter {
l = colorize("???", colorBold, noColor)
}
} else {
if i == nil {
l = colorize("???", colorBold, noColor)
} else {
l = strings.ToUpper(fmt.Sprintf("%s", i))[0:3]
}
l = strings.ToUpper(fmt.Sprintf("%s", i))[0:3]
}
return l
}
@@ -355,22 +342,19 @@ func consoleDefaultFormatCaller(noColor bool) Formatter {
c = strings.TrimPrefix(c, cwd)
c = strings.TrimPrefix(c, "/")
}
c = colorize(c, colorBold, noColor) + colorize(" >", colorCyan, noColor)
c = colorize(c, colorBold, noColor) + colorize(" >", colorFaint, noColor)
}
return c
}
}
func consoleDefaultFormatMessage(i interface{}) string {
if i == nil {
return ""
}
return fmt.Sprintf("%s", i)
}
func consoleDefaultFormatFieldName(noColor bool) Formatter {
return func(i interface{}) string {
return colorize(fmt.Sprintf("%s=", i), colorCyan, noColor)
return colorize(fmt.Sprintf("%s=", i), colorFaint, noColor)
}
}
+10 -102
View File
@@ -76,7 +76,7 @@ func TestConsoleWriter(t *testing.T) {
buf := &bytes.Buffer{}
w := zerolog.ConsoleWriter{Out: buf, NoColor: true, PartsOrder: []string{"foo"}}
_, err := w.Write([]byte(`{"foo": "DEFAULT"}`))
_, err := w.Write([]byte(`{"foo" : "DEFAULT"}`))
if err != nil {
t.Errorf("Unexpected error when writing output: %s", err)
}
@@ -92,12 +92,12 @@ func TestConsoleWriter(t *testing.T) {
buf := &bytes.Buffer{}
w := zerolog.ConsoleWriter{Out: buf, NoColor: false}
_, err := w.Write([]byte(`{"level": "warn", "message": "Foobar"}`))
_, err := w.Write([]byte(`{"level" : "warn", "message" : "Foobar"}`))
if err != nil {
t.Errorf("Unexpected error when writing output: %s", err)
}
expectedOutput := "\x1b[90m<nil>\x1b[0m \x1b[31mWRN\x1b[0m Foobar\n"
expectedOutput := "\x1b[2m<nil>\x1b[0m \x1b[31mWRN\x1b[0m Foobar\n"
actualOutput := buf.String()
if actualOutput != expectedOutput {
t.Errorf("Unexpected output %q, want: %q", actualOutput, expectedOutput)
@@ -109,7 +109,7 @@ func TestConsoleWriter(t *testing.T) {
w := zerolog.ConsoleWriter{Out: buf, NoColor: true}
d := time.Unix(0, 0).UTC().Format(time.RFC3339)
_, err := w.Write([]byte(`{"time": "` + d + `", "level": "debug", "message": "Foobar", "foo": "bar"}`))
_, err := w.Write([]byte(`{"time" : "` + d + `", "level" : "debug", "message" : "Foobar", "foo" : "bar"}`))
if err != nil {
t.Errorf("Unexpected error when writing output: %s", err)
}
@@ -121,104 +121,12 @@ func TestConsoleWriter(t *testing.T) {
}
})
t.Run("Unix timestamp input format", func(t *testing.T) {
of := zerolog.TimeFieldFormat
defer func() {
zerolog.TimeFieldFormat = of
}()
zerolog.TimeFieldFormat = zerolog.TimeFormatUnix
buf := &bytes.Buffer{}
w := zerolog.ConsoleWriter{Out: buf, TimeFormat: time.StampMilli, NoColor: true}
_, err := w.Write([]byte(`{"time": 1234, "level": "debug", "message": "Foobar", "foo": "bar"}`))
if err != nil {
t.Errorf("Unexpected error when writing output: %s", err)
}
expectedOutput := "Jan 1 00:20:34.000 DBG Foobar foo=bar\n"
actualOutput := buf.String()
if actualOutput != expectedOutput {
t.Errorf("Unexpected output %q, want: %q", actualOutput, expectedOutput)
}
})
t.Run("Unix timestamp ms input format", func(t *testing.T) {
of := zerolog.TimeFieldFormat
defer func() {
zerolog.TimeFieldFormat = of
}()
zerolog.TimeFieldFormat = zerolog.TimeFormatUnixMs
buf := &bytes.Buffer{}
w := zerolog.ConsoleWriter{Out: buf, TimeFormat: time.StampMilli, NoColor: true}
_, err := w.Write([]byte(`{"time": 1234567, "level": "debug", "message": "Foobar", "foo": "bar"}`))
if err != nil {
t.Errorf("Unexpected error when writing output: %s", err)
}
expectedOutput := "Jan 1 00:20:34.567 DBG Foobar foo=bar\n"
actualOutput := buf.String()
if actualOutput != expectedOutput {
t.Errorf("Unexpected output %q, want: %q", actualOutput, expectedOutput)
}
})
t.Run("No message field", func(t *testing.T) {
buf := &bytes.Buffer{}
w := zerolog.ConsoleWriter{Out: buf, NoColor: true}
_, err := w.Write([]byte(`{"level": "debug", "foo": "bar"}`))
if err != nil {
t.Errorf("Unexpected error when writing output: %s", err)
}
expectedOutput := "<nil> DBG foo=bar\n"
actualOutput := buf.String()
if actualOutput != expectedOutput {
t.Errorf("Unexpected output %q, want: %q", actualOutput, expectedOutput)
}
})
t.Run("No level field", func(t *testing.T) {
buf := &bytes.Buffer{}
w := zerolog.ConsoleWriter{Out: buf, NoColor: true}
_, err := w.Write([]byte(`{"message": "Foobar", "foo": "bar"}`))
if err != nil {
t.Errorf("Unexpected error when writing output: %s", err)
}
expectedOutput := "<nil> ??? Foobar foo=bar\n"
actualOutput := buf.String()
if actualOutput != expectedOutput {
t.Errorf("Unexpected output %q, want: %q", actualOutput, expectedOutput)
}
})
t.Run("Write colorized fields", func(t *testing.T) {
buf := &bytes.Buffer{}
w := zerolog.ConsoleWriter{Out: buf, NoColor: false}
_, err := w.Write([]byte(`{"level": "warn", "message": "Foobar", "foo": "bar"}`))
if err != nil {
t.Errorf("Unexpected error when writing output: %s", err)
}
expectedOutput := "\x1b[90m<nil>\x1b[0m \x1b[31mWRN\x1b[0m Foobar \x1b[36mfoo=\x1b[0mbar\n"
actualOutput := buf.String()
if actualOutput != expectedOutput {
t.Errorf("Unexpected output %q, want: %q", actualOutput, expectedOutput)
}
})
t.Run("Write error field", func(t *testing.T) {
buf := &bytes.Buffer{}
w := zerolog.ConsoleWriter{Out: buf, NoColor: true}
d := time.Unix(0, 0).UTC().Format(time.RFC3339)
evt := `{"time": "` + d + `", "level": "error", "message": "Foobar", "aaa": "bbb", "error": "Error"}`
evt := `{"time" : "` + d + `", "level" : "error", "message" : "Foobar", "aaa" : "bbb", "error" : "Error"}`
// t.Log(evt)
_, err := w.Write([]byte(evt))
@@ -243,7 +151,7 @@ func TestConsoleWriter(t *testing.T) {
}
d := time.Unix(0, 0).UTC().Format(time.RFC3339)
evt := `{"time": "` + d + `", "level": "debug", "message": "Foobar", "foo": "bar", "caller": "` + cwd + `/foo/bar.go"}`
evt := `{"time" : "` + d + `", "level" : "debug", "message" : "Foobar", "foo" : "bar", "caller" : "` + cwd + `/foo/bar.go"}`
// t.Log(evt)
_, err = w.Write([]byte(evt))
@@ -262,7 +170,7 @@ func TestConsoleWriter(t *testing.T) {
buf := &bytes.Buffer{}
w := zerolog.ConsoleWriter{Out: buf, NoColor: true}
evt := `{"level": "debug", "message": "Foobar", "foo": [1, 2, 3], "bar": true}`
evt := `{"level" : "debug", "message" : "Foobar", "foo" : [1, 2, 3], "bar" : true}`
// t.Log(evt)
_, err := w.Write([]byte(evt))
@@ -284,7 +192,7 @@ func TestConsoleWriterConfiguration(t *testing.T) {
w := zerolog.ConsoleWriter{Out: buf, NoColor: true, TimeFormat: time.RFC3339}
d := time.Unix(0, 0).UTC().Format(time.RFC3339)
evt := `{"time": "` + d + `", "level": "info", "message": "Foobar"}`
evt := `{"time" : "` + d + `", "level" : "info", "message" : "Foobar"}`
_, err := w.Write([]byte(evt))
if err != nil {
@@ -302,7 +210,7 @@ func TestConsoleWriterConfiguration(t *testing.T) {
buf := &bytes.Buffer{}
w := zerolog.ConsoleWriter{Out: buf, NoColor: true, PartsOrder: []string{"message", "level"}}
evt := `{"level": "info", "message": "Foobar"}`
evt := `{"level" : "info", "message" : "Foobar"}`
_, err := w.Write([]byte(evt))
if err != nil {
t.Errorf("Unexpected error when writing output: %s", err)
@@ -320,7 +228,7 @@ func BenchmarkConsoleWriter(b *testing.B) {
b.ResetTimer()
b.ReportAllocs()
var msg = []byte(`{"level": "info", "foo": "bar", "message": "HELLO", "time": "1990-01-01"}`)
var msg = []byte(`{"level" : "info", "foo" : "bar", "message" : "HELLO", "time" : "1990-01-01"}`)
w := zerolog.ConsoleWriter{Out: ioutil.Discard, NoColor: false}
+4 -30
View File
@@ -2,7 +2,6 @@ package zerolog
import (
"io/ioutil"
"math"
"net"
"time"
)
@@ -348,31 +347,14 @@ func (c Context) Interface(key string, i interface{}) Context {
return c
}
type callerHook struct {
callerSkipFrameCount int
}
func newCallerHook(skipFrameCount int) callerHook {
return callerHook{callerSkipFrameCount: skipFrameCount}
}
type callerHook struct{}
func (ch callerHook) Run(e *Event, level Level, msg string) {
switch ch.callerSkipFrameCount {
case useGlobalSkipFrameCount:
// Extra frames to skip (added by hook infra).
e.caller(CallerSkipFrameCount + contextCallerSkipFrameCount)
default:
// Extra frames to skip (added by hook infra).
e.caller(ch.callerSkipFrameCount + contextCallerSkipFrameCount)
}
// Three extra frames to skip (added by hook infra).
e.caller(CallerSkipFrameCount + 3)
}
// useGlobalSkipFrameCount acts as a flag to informat callerHook.Run
// to use the global CallerSkipFrameCount.
const useGlobalSkipFrameCount = math.MinInt32
// ch is the default caller hook using the global CallerSkipFrameCount.
var ch = newCallerHook(useGlobalSkipFrameCount)
var ch = callerHook{}
// Caller adds the file:line of the caller with the zerolog.CallerFieldName key.
func (c Context) Caller() Context {
@@ -380,14 +362,6 @@ func (c Context) Caller() Context {
return c
}
// CallerWithSkipFrameCount adds the file:line of the caller with the zerolog.CallerFieldName key.
// The specified skipFrameCount int will override the global CallerSkipFrameCount for this context's respective logger.
// If set to -1 the global CallerSkipFrameCount will be used.
func (c Context) CallerWithSkipFrameCount(skipFrameCount int) Context {
c.l = c.l.Hook(newCallerHook(skipFrameCount))
return c
}
type stackTraceHook struct{}
func (sh stackTraceHook) Run(e *Event, level Level, msg string) {
+13 -17
View File
@@ -5,6 +5,7 @@ import (
"net"
"os"
"runtime"
"strconv"
"sync"
"time"
)
@@ -105,20 +106,10 @@ func (e *Event) Msg(msg string) {
e.msg(msg)
}
// Send is equivalent to calling Msg("").
// Msgf sends the event with formated msg added as the message field if not empty.
//
// NOTICE: once this method is called, the *Event should be disposed.
func (e *Event) Send() {
if e == nil {
return
}
e.msg("")
}
// Msgf sends the event with formatted msg added as the message field if not empty.
//
// NOTICE: once this method is called, the *Event should be disposed.
// Calling Msgf twice can have unexpected result.
// NOTICE: once this methid is called, the *Event should be disposed.
// Calling Msg twice can have unexpected result.
func (e *Event) Msgf(format string, v ...interface{}) {
if e == nil {
return
@@ -127,8 +118,13 @@ func (e *Event) Msgf(format string, v ...interface{}) {
}
func (e *Event) msg(msg string) {
for _, hook := range e.ch {
hook.Run(e, e.level, msg)
if len(e.ch) > 0 {
e.ch[0].Run(e, e.level, msg)
if len(e.ch) > 1 {
for _, hook := range e.ch[1:] {
hook.Run(e, e.level, msg)
}
}
}
if msg != "" {
e.buf = enc.AppendString(enc.AppendKey(e.buf, MessageFieldName), msg)
@@ -208,7 +204,7 @@ func (e *Event) Object(key string, obj LogObjectMarshaler) *Event {
return e
}
// EmbedObject marshals an object that implement the LogObjectMarshaler interface.
// Object marshals an object that implement the LogObjectMarshaler interface.
func (e *Event) EmbedObject(obj LogObjectMarshaler) *Event {
if e == nil {
return e
@@ -677,7 +673,7 @@ func (e *Event) caller(skip int) *Event {
if !ok {
return e
}
e.buf = enc.AppendString(enc.AppendKey(e.buf, CallerFieldName), CallerMarshalFunc(file, line))
e.buf = enc.AppendString(enc.AppendKey(e.buf, CallerFieldName), file+":"+strconv.Itoa(line))
return e
}
+4 -31
View File
@@ -1,25 +1,8 @@
package zerolog
import (
"strconv"
"time"
)
import "time"
import "sync/atomic"
const (
// TimeFormatUnix defines a time format that makes time fields to be
// serialized as Unix timestamp integers.
TimeFormatUnix = ""
// TimeFormatUnixMs defines a time format that makes time fields to be
// serialized as Unix timestamp integers in milliseconds.
TimeFormatUnixMs = "UNIXMS"
// TimeFormatUnixMicro defines a time format that makes time fields to be
// serialized as Unix timestamp integers in microseconds.
TimeFormatUnixMicro = "UNIXMICRO"
)
var (
// TimestampFieldName is the field name used for the timestamp field.
TimestampFieldName = "time"
@@ -27,11 +10,6 @@ var (
// LevelFieldName is the field name used for the level field.
LevelFieldName = "level"
// LevelFieldMarshalFunc allows customization of global level field marshaling
LevelFieldMarshalFunc = func(l Level) string {
return l.String()
}
// MessageFieldName is the field name used for the message field.
MessageFieldName = "message"
@@ -44,11 +22,6 @@ var (
// CallerSkipFrameCount is the number of stack frames to skip to find the caller.
CallerSkipFrameCount = 2
// CallerMarshalFunc allows customization of global caller marshaling
CallerMarshalFunc = func(file string, line int) string {
return file + ":" + strconv.Itoa(line)
}
// ErrorStackFieldName is the field name used for error stacks.
ErrorStackFieldName = "stack"
@@ -60,9 +33,9 @@ var (
return err
}
// TimeFieldFormat defines the time format of the Time field type. If set to
// TimeFormatUnix, TimeFormatUnixMs or TimeFormatUnixMicro, the time is formatted as an UNIX
// timestamp as integer.
// TimeFieldFormat defines the time format of the Time field type.
// If set to an empty string, the time is formatted as an UNIX timestamp
// as integer.
TimeFieldFormat = time.RFC3339
// TimestampFunc defines the function called to generate a timestamp.
-8
View File
@@ -1,9 +1 @@
module github.com/rs/zerolog
require (
github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e
github.com/pkg/errors v0.8.1
github.com/rs/xid v1.2.1
github.com/zenazn/goji v0.9.0
golang.org/x/tools v0.0.0-20190828213141-aed303cbaa74
)
-16
View File
@@ -1,16 +0,0 @@
github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e h1:Wf6HqHfScWJN9/ZjdUKyjop4mf3Qdd+1TvvltAvM3m8=
github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I=
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/rs/xid v1.2.1 h1:mhH9Nq+C1fY2l1XIpgxIiUOfNpRBYH1kKcr+qfKgjRc=
github.com/rs/xid v1.2.1/go.mod h1:+uKXf+4Djp6Md1KODXJxgGQPKngRmWyn10oCKFzNHOQ=
github.com/zenazn/goji v0.9.0 h1:RSQQAbXGArQ0dIDEq+PI6WqN6if+5KHu6x2Cx/GXLTQ=
github.com/zenazn/goji v0.9.0/go.mod h1:7S9M489iMyHBNxwZnk9/EHS098H4/F6TATF2mIxtB1Q=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/tools v0.0.0-20190828213141-aed303cbaa74 h1:4cFkmztxtMslUX2SctSl+blCyXfpzhGOy9LhKAqSMA4=
golang.org/x/tools v0.0.0-20190828213141-aed303cbaa74/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
-7
View File
@@ -1,7 +0,0 @@
// +build go1.12
package zerolog
// Since go 1.12, some auto generated init functions are hidden from
// runtime.Caller.
const contextCallerSkipFrameCount = 2
+3 -3
View File
@@ -24,9 +24,9 @@ func (Encoder) AppendEndMarker(dst []byte) []byte {
// AppendObjectData takes an object in form of a byte array and appends to dst.
func (Encoder) AppendObjectData(dst []byte, o []byte) []byte {
// BeginMarker is present in the dst, which
// should not be copied when appending to existing data.
return append(dst, o[1:]...)
// BeginMarker is present in the dst, which
// should not be copied when appending to existing data.
return append(dst, o[1:]...)
}
// AppendArrayStart adds markers to indicate the start of an array.
+2 -32
View File
@@ -5,23 +5,11 @@ import (
"time"
)
const (
// Import from zerolog/global.go
timeFormatUnix = ""
timeFormatUnixMs = "UNIXMS"
timeFormatUnixMicro = "UNIXMICRO"
)
// AppendTime formats the input time with the given format
// and appends the encoded string to the input byte slice.
func (e Encoder) AppendTime(dst []byte, t time.Time, format string) []byte {
switch format {
case timeFormatUnix:
if format == "" {
return e.AppendInt64(dst, t.Unix())
case timeFormatUnixMs:
return e.AppendInt64(dst, t.UnixNano()/1000000)
case timeFormatUnixMicro:
return e.AppendInt64(dst, t.UnixNano()/1000)
}
return append(t.AppendFormat(append(dst, '"'), format), '"')
}
@@ -29,11 +17,8 @@ func (e Encoder) AppendTime(dst []byte, t time.Time, format string) []byte {
// AppendTimes converts the input times with the given format
// and appends the encoded string list to the input byte slice.
func (Encoder) AppendTimes(dst []byte, vals []time.Time, format string) []byte {
switch format {
case timeFormatUnix:
if format == "" {
return appendUnixTimes(dst, vals)
case timeFormatUnixMs:
return appendUnixMsTimes(dst, vals)
}
if len(vals) == 0 {
return append(dst, '[', ']')
@@ -64,21 +49,6 @@ func appendUnixTimes(dst []byte, vals []time.Time) []byte {
return dst
}
func appendUnixMsTimes(dst []byte, vals []time.Time) []byte {
if len(vals) == 0 {
return append(dst, '[', ']')
}
dst = append(dst, '[')
dst = strconv.AppendInt(dst, vals[0].UnixNano()/1000000, 10)
if len(vals) > 1 {
for _, t := range vals[1:] {
dst = strconv.AppendInt(append(dst, ','), t.UnixNano()/1000000, 10)
}
}
dst = append(dst, ']')
return dst
}
// AppendDuration formats the input duration with the given unit & format
// and appends the encoded string to the input byte slice.
func (e Encoder) AppendDuration(dst []byte, d time.Duration, unit time.Duration, useInt bool) []byte {
+5 -10
View File
@@ -373,17 +373,12 @@ func (e Encoder) AppendInterface(dst []byte, i interface{}) []byte {
// AppendObjectData takes in an object that is already in a byte array
// and adds it to the dst.
func (Encoder) AppendObjectData(dst []byte, o []byte) []byte {
// Three conditions apply here:
// 1. new content starts with '{' - which should be dropped OR
// 2. new content starts with '{' - which should be replaced with ','
// to separate with existing content OR
// 3. existing content has already other fields
// Two conditions we want to put a ',' between existing content and
// new content:
// 1. new content starts with '{' - which shd be dropped OR
// 2. existing content has already other fields
if o[0] == '{' {
if len(dst) == 0 {
o = o[1:]
} else {
o[0] = ','
}
o[0] = ','
} else if len(dst) > 1 {
dst = append(dst, ',')
}
-20
View File
@@ -165,23 +165,3 @@ func Test_appendMac(t *testing.T) {
})
}
}
func Test_appendObjectData(t *testing.T) {
tests := []struct {
dst []byte
obj []byte
want []byte
}{
{[]byte{}, []byte(`{"foo":"bar"}`), []byte(`"foo":"bar"}`)},
{[]byte(`{"qux":"quz"`), []byte(`{"foo":"bar"}`), []byte(`{"qux":"quz","foo":"bar"}`)},
{[]byte{}, []byte(`"foo":"bar"`), []byte(`"foo":"bar"`)},
{[]byte(`{"qux":"quz"`), []byte(`"foo":"bar"`), []byte(`{"qux":"quz","foo":"bar"`)},
}
for _, tt := range tests {
t.Run("ObjectData", func(t *testing.T) {
if got := enc.AppendObjectData(tt.dst, tt.obj); !reflect.DeepEqual(got, tt.want) {
t.Errorf("appendObjectData() = %s, want %s", got, tt.want)
}
})
}
}
+3 -4
View File
@@ -20,12 +20,11 @@ import (
"bytes"
"encoding/json"
"fmt"
"io"
"strings"
"github.com/coreos/go-systemd/journal"
"github.com/rs/zerolog"
"github.com/rs/zerolog/internal/cbor"
"io"
"strings"
)
const defaultJournalDPrio = journal.PriNotice
@@ -68,7 +67,7 @@ func levelToJPrio(zLevel string) journal.Priority {
func (w journalWriter) Write(p []byte) (n int, err error) {
if !journal.Enabled() {
err = fmt.Errorf("cannot connect to journalD")
err = fmt.Errorf("Cannot connect to journalD!!")
return
}
var event map[string]interface{}
+10 -27
View File
@@ -94,8 +94,8 @@
// Msg("dup")
// // Output: {"level":"info","time":1494567715,"time":1494567715,"message":"dup"}
//
// In this case, many consumers will take the last value,
// but this is not guaranteed; check yours if in doubt.
// However, its not a big deal though as JSON accepts dup keys,
// the last one prevails.
package zerolog
import (
@@ -152,19 +152,19 @@ func (l Level) String() string {
// returns an error if the input string does not match known values.
func ParseLevel(levelStr string) (Level, error) {
switch levelStr {
case LevelFieldMarshalFunc(DebugLevel):
case DebugLevel.String():
return DebugLevel, nil
case LevelFieldMarshalFunc(InfoLevel):
case InfoLevel.String():
return InfoLevel, nil
case LevelFieldMarshalFunc(WarnLevel):
case WarnLevel.String():
return WarnLevel, nil
case LevelFieldMarshalFunc(ErrorLevel):
case ErrorLevel.String():
return ErrorLevel, nil
case LevelFieldMarshalFunc(FatalLevel):
case FatalLevel.String():
return FatalLevel, nil
case LevelFieldMarshalFunc(PanicLevel):
case PanicLevel.String():
return PanicLevel, nil
case LevelFieldMarshalFunc(NoLevel):
case NoLevel.String():
return NoLevel, nil
}
return NoLevel, fmt.Errorf("Unknown Level String: '%s', defaulting to NoLevel", levelStr)
@@ -251,11 +251,6 @@ func (l Logger) Level(lvl Level) Logger {
return l
}
// GetLevel returns the current Level of l.
func (l Logger) GetLevel() Level {
return l.level
}
// Sample returns a logger with the s sampler.
func (l Logger) Sample(s Sampler) Logger {
l.sampler = s
@@ -296,18 +291,6 @@ func (l *Logger) Error() *Event {
return l.newEvent(ErrorLevel, nil)
}
// Err starts a new message with error level with err as a field if not nil or
// with info level if err is nil.
//
// You must call Msg on the returned event in order to send the event.
func (l *Logger) Err(err error) *Event {
if err != nil {
return l.Error().Err(err)
}
return l.Info()
}
// Fatal starts a new message with fatal level. The os.Exit(1) function
// is called by the Msg method, which terminates the program immediately.
//
@@ -397,7 +380,7 @@ func (l *Logger) newEvent(level Level, done func(string)) *Event {
e.done = done
e.ch = l.hooks
if level != NoLevel {
e.Str(LevelFieldName, LevelFieldMarshalFunc(level))
e.Str(LevelFieldName, level.String())
}
if l.context != nil && len(l.context) > 0 {
e.buf = enc.AppendObjectData(e.buf, l.context)
-103
View File
@@ -7,8 +7,6 @@ import (
"net"
"reflect"
"runtime"
"strconv"
"strings"
"testing"
"time"
)
@@ -107,20 +105,6 @@ func TestWith(t *testing.T) {
if got, want := decodeIfBinaryToString(out.Bytes()), `{"string":"foo","bytes":"bar","hex":"12ef","json":{"some":"json"},"error":"some error","bool":true,"int":1,"int8":2,"int16":3,"int32":4,"int64":5,"uint":6,"uint8":7,"uint16":8,"uint32":9,"uint64":10,"float32":11.101,"float64":12.30303,"time":"0001-01-01T00:00:00Z","caller":"`+caller+`"}`+"\n"; got != want {
t.Errorf("invalid log output:\ngot: %v\nwant: %v", got, want)
}
// Validate CallerWithSkipFrameCount.
out.Reset()
_, file, line, _ = runtime.Caller(0)
caller = fmt.Sprintf("%s:%d", file, line+5)
log = ctx.CallerWithSkipFrameCount(3).Logger()
func() {
log.Log().Msg("")
}()
// The above line is a little contrived, but the line above should be the line due
// to the extra frame skip.
if got, want := decodeIfBinaryToString(out.Bytes()), `{"string":"foo","bytes":"bar","hex":"12ef","json":{"some":"json"},"error":"some error","bool":true,"int":1,"int8":2,"int16":3,"int32":4,"int64":5,"uint":6,"uint8":7,"uint16":8,"uint32":9,"uint64":10,"float32":11.101,"float64":12.30303,"time":"0001-01-01T00:00:00Z","caller":"`+caller+`"}`+"\n"; got != want {
t.Errorf("invalid log output:\ngot: %v\nwant: %v", got, want)
}
}
func TestFieldsMap(t *testing.T) {
@@ -453,24 +437,6 @@ func TestLevel(t *testing.T) {
})
}
func TestGetLevel(t *testing.T) {
levels := []Level{
DebugLevel,
InfoLevel,
WarnLevel,
ErrorLevel,
FatalLevel,
PanicLevel,
NoLevel,
Disabled,
}
for _, level := range levels {
if got, want := New(nil).Level(level).GetLevel(), level; got != want {
t.Errorf("GetLevel() = %v, want: %v", got, want)
}
}
}
func TestSampling(t *testing.T) {
out := &bytes.Buffer{}
log := New(out).Sample(&BasicSampler{N: 2})
@@ -675,75 +641,6 @@ func TestErrorMarshalFunc(t *testing.T) {
}
}
func TestCallerMarshalFunc(t *testing.T) {
out := &bytes.Buffer{}
log := New(out)
// test default behaviour this is really brittle due to the line numbers
// actually mattering for validation
_, file, line, _ := runtime.Caller(0)
caller := fmt.Sprintf("%s:%d", file, line+2)
log.Log().Caller().Msg("msg")
if got, want := decodeIfBinaryToString(out.Bytes()), `{"caller":"`+caller+`","message":"msg"}`+"\n"; got != want {
t.Errorf("invalid log output:\ngot: %v\nwant: %v", got, want)
}
out.Reset()
// test custom behavior. In this case we'll take just the last directory
origCallerMarshalFunc := CallerMarshalFunc
defer func() { CallerMarshalFunc = origCallerMarshalFunc }()
CallerMarshalFunc = func(file string, line int) string {
parts := strings.Split(file, "/")
if len(parts) > 1 {
return strings.Join(parts[len(parts)-2:], "/") + ":" + strconv.Itoa(line)
}
return file + ":" + strconv.Itoa(line)
}
_, file, line, _ = runtime.Caller(0)
caller = CallerMarshalFunc(file, line+2)
log.Log().Caller().Msg("msg")
if got, want := decodeIfBinaryToString(out.Bytes()), `{"caller":"`+caller+`","message":"msg"}`+"\n"; got != want {
t.Errorf("invalid log output:\ngot: %v\nwant: %v", got, want)
}
}
func TestLevelFieldMarshalFunc(t *testing.T) {
origLevelFieldMarshalFunc := LevelFieldMarshalFunc
LevelFieldMarshalFunc = func(l Level) string {
return strings.ToUpper(l.String())
}
defer func() {
LevelFieldMarshalFunc = origLevelFieldMarshalFunc
}()
out := &bytes.Buffer{}
log := New(out)
log.Debug().Msg("test")
if got, want := decodeIfBinaryToString(out.Bytes()), `{"level":"DEBUG","message":"test"}`+"\n"; got != want {
t.Errorf("invalid log output:\ngot: %v\nwant: %v", got, want)
}
out.Reset()
log.Info().Msg("test")
if got, want := decodeIfBinaryToString(out.Bytes()), `{"level":"INFO","message":"test"}`+"\n"; got != want {
t.Errorf("invalid log output:\ngot: %v\nwant: %v", got, want)
}
out.Reset()
log.Warn().Msg("test")
if got, want := decodeIfBinaryToString(out.Bytes()), `{"level":"WARN","message":"test"}`+"\n"; got != want {
t.Errorf("invalid log output:\ngot: %v\nwant: %v", got, want)
}
out.Reset()
log.Error().Msg("test")
if got, want := decodeIfBinaryToString(out.Bytes()), `{"level":"ERROR","message":"test"}`+"\n"; got != want {
t.Errorf("invalid log output:\ngot: %v\nwant: %v", got, want)
}
out.Reset()
}
type errWriter struct {
error
}
-5
View File
@@ -1,5 +0,0 @@
// +build !go1.12
package zerolog
const contextCallerSkipFrameCount = 3
+1 -5
View File
@@ -46,12 +46,8 @@ type BasicSampler struct {
// Sample implements the Sampler interface.
func (s *BasicSampler) Sample(lvl Level) bool {
n := s.N
if n == 1 {
return true
}
c := atomic.AddUint32(&s.counter, 1)
return c%n == 1
return c%s.N == s.N-1
}
// BurstSampler lets Burst events pass per Period then pass the decision to