Skip to content

Commit

Permalink
add Objects method
Browse files Browse the repository at this point in the history
  • Loading branch information
phuslu committed May 10, 2024
1 parent 7866d2d commit f3d5880
Show file tree
Hide file tree
Showing 4 changed files with 86 additions and 15 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@
- `NewXID()`, *create a tracing id*
- `Fastrandn(n uint32)`, *fast pseudorandom uint32 in [0,n)*
- `IsTerminal(fd uintptr)`, *isatty for golang*
- `Printf(fmt string, a ...interface{})`, *printf logging*
- `Printf(fmt string, a ...any)`, *printf logging*
- `SlogNewJSONHandler(io.Writer, *slog.HandlerOptions)`, *drop-in replacement of slog.JSONHandler*
* High Performance
- [Significantly faster][high-performance] than all other json loggers.
Expand Down
60 changes: 48 additions & 12 deletions logger.go
Original file line number Diff line number Diff line change
Expand Up @@ -231,7 +231,7 @@ func Panic() (e *Entry) {
}

// Printf sends a log entry without extra field. Arguments are handled in the manner of fmt.Printf.
func Printf(format string, v ...interface{}) {
func Printf(format string, v ...any) {
e := DefaultLogger.header(noLevel)
if caller, full := DefaultLogger.Caller, false; caller != 0 {
if caller < 0 {
Expand Down Expand Up @@ -416,7 +416,7 @@ func (l *Logger) SetLevel(level Level) {
}

// Printf sends a log entry without extra field. Arguments are handled in the manner of fmt.Printf.
func (l *Logger) Printf(format string, v ...interface{}) {
func (l *Logger) Printf(format string, v ...any) {
e := l.header(noLevel)
if e != nil {
if caller, full := l.Caller, false; caller != 0 {
Expand All @@ -431,7 +431,7 @@ func (l *Logger) Printf(format string, v ...interface{}) {
}

var epool = sync.Pool{
New: func() interface{} {
New: func() any {
return &Entry{
buf: make([]byte, 0, 1024),
}
Expand Down Expand Up @@ -1670,7 +1670,7 @@ func (e *Entry) NetIPPrefix(key string, pfx netip.Prefix) *Entry {
}

// Type adds type of the key using reflection to the entry.
func (e *Entry) Type(key string, v interface{}) *Entry {
func (e *Entry) Type(key string, v any) *Entry {
if e == nil {
return nil
}
Expand Down Expand Up @@ -1758,13 +1758,13 @@ func (b *bb) Write(p []byte) (int, error) {
}

var bbpool = sync.Pool{
New: func() interface{} {
New: func() any {
return new(bb)
},
}

// Msgf sends the entry with formatted msg added as the message field if not empty.
func (e *Entry) Msgf(format string, v ...interface{}) {
func (e *Entry) Msgf(format string, v ...any) {
if e == nil {
return
}
Expand All @@ -1781,7 +1781,7 @@ func (e *Entry) Msgf(format string, v ...interface{}) {
}

// Msgs sends the entry with msgs added as the message field if not empty.
func (e *Entry) Msgs(args ...interface{}) {
func (e *Entry) Msgs(args ...any) {
if e == nil {
return
}
Expand Down Expand Up @@ -1972,7 +1972,7 @@ func (e *Entry) bytes(b []byte) {
}

// Interface adds the field key with i marshaled using reflection.
func (e *Entry) Interface(key string, i interface{}) *Entry {
func (e *Entry) Interface(key string, i any) *Entry {
if e == nil {
return nil
}
Expand Down Expand Up @@ -2029,6 +2029,42 @@ func (e *Entry) Object(key string, obj ObjectMarshaler) *Entry {
return e
}

// Objects marshals a slice of objects that implement the ObjectMarshaler interface.
func (e *Entry) Objects(key string, objects any) *Entry {
if e == nil {
return nil
}
values := reflect.ValueOf(objects)
if values.Kind() != reflect.Slice {
e.buf = append(e.buf, ',', '"')
e.buf = append(e.buf, key...)
e.buf = append(e.buf, `":null`...)
return e
}

e.buf = append(e.buf, ',', '"')
e.buf = append(e.buf, key...)
e.buf = append(e.buf, '"', ':', '[')
for i := 0; i < values.Len(); i++ {
if i != 0 {
e.buf = append(e.buf, ',')
}
value := values.Index(i)
if value.IsNil() {
e.buf = append(e.buf, "null"...)
} else if obj, ok := value.Interface().(ObjectMarshaler); ok {
i := len(e.buf)
obj.MarshalObject(e)
e.buf[i] = '{'
e.buf = append(e.buf, '}')
} else {
e.buf = append(e.buf, `null`...)
}
}
e.buf = append(e.buf, ']')
return e
}

// Func allows an anonymous func to run only if the entry is enabled.
func (e *Entry) Func(f func(e *Entry)) *Entry {
if e != nil {
Expand All @@ -2050,7 +2086,7 @@ func (e *Entry) EmbedObject(obj ObjectMarshaler) *Entry {
}

// Any adds the field key with f as an any value to the entry.
func (e *Entry) Any(key string, value interface{}) *Entry {
func (e *Entry) Any(key string, value any) *Entry {
if value == nil || (*[2]uintptr)(unsafe.Pointer(&value))[1] == 0 {
e.buf = append(e.buf, ',', '"')
e.buf = append(e.buf, key...)
Expand Down Expand Up @@ -2154,7 +2190,7 @@ func (e *Entry) Any(key string, value interface{}) *Entry {
}

// KeysAndValues sends keysAndValues to Entry
func (e *Entry) KeysAndValues(keysAndValues ...interface{}) *Entry {
func (e *Entry) KeysAndValues(keysAndValues ...any) *Entry {
if e == nil {
return nil
}
Expand All @@ -2170,7 +2206,7 @@ func (e *Entry) KeysAndValues(keysAndValues ...interface{}) *Entry {
}

// Fields type, used to pass to `Fields`.
type Fields map[string]interface{}
type Fields map[string]any

// Fields is a helper function to use a map to set fields using type assertion.
func (e *Entry) Fields(fields Fields) *Entry {
Expand Down Expand Up @@ -2247,7 +2283,7 @@ func stacks(all bool) (trace []byte) {
}

// wlprintf is a helper function for tests
func wlprintf(w Writer, level Level, format string, args ...interface{}) (int, error) {
func wlprintf(w Writer, level Level, format string, args ...any) (int, error) {
return w.WriteEntry(&Entry{
Level: level,
buf: []byte(fmt.Sprintf(format, args...)),
Expand Down
37 changes: 36 additions & 1 deletion logger_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -208,7 +208,7 @@ func TestLoggerInterface(t *testing.T) {
}{"15", 16, 123.2}

var cyclicStruct struct {
Value interface{}
Value any
}

cyclicStruct.Value = &cyclicStruct
Expand Down Expand Up @@ -260,6 +260,41 @@ func TestLoggerObject(t *testing.T) {
logger.Info().EmbedObject(nilIface).Msg("this is a null_object_2 test")
}

func TestLoggerObjects(t *testing.T) {
logger := Logger{
Level: ParseLevel("debug"),
}

logger.Info().Objects("bad_objects", "1234").Msg("this is a anys test")

objects1 := []*testMarshalObject{
&testMarshalObject{1, "foo"},
&testMarshalObject{2, "bar"},
nil,
}
logger.Info().Objects("objects1", objects1).Msg("this is a objects1 test")

var nullObject ObjectMarshaler
objects2 := []any{
nullObject,
&testMarshalObject{3, "ok"},
nil,
"1234",
&testMarshalObject{4, "haha"},
}
logger.Info().Objects("objects2", objects2).Msg("this is a objects2 test")

type TestObjects []*testMarshalObject
objects3 := TestObjects{
nil,
&testMarshalObject{3, "ok"},
nil,
&testMarshalObject{4, "haha"},
nil,
}
logger.Info().Objects("objects3", objects3).Msg("this is a objects2 test")
}

func TestLoggerLog(t *testing.T) {
logger := Logger{
Level: ParseLevel("debug"),
Expand Down
2 changes: 1 addition & 1 deletion tsv.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ type TSVEntry struct {
}

var tepool = sync.Pool{
New: func() interface{} {
New: func() any {
return new(TSVEntry)
},
}
Expand Down

0 comments on commit f3d5880

Please sign in to comment.