Skip to content

Commit

Permalink
Add ability to customize internal json marshaler
Browse files Browse the repository at this point in the history
Added a package level variable "JSONMarshaler".
It's used to marshal interface to JSON encoded
byte slice, mostly when event.Interface("key", v)
is called.

This enables user to replace the internal json
marshaler at runtime, but will potentially cause
data race if used improperly.
  • Loading branch information
povsister committed May 17, 2021
1 parent 3c3b4a3 commit 9eab6bb
Show file tree
Hide file tree
Showing 7 changed files with 46 additions and 5 deletions.
13 changes: 13 additions & 0 deletions encoder.go
@@ -1,10 +1,23 @@
package zerolog

import (
"encoding/json"
"net"
"time"
)

var (
// JSONMarshaler is used to marshal interface
// to JSON encoded byte slice when an interface
// is passed for logging.
// Default: "encoding/json.Marshal"
JSONMarshaler InterfaceMarshaler = json.Marshal
)

// InterfaceMarshaler represents a way to marshal
// interface to byte slice.
type InterfaceMarshaler func(v interface{}) ([]byte, error)

type encoder interface {
AppendArrayDelim(dst []byte) []byte
AppendArrayEnd(dst []byte) []byte
Expand Down
7 changes: 7 additions & 0 deletions encoder_cbor.go
Expand Up @@ -14,6 +14,13 @@ var (
enc = cbor.Encoder{}
)

func init() {
// using closure to reflect the changes at runtime.
cbor.JSONMarshaler = func(v interface{}) ([]byte, error) {
return JSONMarshaler(v)
}
}

func appendJSON(dst []byte, j []byte) []byte {
return cbor.AppendEmbeddedJSON(dst, j)
}
Expand Down
7 changes: 7 additions & 0 deletions encoder_json.go
Expand Up @@ -15,6 +15,13 @@ var (
enc = json.Encoder{}
)

func init() {
// using closure to reflect the changes at runtime.
json.JSONMarshaler = func(v interface{}) ([]byte, error) {
return JSONMarshaler(v)
}
}

func appendJSON(dst []byte, j []byte) []byte {
return append(dst, j...)
}
Expand Down
10 changes: 9 additions & 1 deletion internal/cbor/base.go
@@ -1,5 +1,13 @@
package cbor

// JSONMarshaler knows how to marshal an interface to JSON encoded byte slice.
// Making it package level instead of embedded in Encoder brings
// some extra efforts at importing, but avoids value copy when
// the functions of Encoder being invoked.
// DO REMEMBER to set this variable at importing, or
// you might get a nil pointer dereference panic at runtime.
var JSONMarshaler func(v interface{}) ([]byte, error)

type Encoder struct{}

// AppendKey adds a key (string) to the binary encoded log message
Expand All @@ -8,4 +16,4 @@ func (e Encoder) AppendKey(dst []byte, key string) []byte {
dst = e.AppendBeginMarker(dst)
}
return e.AppendString(dst, key)
}
}
3 changes: 1 addition & 2 deletions internal/cbor/types.go
@@ -1,7 +1,6 @@
package cbor

import (
"encoding/json"
"fmt"
"math"
"net"
Expand Down Expand Up @@ -432,7 +431,7 @@ func (e Encoder) AppendFloats64(dst []byte, vals []float64) []byte {

// AppendInterface takes an arbitrary object and converts it to JSON and embeds it dst.
func (e Encoder) AppendInterface(dst []byte, i interface{}) []byte {
marshaled, err := json.Marshal(i)
marshaled, err := JSONMarshaler(i)
if err != nil {
return e.AppendString(dst, fmt.Sprintf("marshaling error: %v", err))
}
Expand Down
8 changes: 8 additions & 0 deletions internal/json/base.go
@@ -1,5 +1,13 @@
package json

// JSONMarshaler knows how to marshal an interface to JSON encoded byte slice.
// Making it package level instead of embedded in Encoder brings
// some extra efforts at importing, but avoids value copy when
// the functions of Encoder being invoked.
// DO REMEMBER to set this variable at importing, or
// you might get a nil pointer dereference panic at runtime.
var JSONMarshaler func(v interface{}) ([]byte, error)

type Encoder struct{}

// AppendKey appends a new key to the output JSON.
Expand Down
3 changes: 1 addition & 2 deletions internal/json/types.go
@@ -1,7 +1,6 @@
package json

import (
"encoding/json"
"fmt"
"math"
"net"
Expand Down Expand Up @@ -363,7 +362,7 @@ func (Encoder) AppendFloats64(dst []byte, vals []float64) []byte {
// AppendInterface marshals the input interface to a string and
// appends the encoded string to the input byte slice.
func (e Encoder) AppendInterface(dst []byte, i interface{}) []byte {
marshaled, err := json.Marshal(i)
marshaled, err := JSONMarshaler(i)
if err != nil {
return e.AppendString(dst, fmt.Sprintf("marshaling error: %v", err))
}
Expand Down

0 comments on commit 9eab6bb

Please sign in to comment.