Skip to content

Commit

Permalink
⚡ perf: performance the log message format process
Browse files Browse the repository at this point in the history
  • Loading branch information
inhere committed Apr 14, 2023
1 parent cc218e0 commit 0c3609b
Show file tree
Hide file tree
Showing 4 changed files with 71 additions and 42 deletions.
7 changes: 5 additions & 2 deletions formatter_json.go
Original file line number Diff line number Diff line change
Expand Up @@ -70,10 +70,13 @@ func (f *JSONFormatter) AddField(name string) *JSONFormatter {
return f
}

var jsonPool bytebufferpool.Pool

// Format an log record
func (f *JSONFormatter) Format(r *Record) ([]byte, error) {
logData := make(M, len(f.Fields))

// TODO perf: use buf write build JSON string.
for _, field := range f.Fields {
outName, ok := f.Aliases[field]
if !ok {
Expand Down Expand Up @@ -113,9 +116,9 @@ func (f *JSONFormatter) Format(r *Record) ([]byte, error) {
}

// sort.Interface()
buf := bytebufferpool.Get()
buf := jsonPool.Get()
// buf.Reset()
defer bytebufferpool.Put(buf)
defer jsonPool.Put(buf)
// buf := r.NewBuffer()
// buf.Reset()
// buf.Grow(256)
Expand Down
15 changes: 5 additions & 10 deletions formatter_text.go
Original file line number Diff line number Diff line change
Expand Up @@ -71,11 +71,6 @@ func NewTextFormatter(template ...string) *TextFormatter {

// SetTemplate set the log format template and update field-map
func (f *TextFormatter) SetTemplate(fmtTpl string) {
// ensure last char is newline.
// if fmtTpl[len(fmtTpl)-1] != '\n' {
// fmtTpl += "\n"
// }

f.template = fmtTpl
f.fields = parseTemplateToFields(fmtTpl)
}
Expand All @@ -93,17 +88,17 @@ func (f *TextFormatter) Fields() []string {
ss = append(ss, s)
}
}

return ss
}

var textPool bytebufferpool.Pool

// Format a log record
//
//goland:noinspection GoUnhandledErrorResult
func (f *TextFormatter) Format(r *Record) ([]byte, error) {
buf := bytebufferpool.Get()
buf.Reset()
defer bytebufferpool.Put(buf)
buf := textPool.Get()
defer textPool.Put(buf)

for _, field := range f.fields {
// is not field name. eg: "}}] "
Expand All @@ -119,7 +114,7 @@ func (f *TextFormatter) Format(r *Record) ([]byte, error) {

switch {
case field == FieldKeyDatetime:
buf.WriteString(r.Time.Format(f.TimeFormat))
buf.B = r.Time.AppendFormat(buf.B, f.TimeFormat)
case field == FieldKeyTimestamp:
buf.WriteString(r.timestamp())
case field == FieldKeyCaller && r.Caller != nil:
Expand Down
18 changes: 2 additions & 16 deletions record.go
Original file line number Diff line number Diff line change
Expand Up @@ -401,29 +401,15 @@ func (r *Record) Panicf(format string, args ...any) {
// helper methods
// ---------------------------------------------------------------------------

// NewBuffer get or create a Buffer
// func (r *Record) NewBuffer() *bytes.Buffer {
// if r.Buffer == nil {
// return &bytes.Buffer{}
// }
// return r.Buffer
// }

// LevelName get
func (r *Record) LevelName() string { return r.levelName }

// MicroSecond of the record
// func (r *Record) MicroSecond() int { return r.microSecond }

// GoString of the record
func (r *Record) GoString() string {
return "slog: " + r.Message
}

func (r *Record) timestamp() string {
return strconv.FormatInt(r.Time.Unix(), 10) + "." + strconv.Itoa(r.Time.Nanosecond()/1000)

// require go 1.16+
// s := strconv.FormatInt(r.Time.UnixMicro(), 10)
// return s[:10] + "." + s[10:]
s := strconv.FormatInt(r.Time.UnixMicro(), 10)
return s[:10] + "." + s[10:]
}
73 changes: 59 additions & 14 deletions util.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (
"runtime"
"strconv"
"strings"
"time"

"github.com/gookit/goutil/stdutil"
"github.com/gookit/goutil/strutil"
Expand All @@ -18,10 +19,6 @@ import (
// defaultKnownSlogFrames int = 4
// )

// var (
// argFmtPool bytebufferpool.Pool
// )

// Stack that attempts to recover the data for all goroutines.
// func getCallStacks(callerSkip int) []byte {
// return nil
Expand Down Expand Up @@ -77,6 +74,8 @@ func formatCaller(rf *runtime.Frame, flag uint8) (cs string) {
}
}

var msgBufPool bytebufferpool.Pool

// it like Println, will add spaces for each argument
func formatArgsWithSpaces(vs []any) string {
ln := len(vs)
Expand All @@ -85,30 +84,76 @@ func formatArgsWithSpaces(vs []any) string {
}

if ln == 1 {
// return strutil.ToBytes(msg) // perf: Reduce one memory allocation
return stdutil.ToString(vs[0]) // perf: Reduce one memory allocation
return strutil.SafeString(vs[0]) // perf: Reduce one memory allocation
}

// buf = make([]byte, 0, ln*8)
bb := bytebufferpool.Get()
defer bytebufferpool.Put(bb)
bb := msgBufPool.Get()
defer msgBufPool.Put(bb)

// TIP:
// `float` to string - will alloc 2 times memory
// `int <0`, `int > 100` to string - will alloc 1 times memory
for i := range vs {
// str, _ := strutil.AnyToString(vs[i], false)
str := stdutil.ToString(vs[i])
if i > 0 { // add space
// buf = append(buf, ' ')
bb.B = append(bb.B, ' ')
}
bb.B = appendAny(bb.B, vs[i])
}

// buf = append(buf, str...)
bb.B = append(bb.B, str...)
return string(bb.B)
// return byteutil.String(bb.B) // perf: Reduce one memory allocation
}

// TODO replace to byteutil.AppendAny()
func appendAny(dst []byte, v any) []byte {
if v == nil {
return dst
}

return bb.String()
switch val := v.(type) {
case []byte:
dst = append(dst, val...)
case string:
dst = append(dst, val...)
case int:
dst = strconv.AppendInt(dst, int64(val), 10)
case int8:
dst = strconv.AppendInt(dst, int64(val), 10)
case int16:
dst = strconv.AppendInt(dst, int64(val), 10)
case int32:
dst = strconv.AppendInt(dst, int64(val), 10)
case int64:
dst = strconv.AppendInt(dst, val, 10)
case uint:
dst = strconv.AppendUint(dst, uint64(val), 10)
case uint8:
dst = strconv.AppendUint(dst, uint64(val), 10)
case uint16:
dst = strconv.AppendUint(dst, uint64(val), 10)
case uint32:
dst = strconv.AppendUint(dst, uint64(val), 10)
case uint64:
dst = strconv.AppendUint(dst, val, 10)
case float32:
dst = strconv.AppendFloat(dst, float64(val), 'f', -1, 32)
case float64:
dst = strconv.AppendFloat(dst, val, 'f', -1, 64)
case bool:
dst = strconv.AppendBool(dst, val)
case time.Time:
dst = val.AppendFormat(dst, time.RFC3339)
case time.Duration:
dst = strconv.AppendInt(dst, int64(val), 10)
case error:
dst = append(dst, val.Error()...)
case fmt.Stringer:
dst = append(dst, val.String()...)
default:
dst = append(dst, fmt.Sprint(v)...)
}
return dst
}

// EncodeToString data to string
Expand Down

0 comments on commit 0c3609b

Please sign in to comment.