Use Buffer pool to allocate bytes.Buffer for formatter

Entry.Reader() seams not necessary, removed
This commit is contained in:
plan 2016-06-18 21:47:44 +08:00 committed by plan
parent a283a10442
commit 69df0d2ed7
2 changed files with 37 additions and 22 deletions

View File

@ -3,11 +3,21 @@ package logrus
import ( import (
"bytes" "bytes"
"fmt" "fmt"
"io"
"os" "os"
"sync"
"time" "time"
) )
var bufferPool *sync.Pool
func init() {
bufferPool = &sync.Pool{
New: func() interface{} {
return new(bytes.Buffer)
},
}
}
// Defines the key when adding errors using WithError. // Defines the key when adding errors using WithError.
var ErrorKey = "error" var ErrorKey = "error"
@ -29,6 +39,9 @@ type Entry struct {
// Message passed to Debug, Info, Warn, Error, Fatal or Panic // Message passed to Debug, Info, Warn, Error, Fatal or Panic
Message string Message string
// When formatter is called in entry.log(), an Buffer may be set to entry
Buffer *bytes.Buffer
} }
func NewEntry(logger *Logger) *Entry { func NewEntry(logger *Logger) *Entry {
@ -39,21 +52,15 @@ func NewEntry(logger *Logger) *Entry {
} }
} }
// Returns a reader for the entry, which is a proxy to the formatter.
func (entry *Entry) Reader() (*bytes.Buffer, error) {
serialized, err := entry.Logger.Formatter.Format(entry)
return bytes.NewBuffer(serialized), err
}
// Returns the string representation from the reader and ultimately the // Returns the string representation from the reader and ultimately the
// formatter. // formatter.
func (entry *Entry) String() (string, error) { func (entry *Entry) String() (string, error) {
reader, err := entry.Reader() serialized, err := entry.Logger.Formatter.Format(entry)
if err != nil { if err != nil {
return "", err return "", err
} }
str := string(serialized)
return reader.String(), err return str, nil
} }
// Add an error as single field (using the key defined in ErrorKey) to the Entry. // Add an error as single field (using the key defined in ErrorKey) to the Entry.
@ -81,6 +88,7 @@ func (entry *Entry) WithFields(fields Fields) *Entry {
// This function is not declared with a pointer value because otherwise // This function is not declared with a pointer value because otherwise
// race conditions will occur when using multiple goroutines // race conditions will occur when using multiple goroutines
func (entry Entry) log(level Level, msg string) { func (entry Entry) log(level Level, msg string) {
var buffer *bytes.Buffer
entry.Time = time.Now() entry.Time = time.Now()
entry.Level = level entry.Level = level
entry.Message = msg entry.Message = msg
@ -90,21 +98,24 @@ func (entry Entry) log(level Level, msg string) {
fmt.Fprintf(os.Stderr, "Failed to fire hook: %v\n", err) fmt.Fprintf(os.Stderr, "Failed to fire hook: %v\n", err)
entry.Logger.mu.Unlock() entry.Logger.mu.Unlock()
} }
buffer = bufferPool.Get().(*bytes.Buffer)
reader, err := entry.Reader() buffer.Reset()
defer bufferPool.Put(buffer)
entry.Buffer = buffer
serialized, err := entry.Logger.Formatter.Format(&entry)
entry.Buffer = nil
if err != nil { if err != nil {
entry.Logger.mu.Lock() entry.Logger.mu.Lock()
fmt.Fprintf(os.Stderr, "Failed to obtain reader, %v\n", err) fmt.Fprintf(os.Stderr, "Failed to obtain reader, %v\n", err)
entry.Logger.mu.Unlock() entry.Logger.mu.Unlock()
} } else {
entry.Logger.mu.Lock() entry.Logger.mu.Lock()
defer entry.Logger.mu.Unlock() _, err = entry.Logger.Out.Write(serialized)
_, err = io.Copy(entry.Logger.Out, reader)
if err != nil { if err != nil {
fmt.Fprintf(os.Stderr, "Failed to write to log, %v\n", err) fmt.Fprintf(os.Stderr, "Failed to write to log, %v\n", err)
} }
entry.Logger.mu.Unlock()
}
// To avoid Entry#log() returning a value that only would make sense for // To avoid Entry#log() returning a value that only would make sense for
// panic() to use in Entry#Panic(), we avoid the allocation by checking // panic() to use in Entry#Panic(), we avoid the allocation by checking

View File

@ -57,6 +57,7 @@ type TextFormatter struct {
} }
func (f *TextFormatter) Format(entry *Entry) ([]byte, error) { func (f *TextFormatter) Format(entry *Entry) ([]byte, error) {
var b *bytes.Buffer
var keys []string = make([]string, 0, len(entry.Data)) var keys []string = make([]string, 0, len(entry.Data))
for k := range entry.Data { for k := range entry.Data {
keys = append(keys, k) keys = append(keys, k)
@ -65,8 +66,11 @@ func (f *TextFormatter) Format(entry *Entry) ([]byte, error) {
if !f.DisableSorting { if !f.DisableSorting {
sort.Strings(keys) sort.Strings(keys)
} }
if entry.Buffer != nil {
b := &bytes.Buffer{} b = entry.Buffer
} else {
b = &bytes.Buffer{}
}
prefixFieldClashes(entry.Data) prefixFieldClashes(entry.Data)