logger_bench_test.go 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222
  1. // Copyright (c) 2016 Uber Technologies, Inc.
  2. //
  3. // Permission is hereby granted, free of charge, to any person obtaining a copy
  4. // of this software and associated documentation files (the "Software"), to deal
  5. // in the Software without restriction, including without limitation the rights
  6. // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  7. // copies of the Software, and to permit persons to whom the Software is
  8. // furnished to do so, subject to the following conditions:
  9. //
  10. // The above copyright notice and this permission notice shall be included in
  11. // all copies or substantial portions of the Software.
  12. //
  13. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  14. // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  15. // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  16. // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  17. // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  18. // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  19. // THE SOFTWARE.
  20. package zap
  21. import (
  22. "errors"
  23. "testing"
  24. "time"
  25. "go.uber.org/zap/internal/ztest"
  26. "go.uber.org/zap/zapcore"
  27. )
  28. type user struct {
  29. Name string
  30. Email string
  31. CreatedAt time.Time
  32. }
  33. func (u *user) MarshalLogObject(enc zapcore.ObjectEncoder) error {
  34. enc.AddString("name", u.Name)
  35. enc.AddString("email", u.Email)
  36. enc.AddInt64("created_at", u.CreatedAt.UnixNano())
  37. return nil
  38. }
  39. var _jane = &user{
  40. Name: "Jane Doe",
  41. Email: "jane@test.com",
  42. CreatedAt: time.Date(1980, 1, 1, 12, 0, 0, 0, time.UTC),
  43. }
  44. func withBenchedLogger(b *testing.B, f func(*Logger)) {
  45. logger := New(
  46. zapcore.NewCore(
  47. zapcore.NewJSONEncoder(NewProductionConfig().EncoderConfig),
  48. &ztest.Discarder{},
  49. DebugLevel,
  50. ))
  51. b.ResetTimer()
  52. b.RunParallel(func(pb *testing.PB) {
  53. for pb.Next() {
  54. f(logger)
  55. }
  56. })
  57. }
  58. func BenchmarkNoContext(b *testing.B) {
  59. withBenchedLogger(b, func(log *Logger) {
  60. log.Info("No context.")
  61. })
  62. }
  63. func BenchmarkBoolField(b *testing.B) {
  64. withBenchedLogger(b, func(log *Logger) {
  65. log.Info("Boolean.", Bool("foo", true))
  66. })
  67. }
  68. func BenchmarkByteStringField(b *testing.B) {
  69. val := []byte("bar")
  70. withBenchedLogger(b, func(log *Logger) {
  71. log.Info("ByteString.", ByteString("foo", val))
  72. })
  73. }
  74. func BenchmarkFloat64Field(b *testing.B) {
  75. withBenchedLogger(b, func(log *Logger) {
  76. log.Info("Floating point.", Float64("foo", 3.14))
  77. })
  78. }
  79. func BenchmarkIntField(b *testing.B) {
  80. withBenchedLogger(b, func(log *Logger) {
  81. log.Info("Integer.", Int("foo", 42))
  82. })
  83. }
  84. func BenchmarkInt64Field(b *testing.B) {
  85. withBenchedLogger(b, func(log *Logger) {
  86. log.Info("64-bit integer.", Int64("foo", 42))
  87. })
  88. }
  89. func BenchmarkStringField(b *testing.B) {
  90. withBenchedLogger(b, func(log *Logger) {
  91. log.Info("Strings.", String("foo", "bar"))
  92. })
  93. }
  94. func BenchmarkStringerField(b *testing.B) {
  95. withBenchedLogger(b, func(log *Logger) {
  96. log.Info("Level.", Stringer("foo", InfoLevel))
  97. })
  98. }
  99. func BenchmarkTimeField(b *testing.B) {
  100. t := time.Unix(0, 0)
  101. withBenchedLogger(b, func(log *Logger) {
  102. log.Info("Time.", Time("foo", t))
  103. })
  104. }
  105. func BenchmarkDurationField(b *testing.B) {
  106. withBenchedLogger(b, func(log *Logger) {
  107. log.Info("Duration", Duration("foo", time.Second))
  108. })
  109. }
  110. func BenchmarkErrorField(b *testing.B) {
  111. err := errors.New("egad")
  112. withBenchedLogger(b, func(log *Logger) {
  113. log.Info("Error.", Error(err))
  114. })
  115. }
  116. func BenchmarkErrorsField(b *testing.B) {
  117. errs := []error{
  118. errors.New("egad"),
  119. errors.New("oh no"),
  120. errors.New("dear me"),
  121. errors.New("such fail"),
  122. }
  123. withBenchedLogger(b, func(log *Logger) {
  124. log.Info("Errors.", Errors("errors", errs))
  125. })
  126. }
  127. func BenchmarkStackField(b *testing.B) {
  128. withBenchedLogger(b, func(log *Logger) {
  129. log.Info("Error.", Stack("stacktrace"))
  130. })
  131. }
  132. func BenchmarkObjectField(b *testing.B) {
  133. withBenchedLogger(b, func(log *Logger) {
  134. log.Info("Arbitrary ObjectMarshaler.", Object("user", _jane))
  135. })
  136. }
  137. func BenchmarkReflectField(b *testing.B) {
  138. withBenchedLogger(b, func(log *Logger) {
  139. log.Info("Reflection-based serialization.", Reflect("user", _jane))
  140. })
  141. }
  142. func BenchmarkAddCallerHook(b *testing.B) {
  143. logger := New(
  144. zapcore.NewCore(
  145. zapcore.NewJSONEncoder(NewProductionConfig().EncoderConfig),
  146. &ztest.Discarder{},
  147. InfoLevel,
  148. ),
  149. AddCaller(),
  150. )
  151. b.ResetTimer()
  152. b.RunParallel(func(pb *testing.PB) {
  153. for pb.Next() {
  154. logger.Info("Caller.")
  155. }
  156. })
  157. }
  158. func Benchmark10Fields(b *testing.B) {
  159. withBenchedLogger(b, func(log *Logger) {
  160. log.Info("Ten fields, passed at the log site.",
  161. Int("one", 1),
  162. Int("two", 2),
  163. Int("three", 3),
  164. Int("four", 4),
  165. Int("five", 5),
  166. Int("six", 6),
  167. Int("seven", 7),
  168. Int("eight", 8),
  169. Int("nine", 9),
  170. Int("ten", 10),
  171. )
  172. })
  173. }
  174. func Benchmark100Fields(b *testing.B) {
  175. const batchSize = 50
  176. logger := New(zapcore.NewCore(
  177. zapcore.NewJSONEncoder(NewProductionConfig().EncoderConfig),
  178. &ztest.Discarder{},
  179. DebugLevel,
  180. ))
  181. // Don't include allocating these helper slices in the benchmark. Since
  182. // access to them isn't synchronized, we can't run the benchmark in
  183. // parallel.
  184. first := make([]Field, batchSize)
  185. second := make([]Field, batchSize)
  186. b.ResetTimer()
  187. for i := 0; i < b.N; i++ {
  188. for i := 0; i < batchSize; i++ {
  189. // We're duplicating keys, but that doesn't affect performance.
  190. first[i] = Int("foo", i)
  191. second[i] = Int("foo", i+batchSize)
  192. }
  193. logger.With(first...).Info("Child loggers with lots of context.", second...)
  194. }
  195. }