example_test.go 9.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327
  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_test
  21. import (
  22. "encoding/json"
  23. "io/ioutil"
  24. "log"
  25. "os"
  26. "time"
  27. "go.uber.org/zap"
  28. "go.uber.org/zap/zapcore"
  29. )
  30. func Example_presets() {
  31. // Using zap's preset constructors is the simplest way to get a feel for the
  32. // package, but they don't allow much customization.
  33. logger := zap.NewExample() // or NewProduction, or NewDevelopment
  34. defer logger.Sync()
  35. const url = "http://example.com"
  36. // In most circumstances, use the SugaredLogger. It's 4-10x faster than most
  37. // other structured logging packages and has a familiar, loosely-typed API.
  38. sugar := logger.Sugar()
  39. sugar.Infow("Failed to fetch URL.",
  40. // Structured context as loosely typed key-value pairs.
  41. "url", url,
  42. "attempt", 3,
  43. "backoff", time.Second,
  44. )
  45. sugar.Infof("Failed to fetch URL: %s", url)
  46. // In the unusual situations where every microsecond matters, use the
  47. // Logger. It's even faster than the SugaredLogger, but only supports
  48. // structured logging.
  49. logger.Info("Failed to fetch URL.",
  50. // Structured context as strongly typed fields.
  51. zap.String("url", url),
  52. zap.Int("attempt", 3),
  53. zap.Duration("backoff", time.Second),
  54. )
  55. // Output:
  56. // {"level":"info","msg":"Failed to fetch URL.","url":"http://example.com","attempt":3,"backoff":"1s"}
  57. // {"level":"info","msg":"Failed to fetch URL: http://example.com"}
  58. // {"level":"info","msg":"Failed to fetch URL.","url":"http://example.com","attempt":3,"backoff":"1s"}
  59. }
  60. func Example_basicConfiguration() {
  61. // For some users, the presets offered by the NewProduction, NewDevelopment,
  62. // and NewExample constructors won't be appropriate. For most of those
  63. // users, the bundled Config struct offers the right balance of flexibility
  64. // and convenience. (For more complex needs, see the AdvancedConfiguration
  65. // example.)
  66. //
  67. // See the documentation for Config and zapcore.EncoderConfig for all the
  68. // available options.
  69. rawJSON := []byte(`{
  70. "level": "debug",
  71. "encoding": "json",
  72. "outputPaths": ["stdout", "/tmp/logs"],
  73. "errorOutputPaths": ["stderr"],
  74. "initialFields": {"foo": "bar"},
  75. "encoderConfig": {
  76. "messageKey": "message",
  77. "levelKey": "level",
  78. "levelEncoder": "lowercase"
  79. }
  80. }`)
  81. var cfg zap.Config
  82. if err := json.Unmarshal(rawJSON, &cfg); err != nil {
  83. panic(err)
  84. }
  85. logger, err := cfg.Build()
  86. if err != nil {
  87. panic(err)
  88. }
  89. defer logger.Sync()
  90. logger.Info("logger construction succeeded")
  91. // Output:
  92. // {"level":"info","message":"logger construction succeeded","foo":"bar"}
  93. }
  94. func Example_advancedConfiguration() {
  95. // The bundled Config struct only supports the most common configuration
  96. // options. More complex needs, like splitting logs between multiple files
  97. // or writing to non-file outputs, require use of the zapcore package.
  98. //
  99. // In this example, imagine we're both sending our logs to Kafka and writing
  100. // them to the console. We'd like to encode the console output and the Kafka
  101. // topics differently, and we'd also like special treatment for
  102. // high-priority logs.
  103. // First, define our level-handling logic.
  104. highPriority := zap.LevelEnablerFunc(func(lvl zapcore.Level) bool {
  105. return lvl >= zapcore.ErrorLevel
  106. })
  107. lowPriority := zap.LevelEnablerFunc(func(lvl zapcore.Level) bool {
  108. return lvl < zapcore.ErrorLevel
  109. })
  110. // Assume that we have clients for two Kafka topics. The clients implement
  111. // zapcore.WriteSyncer and are safe for concurrent use. (If they only
  112. // implement io.Writer, we can use zapcore.AddSync to add a no-op Sync
  113. // method. If they're not safe for concurrent use, we can add a protecting
  114. // mutex with zapcore.Lock.)
  115. topicDebugging := zapcore.AddSync(ioutil.Discard)
  116. topicErrors := zapcore.AddSync(ioutil.Discard)
  117. // High-priority output should also go to standard error, and low-priority
  118. // output should also go to standard out.
  119. consoleDebugging := zapcore.Lock(os.Stdout)
  120. consoleErrors := zapcore.Lock(os.Stderr)
  121. // Optimize the Kafka output for machine consumption and the console output
  122. // for human operators.
  123. kafkaEncoder := zapcore.NewJSONEncoder(zap.NewProductionEncoderConfig())
  124. consoleEncoder := zapcore.NewConsoleEncoder(zap.NewDevelopmentEncoderConfig())
  125. // Join the outputs, encoders, and level-handling functions into
  126. // zapcore.Cores, then tee the four cores together.
  127. core := zapcore.NewTee(
  128. zapcore.NewCore(kafkaEncoder, topicErrors, highPriority),
  129. zapcore.NewCore(consoleEncoder, consoleErrors, highPriority),
  130. zapcore.NewCore(kafkaEncoder, topicDebugging, lowPriority),
  131. zapcore.NewCore(consoleEncoder, consoleDebugging, lowPriority),
  132. )
  133. // From a zapcore.Core, it's easy to construct a Logger.
  134. logger := zap.New(core)
  135. defer logger.Sync()
  136. logger.Info("constructed a logger")
  137. }
  138. func ExampleNamespace() {
  139. logger := zap.NewExample()
  140. defer logger.Sync()
  141. logger.With(
  142. zap.Namespace("metrics"),
  143. zap.Int("counter", 1),
  144. ).Info("tracked some metrics")
  145. // Output:
  146. // {"level":"info","msg":"tracked some metrics","metrics":{"counter":1}}
  147. }
  148. func ExampleNewStdLog() {
  149. logger := zap.NewExample()
  150. defer logger.Sync()
  151. std := zap.NewStdLog(logger)
  152. std.Print("standard logger wrapper")
  153. // Output:
  154. // {"level":"info","msg":"standard logger wrapper"}
  155. }
  156. func ExampleRedirectStdLog() {
  157. logger := zap.NewExample()
  158. defer logger.Sync()
  159. undo := zap.RedirectStdLog(logger)
  160. defer undo()
  161. log.Print("redirected standard library")
  162. // Output:
  163. // {"level":"info","msg":"redirected standard library"}
  164. }
  165. func ExampleReplaceGlobals() {
  166. logger := zap.NewExample()
  167. defer logger.Sync()
  168. undo := zap.ReplaceGlobals(logger)
  169. defer undo()
  170. zap.L().Info("replaced zap's global loggers")
  171. // Output:
  172. // {"level":"info","msg":"replaced zap's global loggers"}
  173. }
  174. func ExampleAtomicLevel() {
  175. atom := zap.NewAtomicLevel()
  176. // To keep the example deterministic, disable timestamps in the output.
  177. encoderCfg := zap.NewProductionEncoderConfig()
  178. encoderCfg.TimeKey = ""
  179. logger := zap.New(zapcore.NewCore(
  180. zapcore.NewJSONEncoder(encoderCfg),
  181. zapcore.Lock(os.Stdout),
  182. atom,
  183. ))
  184. defer logger.Sync()
  185. logger.Info("info logging enabled")
  186. atom.SetLevel(zap.ErrorLevel)
  187. logger.Info("info logging disabled")
  188. // Output:
  189. // {"level":"info","msg":"info logging enabled"}
  190. }
  191. func ExampleAtomicLevel_config() {
  192. // The zap.Config struct includes an AtomicLevel. To use it, keep a
  193. // reference to the Config.
  194. rawJSON := []byte(`{
  195. "level": "info",
  196. "outputPaths": ["stdout"],
  197. "errorOutputPaths": ["stderr"],
  198. "encoding": "json",
  199. "encoderConfig": {
  200. "messageKey": "message",
  201. "levelKey": "level",
  202. "levelEncoder": "lowercase"
  203. }
  204. }`)
  205. var cfg zap.Config
  206. if err := json.Unmarshal(rawJSON, &cfg); err != nil {
  207. panic(err)
  208. }
  209. logger, err := cfg.Build()
  210. if err != nil {
  211. panic(err)
  212. }
  213. defer logger.Sync()
  214. logger.Info("info logging enabled")
  215. cfg.Level.SetLevel(zap.ErrorLevel)
  216. logger.Info("info logging disabled")
  217. // Output:
  218. // {"level":"info","message":"info logging enabled"}
  219. }
  220. func ExampleLogger_Check() {
  221. logger := zap.NewExample()
  222. defer logger.Sync()
  223. if ce := logger.Check(zap.DebugLevel, "debugging"); ce != nil {
  224. // If debug-level log output isn't enabled or if zap's sampling would have
  225. // dropped this log entry, we don't allocate the slice that holds these
  226. // fields.
  227. ce.Write(
  228. zap.String("foo", "bar"),
  229. zap.String("baz", "quux"),
  230. )
  231. }
  232. // Output:
  233. // {"level":"debug","msg":"debugging","foo":"bar","baz":"quux"}
  234. }
  235. func ExampleLogger_Named() {
  236. logger := zap.NewExample()
  237. defer logger.Sync()
  238. // By default, Loggers are unnamed.
  239. logger.Info("no name")
  240. // The first call to Named sets the Logger name.
  241. main := logger.Named("main")
  242. main.Info("main logger")
  243. // Additional calls to Named create a period-separated path.
  244. main.Named("subpackage").Info("sub-logger")
  245. // Output:
  246. // {"level":"info","msg":"no name"}
  247. // {"level":"info","logger":"main","msg":"main logger"}
  248. // {"level":"info","logger":"main.subpackage","msg":"sub-logger"}
  249. }
  250. func ExampleWrapCore_replace() {
  251. // Replacing a Logger's core can alter fundamental behaviors.
  252. // For example, it can convert a Logger to a no-op.
  253. nop := zap.WrapCore(func(zapcore.Core) zapcore.Core {
  254. return zapcore.NewNopCore()
  255. })
  256. logger := zap.NewExample()
  257. defer logger.Sync()
  258. logger.Info("working")
  259. logger.WithOptions(nop).Info("no-op")
  260. logger.Info("original logger still works")
  261. // Output:
  262. // {"level":"info","msg":"working"}
  263. // {"level":"info","msg":"original logger still works"}
  264. }
  265. func ExampleWrapCore_wrap() {
  266. // Wrapping a Logger's core can extend its functionality. As a trivial
  267. // example, it can double-write all logs.
  268. doubled := zap.WrapCore(func(c zapcore.Core) zapcore.Core {
  269. return zapcore.NewTee(c, c)
  270. })
  271. logger := zap.NewExample()
  272. defer logger.Sync()
  273. logger.Info("single")
  274. logger.WithOptions(doubled).Info("doubled")
  275. // Output:
  276. // {"level":"info","msg":"single"}
  277. // {"level":"info","msg":"doubled"}
  278. // {"level":"info","msg":"doubled"}
  279. }