github.com/facebookincubator/go-belt@v0.0.0-20230703220935-39cd348f1a38/tool/logger/implementation/zap/bench_test.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  package zap
    14  
    15  import (
    16  	"fmt"
    17  	"os"
    18  	"testing"
    19  
    20  	"github.com/facebookincubator/go-belt/pkg/field"
    21  	"go.uber.org/zap"
    22  	"go.uber.org/zap/zapcore"
    23  )
    24  
    25  type zapConfig struct {
    26  	Name   string
    27  	Logger *zap.Logger
    28  }
    29  
    30  func zapConfigs(t interface{ Fatal(...any) }) []zapConfig {
    31  	var err error
    32  
    33  	stdErr := os.Stderr
    34  	os.Stderr, err = os.Open("/dev/null")
    35  	if err != nil {
    36  		t.Fatal(err)
    37  	}
    38  	zapProd, err := zap.NewProduction()
    39  	if err != nil {
    40  		t.Fatal(err)
    41  	}
    42  	zapDev, err := zap.NewDevelopment()
    43  	if err != nil {
    44  		t.Fatal(err)
    45  	}
    46  	os.Stderr = stdErr
    47  
    48  	return []zapConfig{
    49  		{
    50  			Name:   "prod",
    51  			Logger: zapProd,
    52  		},
    53  		{
    54  			Name:   "dev",
    55  			Logger: zapDev,
    56  		},
    57  		{
    58  			Name:   "nop",
    59  			Logger: zap.NewNop(),
    60  		},
    61  	}
    62  }
    63  
    64  func Benchmark(b *testing.B) {
    65  	for _, zapConfig := range zapConfigs(b) {
    66  		b.Run(zapConfig.Name, func(b *testing.B) {
    67  
    68  			for depth := 0; depth <= 256; depth = 1 + depth*4/3 {
    69  				var keys [256][4]string
    70  				for i, _keys := range keys {
    71  					for j := range _keys {
    72  						keys[i][j] = fmt.Sprintf("key %d:%d", i, j)
    73  					}
    74  				}
    75  				b.Run(fmt.Sprintf("depth%d", depth), func(b *testing.B) {
    76  					b.Run("WithField", func(b *testing.B) {
    77  						for _, callLog := range []bool{false, true} {
    78  							b.Run(fmt.Sprintf("callLog-%v", callLog), func(b *testing.B) {
    79  								b.Run("bare_zap", func(b *testing.B) {
    80  									lOrig := zapConfig.Logger
    81  									b.ReportAllocs()
    82  									b.ResetTimer()
    83  									for i := 0; i < b.N; i++ {
    84  										l := lOrig
    85  										for num := 0; num < depth; num++ {
    86  											l = l.With(zap.Field{
    87  												Key:    keys[num][0],
    88  												Type:   zapcore.StringType,
    89  												String: "some value",
    90  											})
    91  											l = l.With(
    92  												zap.Field{
    93  													Key:    keys[num][1],
    94  													Type:   zapcore.StringType,
    95  													String: "more values 1",
    96  												},
    97  												zap.Field{
    98  													Key:    keys[num][2],
    99  													Type:   zapcore.StringType,
   100  													String: "more values 2",
   101  												},
   102  												zap.Field{
   103  													Key:     keys[num][3],
   104  													Type:    zapcore.Int64Type,
   105  													Integer: 3,
   106  												},
   107  											)
   108  										}
   109  										if callLog {
   110  											l.Error("unit-test")
   111  										}
   112  									}
   113  								})
   114  								b.Run("adapted_zap", func(b *testing.B) {
   115  									lOrig := New(zapConfig.Logger)
   116  									b.ReportAllocs()
   117  									b.ResetTimer()
   118  									for i := 0; i < b.N; i++ {
   119  										l := lOrig
   120  										for num := 0; num < depth; num++ {
   121  											l = l.WithField(keys[num][0], "some value")
   122  											l = l.WithFields(field.Fields{
   123  												{Key: keys[num][1], Value: "more values 1"},
   124  												{Key: keys[num][2], Value: "more values 2"},
   125  												{Key: keys[num][3], Value: 3},
   126  											})
   127  										}
   128  										if callLog {
   129  											l.Errorf("unit-test")
   130  										}
   131  									}
   132  								})
   133  							})
   134  						}
   135  					})
   136  					b.Run("Log", func(b *testing.B) {
   137  						zapLogger := zapConfig.Logger
   138  						for num := 0; num < depth; num++ {
   139  							zapLogger = zapLogger.With(zap.Field{
   140  								Key:    keys[num][0],
   141  								Type:   zapcore.StringType,
   142  								String: "some value",
   143  							})
   144  						}
   145  
   146  						for fieldNum := 0; fieldNum < 8; fieldNum++ {
   147  							b.Run(fmt.Sprintf("fields-%d", fieldNum), func(b *testing.B) {
   148  								b.Run("bare_zap", func(b *testing.B) {
   149  									l := zapLogger
   150  									var fields []zap.Field
   151  									for i := 0; i < fieldNum; i++ {
   152  										fields = append(fields, zap.Field{
   153  											Key:    fmt.Sprintf("key %d", i),
   154  											Type:   zapcore.StringType,
   155  											String: fmt.Sprintf("value %d", i),
   156  										})
   157  									}
   158  									b.ReportAllocs()
   159  									b.ResetTimer()
   160  									for i := 0; i < b.N; i++ {
   161  										l.Error("unit-test", fields...)
   162  									}
   163  								})
   164  								b.Run("adapted_zap", func(b *testing.B) {
   165  									l := New(zapLogger)
   166  									var fields field.Fields
   167  									for i := 0; i < fieldNum; i++ {
   168  										fields = append(fields, field.Field{
   169  											Key:   fmt.Sprintf("key %d", i),
   170  											Value: fmt.Sprintf("value %d", i),
   171  										})
   172  									}
   173  									b.ReportAllocs()
   174  									b.ResetTimer()
   175  									for i := 0; i < b.N; i++ {
   176  										l.ErrorFields("unit-test", &fields)
   177  									}
   178  								})
   179  							})
   180  						}
   181  					})
   182  				})
   183  			}
   184  		})
   185  	}
   186  }