github.com/facebookincubator/go-belt@v0.0.0-20230703220935-39cd348f1a38/tool/logger/implementation/zap/logger.go (about)

     1  // Copyright 2022 Meta Platforms, Inc. and affiliates.
     2  //
     3  // Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
     4  //
     5  // 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
     6  //
     7  // 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
     8  //
     9  // 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
    10  //
    11  // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
    12  
    13  // Copyright (c) Facebook, Inc. and its affiliates.
    14  //
    15  // This source code is licensed under the MIT license found in the
    16  // LICENSE file in the root directory of this source tree.
    17  
    18  package zap
    19  
    20  import (
    21  	"fmt"
    22  	"os"
    23  	"strings"
    24  	"sync"
    25  	"sync/atomic"
    26  	"time"
    27  
    28  	"github.com/facebookincubator/go-belt"
    29  	"github.com/facebookincubator/go-belt/pkg/field"
    30  	"github.com/facebookincubator/go-belt/pkg/valuesparser"
    31  	"github.com/facebookincubator/go-belt/tool/logger"
    32  	"github.com/facebookincubator/go-belt/tool/logger/adapter"
    33  	"github.com/facebookincubator/go-belt/tool/logger/types"
    34  	"go.uber.org/zap"
    35  	"go.uber.org/zap/zapcore"
    36  )
    37  
    38  var (
    39  	// FieldNameTraceIDs is the field name used to store belt.TraceIDs.
    40  	FieldNameTraceIDs = "trace_id"
    41  )
    42  
    43  // Emitter is the implementation of types.Emitter based on a zap (non-sugared) logger.
    44  type Emitter struct {
    45  	ZapLogger *zap.Logger
    46  }
    47  
    48  var _ types.Emitter = (*Emitter)(nil)
    49  
    50  // NewEmitter returns a new instance of Emitter
    51  func NewEmitter(zapLogger *zap.Logger) Emitter {
    52  	return Emitter{
    53  		ZapLogger: zapLogger,
    54  	}
    55  }
    56  
    57  const (
    58  	preallocateFieldsSize = 16
    59  )
    60  
    61  var fieldsPool = sync.Pool{
    62  	New: func() any {
    63  		fields := make([]zap.Field, 0, preallocateFieldsSize)
    64  		return &fields
    65  	},
    66  }
    67  
    68  func acquireZapFields() *[]zap.Field {
    69  	return fieldsPool.Get().(*[]zap.Field)
    70  }
    71  
    72  func releaseZapFields(fieldsPtr *[]zap.Field) {
    73  	if fieldsPtr == nil || len(*fieldsPtr) >= 256 {
    74  		return
    75  	}
    76  	*fieldsPtr = (*fieldsPtr)[:0]
    77  	fieldsPool.Put(fieldsPtr)
    78  }
    79  
    80  // Flush implements types.Emitter.
    81  func (l Emitter) Flush() {
    82  	err := l.getZapLogger().Sync()
    83  	if err == nil {
    84  		return
    85  	}
    86  
    87  	errDesc := err.Error()
    88  	if strings.Contains(errDesc, "sync /dev/stderr: invalid argument") {
    89  		// Intentionally ignore this error, see https://github.com/uber-go/zap/issues/328
    90  		return
    91  	}
    92  
    93  	l.Emit(&types.Entry{
    94  		Timestamp: time.Now(),
    95  		Level:     types.LevelError,
    96  		Message:   fmt.Sprintf("unable to Sync(): %s", errDesc),
    97  	})
    98  }
    99  
   100  // CheckZapLevel returns true if the given zap's logging level is enabled in this logger.
   101  func (l Emitter) CheckZapLevel(level zapcore.Level) bool {
   102  	return l.getZapLogger().Core().Enabled(level)
   103  }
   104  
   105  // CheckLevel returns true if the given types.Level is enabled in this logger.
   106  func (l Emitter) CheckLevel(level types.Level) bool {
   107  	return l.CheckZapLevel(LevelToZap(level))
   108  }
   109  
   110  // Emit implements types.Emitter.
   111  func (l Emitter) Emit(entry *types.Entry) {
   112  	// We log panics and fatals even if logging level is lower because
   113  	// they supposed to trigger panic or os.Exit, and we cannot just return without that.
   114  	// So it should be silent, but destructive.
   115  	if entry.Level == types.LevelNone || !l.CheckLevel(entry.Level) && entry.Level > types.LevelPanic {
   116  		return
   117  	}
   118  
   119  	var zapFields []zap.Field
   120  	if !entry.Properties.Has(EntryPropertyIgnoreFields) && entry.Fields != nil {
   121  		zapFieldsPtr := fieldsToZap(entry.Fields.Len(), entry.Fields.ForEachField)
   122  		if zapFieldsPtr != nil {
   123  			defer releaseZapFields(zapFieldsPtr)
   124  			zapFields = *zapFieldsPtr
   125  		}
   126  	}
   127  
   128  	zapEntry := zapcore.Entry{
   129  		Level:      LevelToZap(entry.Level),
   130  		Time:       entry.Timestamp,
   131  		LoggerName: "",
   132  		Message:    entry.Message,
   133  		Stack:      "",
   134  	}
   135  	if entry.Caller != 0 {
   136  		file, line := entry.Caller.FileLine()
   137  		zapEntry.Caller = zapcore.EntryCaller{
   138  			Defined: true,
   139  			PC:      uintptr(entry.Caller),
   140  			File:    file,
   141  			Line:    line,
   142  		}
   143  	}
   144  
   145  	l.LogZapEntry(zapEntry, zapFields...)
   146  }
   147  
   148  // LogZapEntry logs an entry given its zap structure.
   149  func (l Emitter) LogZapEntry(zapEntry zapcore.Entry, zapFields ...zap.Field) {
   150  	l.ZapLogger.Core().Check(zapEntry, nil).Write(zapFields...)
   151  }
   152  
   153  type mostlyPersistentData struct {
   154  	entryPool       *sync.Pool
   155  	zapEntryPool    *sync.Pool
   156  	fmtBufPool      *sync.Pool
   157  	preHooks        logger.PreHooks
   158  	hooks           logger.Hooks
   159  	traceIDs        belt.TraceIDs
   160  	getCallerFunc   types.GetCallerPC
   161  	messagePrefix   string
   162  	entryProperties types.EntryProperties
   163  }
   164  
   165  // CompactLogger is an implementation of types.CompactLogger based on a zap logger.
   166  type CompactLogger struct {
   167  	*mostlyPersistentData
   168  	emitter            Emitter
   169  	contextFields      *field.FieldsChain
   170  	contextNewFields   uint32
   171  	prepareEmitterOnce sync.Once
   172  }
   173  
   174  var _ adapter.CompactLogger = (*CompactLogger)(nil)
   175  
   176  // Flush implements types.CompactLogger.
   177  func (l *CompactLogger) Flush() {
   178  	l.emitter.Flush()
   179  	for _, hook := range l.hooks {
   180  		hook.Flush()
   181  	}
   182  }
   183  
   184  var timeNow = time.Now
   185  
   186  func (l *CompactLogger) acquireEntry() *types.Entry {
   187  	entry := l.entryPool.Get().(*types.Entry)
   188  	entry.Timestamp = timeNow()
   189  	entry.Fields = l.contextFields
   190  	entry.Properties = append(entry.Properties, EntryPropertyIgnoreFields)
   191  	return entry
   192  }
   193  
   194  func (l *CompactLogger) releaseEntry(entry *types.Entry) {
   195  	entry.Caller = 0
   196  	entry.Fields = nil
   197  	entry.Message = ""
   198  	entry.Properties = entry.Properties[:0]
   199  	l.entryPool.Put(entry)
   200  }
   201  
   202  func (l *CompactLogger) acquireZapEntry() *zapcore.Entry {
   203  	entry := l.zapEntryPool.Get().(*zapcore.Entry)
   204  	entry.Time = timeNow()
   205  	return entry
   206  }
   207  
   208  func (l *CompactLogger) releaseZapEntry(entry *zapcore.Entry) {
   209  	entry.Message = ""
   210  	entry.Stack = ""
   211  	entry.Caller.Defined = false
   212  	l.zapEntryPool.Put(entry)
   213  }
   214  
   215  func (l *CompactLogger) acquireBuf() *strings.Builder {
   216  	return l.fmtBufPool.Get().(*strings.Builder)
   217  }
   218  
   219  func (l *CompactLogger) releaseBuf(buf *strings.Builder) {
   220  	if buf.Cap() > 1024 {
   221  		return
   222  	}
   223  	buf.Reset()
   224  	l.fmtBufPool.Put(buf)
   225  }
   226  
   227  func (l *CompactLogger) logEntry(entry *logger.Entry) {
   228  	if !entry.Caller.Defined() && l.getCallerFunc != nil {
   229  		entry.Caller = l.getCallerFunc()
   230  	}
   231  	if len(l.entryProperties) > 0 {
   232  		entry.Properties = append(entry.Properties, l.entryProperties)
   233  	}
   234  	if !adapter.ProcessHooks(l.hooks, entry) {
   235  		return
   236  	}
   237  
   238  	zapEntry := l.acquireZapEntry()
   239  	defer l.releaseZapEntry(zapEntry)
   240  
   241  	zapEntry.Time = entry.Timestamp
   242  	zapEntry.Caller.Defined = entry.Caller.Defined()
   243  	if zapEntry.Caller.Defined {
   244  		file, line := entry.Caller.FileLine()
   245  		zapEntry.Caller = zapcore.EntryCaller{
   246  			Defined: true,
   247  			PC:      uintptr(entry.Caller),
   248  			File:    file,
   249  			Line:    line,
   250  		}
   251  	}
   252  	zapEntry.Message = entry.Message
   253  	zapEntry.Level = LevelToZap(entry.Level)
   254  	var zapFields []zap.Field
   255  	zapFieldsPtr := fieldsToZap(entry.Fields.Len(), entry.Fields.ForEachField)
   256  	if zapFieldsPtr != nil {
   257  		defer releaseZapFields(zapFieldsPtr)
   258  		zapFields = *zapFieldsPtr
   259  	}
   260  
   261  	l.logZapEntryNoHooks(zapEntry, zapFields...)
   262  }
   263  
   264  func (l *CompactLogger) logZapEntryNoHooks(zapEntry *zapcore.Entry, zapFields ...zapcore.Field) {
   265  	l.prepareEmitter()
   266  	l.zapSetCaller(zapEntry)
   267  	l.emitter.LogZapEntry(*zapEntry, zapFields...)
   268  
   269  	// zap authors decided not to panic or/and exit on Panics and Fatals,
   270  	// see: https://github.com/uber-go/zap/issues/358
   271  	//
   272  	// So doing this manually here:
   273  	switch zapEntry.Level {
   274  	case zap.PanicLevel, zap.DPanicLevel:
   275  		panic(fmt.Sprintf("%#+v: %#+v", *zapEntry, zapFields))
   276  	case zap.FatalLevel:
   277  		os.Exit(1)
   278  	}
   279  }
   280  
   281  func (l *CompactLogger) zapSetCaller(zapEntry *zapcore.Entry) {
   282  	if zapEntry.Caller.Defined || l.getCallerFunc == nil {
   283  		return
   284  	}
   285  
   286  	caller := l.getCallerFunc()
   287  	if !caller.Defined() {
   288  		return
   289  	}
   290  	file, line := caller.FileLine()
   291  
   292  	zapEntry.Caller = zapcore.NewEntryCaller(
   293  		uintptr(caller),
   294  		file,
   295  		line,
   296  		true,
   297  	)
   298  }
   299  
   300  // LogFields implements types.CompactLogger.
   301  func (l *CompactLogger) LogFields(level types.Level, message string, fields field.AbstractFields) {
   302  	preHooksResult := adapter.LogFieldsPreprocess(l.preHooks, l.traceIDs, level, l.emitter.CheckLevel(level), message, fields)
   303  	if preHooksResult.Skip {
   304  		return
   305  	}
   306  
   307  	if preHooksResult.ExtraFields != nil {
   308  		fields = field.Slice[field.AbstractFields]{fields, preHooksResult.ExtraFields}
   309  	}
   310  
   311  	if len(l.hooks) != 0 {
   312  		entry := l.acquireEntry()
   313  		defer l.releaseEntry(entry)
   314  
   315  		entry.Level = level
   316  		entry.Message = l.messagePrefix + message
   317  		entry.Fields = fields
   318  		l.logEntry(entry)
   319  		return
   320  	}
   321  
   322  	entry := l.acquireZapEntry()
   323  	defer l.releaseZapEntry(entry)
   324  
   325  	entry.Level = LevelToZap(level)
   326  	entry.Message = l.messagePrefix + message
   327  
   328  	var (
   329  		zapFields    []zap.Field
   330  		zapFieldsPtr *[]zap.Field
   331  	)
   332  	zapFieldsPtr = fieldsToZap(fields.Len(), fields.ForEachField)
   333  	if zapFieldsPtr != nil {
   334  		defer releaseZapFields(zapFieldsPtr)
   335  		zapFields = *zapFieldsPtr
   336  	}
   337  	l.logZapEntryNoHooks(entry, zapFields...)
   338  }
   339  
   340  // Logf implements types.CompactLogger.
   341  func (l *CompactLogger) Logf(level types.Level, format string, args ...any) {
   342  	preHooksResult := adapter.LogfPreprocess(l.preHooks, l.traceIDs, level, l.emitter.CheckLevel(level), format, args...)
   343  	if preHooksResult.Skip {
   344  		return
   345  	}
   346  
   347  	buf := l.acquireBuf()
   348  	defer l.releaseBuf(buf)
   349  	if len(l.messagePrefix) > 0 {
   350  		buf.WriteString(l.messagePrefix)
   351  	}
   352  	fmt.Fprintf(buf, format, args...)
   353  
   354  	if len(l.hooks) != 0 {
   355  		entry := l.acquireEntry()
   356  		defer l.releaseEntry(entry)
   357  
   358  		entry.Level = level
   359  		entry.Message = buf.String()
   360  		entry.Fields = preHooksResult.ExtraFields
   361  		l.logEntry(entry)
   362  		return
   363  	}
   364  
   365  	entry := l.acquireZapEntry()
   366  	defer l.releaseZapEntry(entry)
   367  
   368  	entry.Level = LevelToZap(level)
   369  	entry.Message = buf.String()
   370  
   371  	var zapFields []zap.Field
   372  	if preHooksResult.ExtraFields != nil {
   373  		zapFieldsPtr := fieldsToZap(preHooksResult.ExtraFields.Len(), preHooksResult.ExtraFields.ForEachField)
   374  		if zapFieldsPtr != nil {
   375  			defer releaseZapFields(zapFieldsPtr)
   376  			zapFields = *zapFieldsPtr
   377  		}
   378  	}
   379  
   380  	l.logZapEntryNoHooks(entry, zapFields...)
   381  }
   382  
   383  // Log implements types.CompactLogger.
   384  func (l *CompactLogger) Log(level types.Level, values ...any) {
   385  	forceProcess := level == logger.LevelFatal || level == logger.LevelPanic
   386  
   387  	preHooksResult := adapter.LogPreprocess(l.preHooks, l.traceIDs, level, l.emitter.CheckLevel(level), values...)
   388  	if preHooksResult.Skip && !forceProcess {
   389  		return
   390  	}
   391  
   392  	if len(values) == 1 {
   393  		if entry, ok := values[0].(*logger.Entry); ok {
   394  			if entry.TraceIDs != nil {
   395  				entry.Fields = field.Add(entry.Fields, preHooksResult.ExtraFields, &field.Field{Key: FieldNameTraceIDs, Value: entry.TraceIDs})
   396  			} else {
   397  				entry.Fields = field.Add(entry.Fields, preHooksResult.ExtraFields)
   398  			}
   399  			l.logEntry(entry)
   400  			return
   401  		}
   402  	}
   403  
   404  	valuesParser := valuesparser.AnySlice(values)
   405  
   406  	if len(l.hooks) != 0 {
   407  		entry := l.acquireEntry()
   408  		defer l.releaseEntry(entry)
   409  
   410  		entry.Level = level
   411  		entry.Fields = field.Add(entry.Fields, preHooksResult.ExtraFields)
   412  
   413  		buf := l.acquireBuf()
   414  		defer l.releaseBuf(buf)
   415  		valuesParser.ForEachField(func(f *field.Field) bool { return true }) // just causing to parse the fields to make valuesParser.WriteUnparsed(buf) work correctly
   416  		buf.WriteString(l.messagePrefix)
   417  		valuesParser.WriteUnparsed(buf)
   418  		entry.Message = buf.String()
   419  
   420  		l.logEntry(entry)
   421  		return
   422  	}
   423  
   424  	entry := l.acquireZapEntry()
   425  	defer l.releaseZapEntry(entry)
   426  
   427  	entry.Level = LevelToZap(level)
   428  
   429  	var (
   430  		zapFields    []zap.Field
   431  		zapFieldsPtr *[]zap.Field
   432  	)
   433  	if preHooksResult.ExtraFields != nil {
   434  		fields := field.Slice[field.AbstractFields]{&valuesParser, preHooksResult.ExtraFields}
   435  		zapFieldsPtr = fieldsToZap(fields.Len(), fields.ForEachField)
   436  	} else {
   437  		zapFieldsPtr = fieldsToZap(valuesParser.Len(), valuesParser.ForEachField)
   438  	}
   439  	if zapFieldsPtr != nil {
   440  		defer releaseZapFields(zapFieldsPtr)
   441  		zapFields = *zapFieldsPtr
   442  	}
   443  
   444  	buf := l.acquireBuf()
   445  	defer l.releaseBuf(buf)
   446  	buf.WriteString(l.messagePrefix)
   447  	valuesParser.WriteUnparsed(buf)
   448  	entry.Message = buf.String()
   449  
   450  	l.logZapEntryNoHooks(entry, zapFields...)
   451  }
   452  
   453  // Level implements types.CompactLogger.
   454  func (l *CompactLogger) Level() types.Level {
   455  	core := l.emitter.ZapLogger.Core()
   456  	for level := types.EndOfLevel - 1; level >= 0; level-- {
   457  		if core.Enabled(LevelToZap(level)) {
   458  			return level
   459  		}
   460  	}
   461  	return types.LevelNone
   462  }
   463  
   464  // WithLevel implements types.CompactLogger.
   465  func (l *CompactLogger) WithLevel(newLevel types.Level) adapter.CompactLogger {
   466  	branch := l.branch()
   467  	branch.emitter.ZapLogger = branch.emitter.ZapLogger.WithOptions(zap.IncreaseLevel(LevelToZap(newLevel)))
   468  	return branch
   469  }
   470  
   471  func (l *CompactLogger) branch() *CompactLogger {
   472  	return &CompactLogger{
   473  		mostlyPersistentData: l.mostlyPersistentData,
   474  		emitter:              Emitter{ZapLogger: l.emitter.getZapLogger()},
   475  		contextFields:        l.contextFields,
   476  		contextNewFields:     atomic.LoadUint32(&l.contextNewFields),
   477  	}
   478  }
   479  
   480  func (l *CompactLogger) clone() *CompactLogger {
   481  	clone := l.branch()
   482  	clone.mostlyPersistentData = &[]mostlyPersistentData{*l.mostlyPersistentData}[0]
   483  	return clone
   484  }
   485  
   486  // WithMessagePrefix implements types.CompactLogger.
   487  func (l *CompactLogger) WithMessagePrefix(prefix string) adapter.CompactLogger {
   488  	clone := l.clone()
   489  	clone.messagePrefix += prefix
   490  	return clone
   491  }
   492  
   493  // WithEntryProperties implements types.CompactLogger.
   494  func (l *CompactLogger) WithEntryProperties(props ...types.EntryProperty) adapter.CompactLogger {
   495  	clone := l.clone()
   496  	clone.entryProperties = clone.entryProperties.Add(props)
   497  	return clone
   498  }
   499  
   500  // WithHooks implements types.CompactLogger.
   501  func (l *CompactLogger) WithHooks(hooks ...types.Hook) adapter.CompactLogger {
   502  	clone := l.clone()
   503  	clone.hooks = make(types.Hooks, len(l.hooks)+len(hooks))
   504  	copy(clone.hooks, l.hooks)
   505  	copy(clone.hooks[len(l.hooks):], hooks)
   506  	return clone
   507  }
   508  
   509  // WithPreHooks implements types.CompactLogger.
   510  func (l *CompactLogger) WithPreHooks(preHooks ...types.PreHook) adapter.CompactLogger {
   511  	clone := l.clone()
   512  	clone.preHooks = make(types.PreHooks, len(l.preHooks)+len(preHooks))
   513  	copy(clone.preHooks, l.preHooks)
   514  	copy(clone.preHooks[len(l.preHooks):], preHooks)
   515  	return clone
   516  }
   517  
   518  // WithField implements types.CompactLogger.
   519  func (l *CompactLogger) WithField(
   520  	key field.Key,
   521  	value field.Value,
   522  	props ...field.Property,
   523  ) adapter.CompactLogger {
   524  	branch := l.branch()
   525  	branch.contextFields = l.contextFields.WithField(key, value, props)
   526  	branch.contextNewFields++
   527  	return branch
   528  }
   529  
   530  // WithFields implements types.CompactLogger.
   531  func (l *CompactLogger) WithFields(fields field.AbstractFields) adapter.CompactLogger {
   532  	branch := l.branch()
   533  	branch.contextFields = l.contextFields.WithFields(fields)
   534  	branch.contextNewFields += uint32(fields.Len())
   535  	return branch
   536  }
   537  
   538  // WithTraceIDs implements types.CompactLogger and belt.Tool.
   539  func (l *CompactLogger) WithTraceIDs(allTraceIDs belt.TraceIDs, newTraceIDsCount int) belt.Tool {
   540  	clone := l.clone()
   541  	clone.traceIDs = allTraceIDs
   542  	clone.contextFields = clone.contextFields.WithField(FieldNameTraceIDs, allTraceIDs)
   543  	clone.contextNewFields++
   544  	return clone
   545  }
   546  
   547  // WithContextFields implements types.CompactLogger and belt.Tool.
   548  func (l *CompactLogger) WithContextFields(allFields *field.FieldsChain, newFieldsCount int) belt.Tool {
   549  	branch := l.branch()
   550  	branch.contextFields = allFields
   551  	branch.contextNewFields += uint32(newFieldsCount)
   552  	return branch
   553  }
   554  
   555  func (l *CompactLogger) compileEmitterFields() {
   556  	// This function is the only one which can change
   557  	// the value of l.contextNewFields, and it is called
   558  	// only within l.prepareEmitterOnce.Do, so:
   559  	// * We do not need to atomically load the l.contextNewFields value.
   560  	// * We still need to atomically store the l.contextNewFields value,
   561  	//   because other goroutines may read it concurrently in other functions.
   562  	if l.contextNewFields == 0 {
   563  		return
   564  	}
   565  	defer atomic.StoreUint32(&l.contextNewFields, 0)
   566  	zapFieldsPtr := fieldsToZap(int(l.contextNewFields), l.contextFields.ForEachField)
   567  	if zapFieldsPtr == nil {
   568  		return
   569  	}
   570  	defer releaseZapFields(zapFieldsPtr)
   571  	l.emitter.setZapLogger(l.emitter.ZapLogger.With(*zapFieldsPtr...))
   572  }
   573  
   574  func (l *CompactLogger) prepareEmitter() {
   575  	l.prepareEmitterOnce.Do(func() {
   576  		l.compileEmitterFields()
   577  	})
   578  }
   579  
   580  // Emitter implements types.CompactLogger.
   581  func (l *CompactLogger) Emitter() types.Emitter {
   582  	l.prepareEmitter()
   583  	return l.emitter
   584  }
   585  
   586  // DefaultZapLogger is the (overridable) function which returns
   587  // a zap logger with the default configuration.
   588  //
   589  // Do not override this anywhere but in the `main` package.
   590  var DefaultZapLogger = func() *zap.Logger {
   591  	cfg := zap.NewProductionConfig()
   592  	cfg.Level = zap.NewAtomicLevelAt(LevelToZap(logger.LevelTrace))
   593  	zapLogger, err := cfg.Build()
   594  	if err != nil {
   595  		panic(err)
   596  	}
   597  	return zapLogger
   598  }
   599  
   600  // Default returns a logger.Logger using the default zap logger
   601  // (see DefaultZapLogger).
   602  func Default() types.Logger {
   603  	return New(DefaultZapLogger())
   604  }
   605  
   606  // New returns a new instance of logger.Logger given a zap logger.
   607  func New(logger *zap.Logger, opts ...types.Option) types.Logger {
   608  	return adapter.GenericSugar{
   609  		CompactLogger: newCompactLoggerFromZap(logger, opts...),
   610  	}
   611  }
   612  
   613  func newCompactLoggerFromZap(zapLogger *zap.Logger, opts ...types.Option) *CompactLogger {
   614  	cfg := types.Options(opts).Config()
   615  	return &CompactLogger{
   616  		emitter: NewEmitter(zapLogger),
   617  		mostlyPersistentData: &mostlyPersistentData{
   618  			getCallerFunc: cfg.GetCallerFunc,
   619  			fmtBufPool: &sync.Pool{
   620  				New: func() any {
   621  					return &strings.Builder{}
   622  				},
   623  			},
   624  			entryPool: &sync.Pool{
   625  				New: func() any {
   626  					return &types.Entry{}
   627  				},
   628  			},
   629  			zapEntryPool: &sync.Pool{
   630  				New: func() any {
   631  					return &zapcore.Entry{}
   632  				},
   633  			},
   634  		},
   635  	}
   636  }