blob: 918d2dd02366eed84357296f3b435a4ac8d8f53b [file] [log] [blame]
// Copyright 2022 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package zap_benchmarks
import (
"io"
"sync"
"time"
"go.uber.org/zap"
"go.uber.org/zap/buffer"
"go.uber.org/zap/zapcore"
)
// from zap/internal/ztest
// A syncer is a spy for the Sync portion of zapcore.WriteSyncer.
type syncer struct {
err error
called bool
}
// SetError sets the error that the Sync method will return.
func (s *syncer) SetError(err error) {
s.err = err
}
// Sync records that it was called, then returns the user-supplied error (if
// any).
func (s *syncer) Sync() error {
s.called = true
return s.err
}
// Called reports whether the Sync method was called.
func (s *syncer) Called() bool {
return s.called
}
// A discarder sends all writes to ioutil.Discard.
type discarder struct{ syncer }
// Write implements io.Writer.
func (d *discarder) Write(b []byte) (int, error) {
return io.Discard.Write(b)
}
// fastTextEncoder mimics slog/benchmarks.fastTextHandler.
type fastTextEncoder struct {
buf *buffer.Buffer
zapcore.ObjectEncoder
}
var bufferPool = buffer.NewPool()
var tePool = sync.Pool{
New: func() any { return &fastTextEncoder{} },
}
func newFastTextEncoder() *fastTextEncoder {
e := tePool.Get().(*fastTextEncoder)
e.buf = bufferPool.Get()
return e
}
func (c *fastTextEncoder) Clone() zapcore.Encoder {
clone := newFastTextEncoder()
if c.buf != nil {
panic("buf should be nil")
clone.buf.Write(c.buf.Bytes())
}
return clone
}
func (c *fastTextEncoder) EncodeEntry(e zapcore.Entry, fs []zap.Field) (*buffer.Buffer, error) {
c2 := newFastTextEncoder()
if !e.Time.IsZero() {
c2.buf.AppendString("time=")
c2.appendTime(e.Time)
c2.buf.AppendByte(' ')
}
c2.buf.AppendString("level=")
c2.buf.AppendInt(int64(e.Level))
c2.buf.AppendByte(' ')
c2.buf.AppendString("msg=")
c2.buf.AppendString(e.Message)
for _, f := range fs {
c2.buf.AppendByte(' ')
f.AddTo(c2)
}
c2.buf.AppendString("\n")
buf := c2.buf
tePool.Put(c2)
return buf, nil
}
func (c *fastTextEncoder) AddString(key, value string) {
c.buf.AppendString(key)
c.buf.AppendByte('=')
c.buf.AppendString(value)
}
func (c *fastTextEncoder) AddTime(key string, value time.Time) {
c.buf.AppendString(key)
c.buf.AppendByte('=')
c.appendTime(value)
}
func (c *fastTextEncoder) AddDuration(key string, value time.Duration) {
c.buf.AppendString(key)
c.buf.AppendByte('=')
c.buf.AppendInt(value.Nanoseconds())
}
func (c *fastTextEncoder) AddInt64(key string, value int64) {
c.buf.AppendString(key)
c.buf.AppendByte('=')
c.buf.AppendInt(value)
}
func (c *fastTextEncoder) appendTime(t time.Time) {
c.buf.AppendInt(t.Unix())
}
// asyncCore mimics slog/benchmarks.asyncHandler.
type asyncCore struct {
ringBuffer [100]entryAndFields
next int
}
type entryAndFields struct {
e zapcore.Entry
f []zap.Field
}
func (*asyncCore) Enabled(zapcore.Level) bool { return true }
func (c *asyncCore) With([]zap.Field) zapcore.Core { return c }
func (*asyncCore) Sync() error { return nil }
// Also needed to make this non-trivial.
func (c *asyncCore) Check(ent zapcore.Entry, ce *zapcore.CheckedEntry) *zapcore.CheckedEntry {
return ce.AddCore(ent, c)
}
func (c *asyncCore) Write(e zapcore.Entry, f []zap.Field) error {
c.ringBuffer[c.next] = entryAndFields{e, f}
c.next = (c.next + 1) % len(c.ringBuffer)
return nil
}