[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"project-4973":3},{"id":4,"name":5,"fullName":6,"owner":7,"repo":5,"description":8,"homepage":9,"htmlUrl":10,"language":11,"languages":10,"totalLinesOfCode":10,"stars":12,"forks":13,"watchers":14,"openIssues":15,"contributorsCount":16,"subscribersCount":16,"size":16,"stars1d":16,"stars7d":17,"stars30d":18,"stars90d":16,"forks30d":16,"starsTrendScore":19,"compositeScore":20,"rankGlobal":10,"rankLanguage":10,"license":21,"archived":22,"fork":22,"defaultBranch":23,"hasWiki":24,"hasPages":24,"topics":25,"createdAt":10,"pushedAt":10,"updatedAt":30,"readmeContent":31,"aiSummary":32,"trendingCount":16,"starSnapshotCount":16,"syncStatus":19,"lastSyncTime":33,"discoverSource":34},4973,"zerolog","rs\u002Fzerolog","rs","Zero Allocation JSON Logger","",null,"Go",12415,622,70,118,0,4,44,2,74.78,"MIT License",false,"master",true,[26,27,28,29,5],"golang","json","logging","structured-logging","2026-06-12 04:00:24","# Zero Allocation JSON Logger\n\n[![godoc](http:\u002F\u002Fimg.shields.io\u002Fbadge\u002Fgodoc-reference-blue.svg?style=flat)](https:\u002F\u002Fgodoc.org\u002Fgithub.com\u002Frs\u002Fzerolog) [![license](http:\u002F\u002Fimg.shields.io\u002Fbadge\u002Flicense-MIT-red.svg?style=flat)](https:\u002F\u002Fraw.githubusercontent.com\u002Frs\u002Fzerolog\u002Fmaster\u002FLICENSE) [![Build Status](https:\u002F\u002Fgithub.com\u002Frs\u002Fzerolog\u002Factions\u002Fworkflows\u002Ftest.yml\u002Fbadge.svg)](https:\u002F\u002Fgithub.com\u002Frs\u002Fzerolog\u002Factions\u002Fworkflows\u002Ftest.yml) [![Go Coverage](https:\u002F\u002Fgithub.com\u002Frs\u002Fzerolog\u002Fwiki\u002Fcoverage.svg)](https:\u002F\u002Fraw.githack.com\u002Fwiki\u002Frs\u002Fzerolog\u002Fcoverage.html)\n\nThe zerolog package provides a fast and simple logger dedicated to JSON output.\n\nZerolog's API is designed to provide both a great developer experience and stunning [performance](#benchmarks). Its unique chaining API allows zerolog to write JSON (or CBOR) log events by avoiding allocations and reflection.\n\nUber's [zap](https:\u002F\u002Fgodoc.org\u002Fgo.uber.org\u002Fzap) library pioneered this approach. Zerolog is taking this concept to the next level with a simpler to use API and even better performance.\n\nTo keep the code base and the API simple, zerolog focuses on efficient structured logging only. Pretty logging on the console is made possible using the provided (but inefficient) [`zerolog.ConsoleWriter`](#pretty-logging).\n\n![Pretty Logging Image](pretty.png)\n\n## Who uses zerolog\n\nFind out [who uses zerolog](https:\u002F\u002Fgithub.com\u002Frs\u002Fzerolog\u002Fwiki\u002FWho-uses-zerolog) and add your company \u002F project to the list.\n\n## Features\n\n- [Blazing fast](#benchmarks)\n- [Low to zero allocation](#benchmarks)\n- [Leveled logging](#leveled-logging)\n- [Sampling](#log-sampling)\n- [Hooks](#hooks)\n- [Contextual fields](#contextual-logging)\n- [`context.Context` integration](#contextcontext-integration)\n- [Integration with `net\u002Fhttp`](#integration-with-nethttp)\n- [JSON and CBOR encoding formats](#binary-encoding)\n- [Pretty logging for development](#pretty-logging)\n- [Error Logging (with optional Stacktrace)](#error-logging)\n- [`log\u002Fslog` integration](#integration-with-logslog)\n\n## Installation\n\n```bash\ngo get -u github.com\u002Frs\u002Fzerolog\u002Flog\n```\n\n## Getting Started\n\n### Simple Logging Example\n\nFor simple logging, import the global logger package **github.com\u002Frs\u002Fzerolog\u002Flog**\n\n```go\npackage main\n\nimport (\n    \"github.com\u002Frs\u002Fzerolog\"\n    \"github.com\u002Frs\u002Fzerolog\u002Flog\"\n)\n\nfunc main() {\n    \u002F\u002F UNIX Time is faster and smaller than most timestamps\n    zerolog.TimeFieldFormat = zerolog.TimeFormatUnix\n\n    log.Print(\"hello world\")\n}\n\n\u002F\u002F Output: {\"time\":1516134303,\"level\":\"debug\",\"message\":\"hello world\"}\n```\n\n> Note: By default log writes to `os.Stderr`\n> Note: The default log level for `log.Print` is _trace_\n\n### Contextual Logging\n\n**zerolog** allows data to be added to log messages in the form of key:value pairs. The data added to the message adds \"context\" about the log event that can be critical for debugging as well as myriad other purposes. An example of this is below:\n\n```go\npackage main\n\nimport (\n    \"github.com\u002Frs\u002Fzerolog\"\n    \"github.com\u002Frs\u002Fzerolog\u002Flog\"\n)\n\nfunc main() {\n    zerolog.TimeFieldFormat = zerolog.TimeFormatUnix\n\n    log.Debug().\n        Str(\"Scale\", \"833 cents\").\n        Float64(\"Interval\", 833.09).\n        Msg(\"Fibonacci is everywhere\")\n\n    log.Debug().\n        Str(\"Name\", \"Tom\").\n        Send()\n}\n\n\u002F\u002F Output: {\"level\":\"debug\",\"Scale\":\"833 cents\",\"Interval\":833.09,\"time\":1562212768,\"message\":\"Fibonacci is everywhere\"}\n\u002F\u002F Output: {\"level\":\"debug\",\"Name\":\"Tom\",\"time\":1562212768}\n```\n\n> You'll note in the above example that when adding contextual fields, the fields are strongly typed. You can find the full list of supported fields [here](#standard-types)\n\n### Leveled Logging\n\n#### Simple Leveled Logging Example\n\n```go\npackage main\n\nimport (\n    \"github.com\u002Frs\u002Fzerolog\"\n    \"github.com\u002Frs\u002Fzerolog\u002Flog\"\n)\n\nfunc main() {\n    zerolog.TimeFieldFormat = zerolog.TimeFormatUnix\n\n    log.Info().Msg(\"hello world\")\n}\n\n\u002F\u002F Output: {\"time\":1516134303,\"level\":\"info\",\"message\":\"hello world\"}\n```\n\n> It is very important to note that when using the **zerolog** chaining API, as shown above (`log.Info().Msg(\"hello world\"`), the chain must have either the `Msg` or `Msgf` method call. If you forget to add either of these, the log will not occur and there is no compile time error to alert you of this.\n\n**zerolog** allows for logging at the following levels (from highest to lowest):\n\n- panic (`zerolog.PanicLevel`, 5)\n- fatal (`zerolog.FatalLevel`, 4)\n- error (`zerolog.ErrorLevel`, 3)\n- warn (`zerolog.WarnLevel`, 2)\n- info (`zerolog.InfoLevel`, 1)\n- debug (`zerolog.DebugLevel`, 0)\n- trace (`zerolog.TraceLevel`, -1)\n\nYou can set the Global logging level to any of these options using the `SetGlobalLevel` function in the zerolog package, passing in one of the given constants above, e.g. `zerolog.InfoLevel` would be the \"info\" level. Whichever level is chosen, all logs with a level greater than or equal to that level will be written. To turn off logging entirely, pass the `zerolog.Disabled` constant.\n\n#### Setting Global Log Level\n\nThis example uses command-line flags to demonstrate various outputs depending on the chosen log level.\n\n```go\npackage main\n\nimport (\n    \"flag\"\n\n    \"github.com\u002Frs\u002Fzerolog\"\n    \"github.com\u002Frs\u002Fzerolog\u002Flog\"\n)\n\nfunc main() {\n    zerolog.TimeFieldFormat = zerolog.TimeFormatUnix\n    debug := flag.Bool(\"debug\", false, \"sets log level to debug\")\n\n    flag.Parse()\n\n    \u002F\u002F Default level for this example is info, unless debug flag is present\n    zerolog.SetGlobalLevel(zerolog.InfoLevel)\n    if *debug {\n        zerolog.SetGlobalLevel(zerolog.DebugLevel)\n    }\n\n    log.Debug().Msg(\"This message appears only when log level set to Debug\")\n    log.Info().Msg(\"This message appears when log level set to Debug or Info\")\n\n    if e := log.Debug(); e.Enabled() {\n        \u002F\u002F Compute log output only if enabled.\n        value := \"bar\"\n        e.Str(\"foo\", value).Msg(\"some debug message\")\n    }\n}\n```\n\nInfo Output (no flag)\n\n```bash\n$ .\u002FlogLevelExample\n{\"time\":1516387492,\"level\":\"info\",\"message\":\"This message appears when log level set to Debug or Info\"}\n```\n\nDebug Output (debug flag set)\n\n```bash\n$ .\u002FlogLevelExample -debug\n{\"time\":1516387573,\"level\":\"debug\",\"message\":\"This message appears only when log level set to Debug\"}\n{\"time\":1516387573,\"level\":\"info\",\"message\":\"This message appears when log level set to Debug or Info\"}\n{\"time\":1516387573,\"level\":\"debug\",\"foo\":\"bar\",\"message\":\"some debug message\"}\n```\n\n#### Logging without Level or Message\n\nYou may choose to log without a specific level by using the `Log` method. You may also write without a message by setting an empty string in the `msg string` parameter of the `Msg` method. Both are demonstrated in the example below.\n\n```go\npackage main\n\nimport (\n    \"github.com\u002Frs\u002Fzerolog\"\n    \"github.com\u002Frs\u002Fzerolog\u002Flog\"\n)\n\nfunc main() {\n    zerolog.TimeFieldFormat = zerolog.TimeFormatUnix\n\n    log.Log().\n        Str(\"foo\", \"bar\").\n        Msg(\"\")\n}\n\n\u002F\u002F Output: {\"time\":1494567715,\"foo\":\"bar\"}\n```\n\n### Error Logging\n\nYou can log errors using the `Err` method\n\n```go\npackage main\n\nimport (\n    \"errors\"\n\n    \"github.com\u002Frs\u002Fzerolog\"\n    \"github.com\u002Frs\u002Fzerolog\u002Flog\"\n)\n\nfunc main() {\n    zerolog.TimeFieldFormat = zerolog.TimeFormatUnix\n\n    err := errors.New(\"seems we have an error here\")\n    log.Error().Err(err).Msg(\"\")\n}\n\n\u002F\u002F Output: {\"level\":\"error\",\"error\":\"seems we have an error here\",\"time\":1609085256}\n```\n\n> The default field name for errors is `error`, you can change this by setting `zerolog.ErrorFieldName` to meet your needs.\n\n#### Error Logging with Stacktrace\n\nUsing `github.com\u002Fpkg\u002Ferrors`, you can add a formatted stacktrace to your errors.\n\n```go\npackage main\n\nimport (\n    \"github.com\u002Fpkg\u002Ferrors\"\n    \"github.com\u002Frs\u002Fzerolog\u002Fpkgerrors\"\n\n    \"github.com\u002Frs\u002Fzerolog\"\n    \"github.com\u002Frs\u002Fzerolog\u002Flog\"\n)\n\nfunc main() {\n    zerolog.TimeFieldFormat = zerolog.TimeFormatUnix\n    zerolog.ErrorStackMarshaler = pkgerrors.MarshalStack\n\n    err := outer()\n    log.Error().Stack().Err(err).Msg(\"\")\n}\n\nfunc inner() error {\n    return errors.New(\"seems we have an error here\")\n}\n\nfunc middle() error {\n    err := inner()\n    if err != nil {\n        return err\n    }\n    return nil\n}\n\nfunc outer() error {\n    err := middle()\n    if err != nil {\n        return err\n    }\n    return nil\n}\n\n\u002F\u002F Output: {\"level\":\"error\",\"stack\":[{\"func\":\"inner\",\"line\":\"20\",\"source\":\"errors.go\"},{\"func\":\"middle\",\"line\":\"24\",\"source\":\"errors.go\"},{\"func\":\"outer\",\"line\":\"32\",\"source\":\"errors.go\"},{\"func\":\"main\",\"line\":\"15\",\"source\":\"errors.go\"},{\"func\":\"main\",\"line\":\"204\",\"source\":\"proc.go\"},{\"func\":\"goexit\",\"line\":\"1374\",\"source\":\"asm_amd64.s\"}],\"error\":\"seems we have an error here\",\"time\":1609086683}\n```\n\n> zerolog.ErrorStackMarshaler must be set in order for the stack to output anything.\n\n#### Logging Fatal Messages\n\n```go\npackage main\n\nimport (\n    \"errors\"\n\n    \"github.com\u002Frs\u002Fzerolog\"\n    \"github.com\u002Frs\u002Fzerolog\u002Flog\"\n)\n\nfunc main() {\n    err := errors.New(\"A repo man spends his life getting into tense situations\")\n    service := \"myservice\"\n\n    zerolog.TimeFieldFormat = zerolog.TimeFormatUnix\n\n    log.Fatal().\n        Err(err).\n        Str(\"service\", service).\n        Msgf(\"Cannot start %s\", service)\n}\n\n\u002F\u002F Output: {\"time\":1516133263,\"level\":\"fatal\",\"error\":\"A repo man spends his life getting into tense situations\",\"service\":\"myservice\",\"message\":\"Cannot start myservice\"}\n\u002F\u002F         exit status 1\n```\n\n> NOTE: Using `Msgf` generates one allocation even when the logger is disabled.\n\n### Create logger instance to manage different outputs\n\n```go\nlogger := zerolog.New(os.Stderr).With().Timestamp().Logger()\n\nlogger.Info().Str(\"foo\", \"bar\").Msg(\"hello world\")\n\n\u002F\u002F Output: {\"level\":\"info\",\"time\":1494567715,\"message\":\"hello world\",\"foo\":\"bar\"}\n```\n\n### Sub-loggers let you chain loggers with additional context\n\n```go\nsublogger := log.With().\n                 Str(\"component\", \"foo\").\n                 Logger()\nsublogger.Info().Msg(\"hello world\")\n\n\u002F\u002F Output: {\"level\":\"info\",\"time\":1494567715,\"message\":\"hello world\",\"component\":\"foo\"}\n```\n\n### Pretty logging\n\nTo log a human-friendly, colorized output, use `zerolog.ConsoleWriter`:\n\n```go\nlog.Logger = log.Output(zerolog.ConsoleWriter{Out: os.Stderr})\n\nlog.Info().Str(\"foo\", \"bar\").Msg(\"Hello world\")\n\n\u002F\u002F Output: 3:04PM INF Hello World foo=bar\n```\n\nTo customize the configuration and formatting:\n\n```go\noutput := zerolog.ConsoleWriter{Out: os.Stdout, TimeFormat: time.RFC3339}\noutput.FormatLevel = func(i interface{}) string {\n    return strings.ToUpper(fmt.Sprintf(\"| %-6s|\", i))\n}\noutput.FormatMessage = func(i interface{}) string {\n    return fmt.Sprintf(\"***%s****\", i)\n}\noutput.FormatFieldName = func(i interface{}) string {\n    return fmt.Sprintf(\"%s:\", i)\n}\noutput.FormatFieldValue = func(i interface{}) string {\n    return strings.ToUpper(fmt.Sprintf(\"%s\", i))\n}\n\nlog := zerolog.New(output).With().Timestamp().Logger()\n\nlog.Info().Str(\"foo\", \"bar\").Msg(\"Hello World\")\n\n\u002F\u002F Output: 2006-01-02T15:04:05Z07:00 | INFO  | ***Hello World**** foo:BAR\n```\n\nTo use custom advanced formatting:\n\n```go\noutput := zerolog.ConsoleWriter{Out: os.Stdout, NoColor: true,\n    PartsOrder:    []string{\"level\", \"one\", \"two\", \"three\", \"message\"},\n    FieldsExclude: []string{\"one\", \"two\", \"three\"}}\noutput.FormatLevel = func(i interface{}) string { return strings.ToUpper(fmt.Sprintf(\"%-6s\", i)) }\noutput.FormatFieldName = func(i interface{}) string { return fmt.Sprintf(\"%s:\", i) }\noutput.FormatPartValueByName = func(i interface{}, s string) string {\n    var ret string\n    switch s {\n    case \"one\":\n        ret = strings.ToUpper(fmt.Sprintf(\"%s\", i))\n    case \"two\":\n        ret = strings.ToLower(fmt.Sprintf(\"%s\", i))\n    case \"three\":\n        ret = strings.ToLower(fmt.Sprintf(\"(%s)\", i))\n    }\n    return ret\n}\nlog := zerolog.New(output)\n\nlog.Info().Str(\"foo\", \"bar\").\n    Str(\"two\", \"TEST_TWO\").\n    Str(\"one\", \"test_one\").\n    Str(\"three\", \"test_three\").\n    Msg(\"Hello World\")\n\n\u002F\u002F Output: INFO   TEST_ONE test_two (test_three) Hello World foo:bar\n```\n\n### Sub dictionary\n\n```go\nlog.Info().\n    Str(\"foo\", \"bar\").\n    Dict(\"dict\", zerolog.Dict().\n        Str(\"bar\", \"baz\").\n        Int(\"n\", 1),\n    ).Msg(\"hello world\")\n\n\u002F\u002F Output: {\"level\":\"info\",\"time\":1494567715,\"foo\":\"bar\",\"dict\":{\"bar\":\"baz\",\"n\":1},\"message\":\"hello world\"}\n```\n\n### Customize automatic field names\n\n```go\nzerolog.TimestampFieldName = \"t\"\nzerolog.LevelFieldName = \"l\"\nzerolog.MessageFieldName = \"m\"\n\nlog.Info().Msg(\"hello world\")\n\n\u002F\u002F Output: {\"l\":\"info\",\"t\":1494567715,\"m\":\"hello world\"}\n```\n\n### Add contextual fields to the global logger\n\n```go\nlog.Logger = log.With().Str(\"foo\", \"bar\").Logger()\n```\n\n### Add file and line number to log\n\nEquivalent of `Llongfile`:\n\n```go\nlog.Logger = log.With().Caller().Logger()\nlog.Info().Msg(\"hello world\")\n\n\u002F\u002F Output: {\"level\": \"info\", \"message\": \"hello world\", \"caller\": \"\u002Fgo\u002Fsrc\u002Fyour_project\u002Fsome_file:21\"}\n```\n\nEquivalent of `Lshortfile`:\n\n```go\nzerolog.CallerMarshalFunc = func(pc uintptr, file string, line int) string {\n    return filepath.Base(file) + \":\" + strconv.Itoa(line)\n}\nlog.Logger = log.With().Caller().Logger()\nlog.Info().Msg(\"hello world\")\n\n\u002F\u002F Output: {\"level\": \"info\", \"message\": \"hello world\", \"caller\": \"some_file:21\"}\n```\n\n### Thread-safe, lock-free, non-blocking writer\n\nIf your writer might be slow or not thread-safe and you need your log producers to never get slowed down by a slow writer, you can use a `diode.Writer` as follows:\n\n```go\nwr := diode.NewWriter(os.Stdout, 1000, 10*time.Millisecond, func(missed int) {\n        fmt.Printf(\"Logger Dropped %d messages\", missed)\n    })\nlog := zerolog.New(wr)\nlog.Print(\"test\")\n```\n\nYou will need to install `code.cloudfoundry.org\u002Fgo-diodes` to use this feature.\n\n### Log Sampling\n\n```go\nsampled := log.Sample(&zerolog.BasicSampler{N: 10})\nsampled.Info().Msg(\"will be logged every 10 messages\")\n\n\u002F\u002F Output: {\"time\":1494567715,\"level\":\"info\",\"message\":\"will be logged every 10 messages\"}\n```\n\nMore advanced sampling:\n\n```go\n\u002F\u002F Will let 5 debug messages per period of 1 second.\n\u002F\u002F Over 5 debug message, 1 every 100 debug messages are logged.\n\u002F\u002F Other levels are not sampled.\nsampled := log.Sample(zerolog.LevelSampler{\n    DebugSampler: &zerolog.BurstSampler{\n        Burst: 5,\n        Period: 1*time.Second,\n        NextSampler: &zerolog.BasicSampler{N: 100},\n    },\n})\nsampled.Debug().Msg(\"hello world\")\n\n\u002F\u002F Output: {\"time\":1494567715,\"level\":\"debug\",\"message\":\"hello world\"}\n```\n\n### Hooks\n\n```go\ntype SeverityHook struct{}\n\nfunc (h SeverityHook) Run(e *zerolog.Event, level zerolog.Level, msg string) {\n    if level != zerolog.NoLevel {\n        e.Str(\"severity\", level.String())\n    }\n}\n\nhooked := log.Hook(SeverityHook{})\nhooked.Warn().Msg(\"\")\n\n\u002F\u002F Output: {\"level\":\"warn\",\"severity\":\"warn\"}\n```\n\n### Pass a sub-logger by context\n\n```go\nctx := log.With().Str(\"component\", \"module\").Logger().WithContext(ctx)\n\nlog.Ctx(ctx).Info().Msg(\"hello world\")\n\n\u002F\u002F Output: {\"component\":\"module\",\"level\":\"info\",\"message\":\"hello world\"}\n```\n\n### Set as standard logger output\n\n```go\nlog := zerolog.New(os.Stdout).With().\n    Str(\"foo\", \"bar\").\n    Logger()\n\nstdlog.SetFlags(0)\nstdlog.SetOutput(log)\n\nstdlog.Print(\"hello world\")\n\n\u002F\u002F Output: {\"foo\":\"bar\",\"message\":\"hello world\"}\n```\n\n### context.Context integration\n\nGo contexts are commonly passed throughout Go code, and this can help you pass\nyour Logger into places it might otherwise be hard to inject. The `Logger`\ninstance may be attached to Go context (`context.Context`) using\n`Logger.WithContext(ctx)` and extracted from it using `zerolog.Ctx(ctx)`.\nFor example:\n\n```go\nfunc f() {\n    logger := zerolog.New(os.Stdout)\n    ctx := context.Background()\n\n    \u002F\u002F Attach the Logger to the context.Context\n    ctx = logger.WithContext(ctx)\n    someFunc(ctx)\n}\n\nfunc someFunc(ctx context.Context) {\n    \u002F\u002F Get Logger from the go Context. if it's nil, then\n    \u002F\u002F `zerolog.DefaultContextLogger` is returned, if\n    \u002F\u002F `DefaultContextLogger` is nil, then a disabled logger is returned.\n    logger := zerolog.Ctx(ctx)\n    logger.Info().Msg(\"Hello\")\n}\n```\n\nA second form of `context.Context` integration allows you to pass the current\n`context.Context` into the logged event, and retrieve it from hooks. This can be\nuseful to log trace and span IDs or other information stored in the go context,\nand facilitates the unification of logging and tracing in some systems:\n\n```go\ntype TracingHook struct{}\n\nfunc (h TracingHook) Run(e *zerolog.Event, level zerolog.Level, msg string) {\n    ctx := e.GetCtx()\n    spanId := getSpanIdFromContext(ctx) \u002F\u002F as per your tracing framework\n    e.Str(\"span-id\", spanId)\n}\n\nfunc f() {\n    \u002F\u002F Setup the logger\n    logger := zerolog.New(os.Stdout)\n    logger = logger.Hook(TracingHook{})\n\n    ctx := context.Background()\n    \u002F\u002F Use the Ctx function to make the context available to the hook\n    logger.Info().Ctx(ctx).Msg(\"Hello\")\n}\n```\n\n### Integration with `net\u002Fhttp`\n\nThe `github.com\u002Frs\u002Fzerolog\u002Fhlog` package provides some helpers to integrate zerolog with `http.Handler`.\n\nIn this example we use [alice](https:\u002F\u002Fgithub.com\u002Fjustinas\u002Falice) to install logger for better readability.\n\n```go\nlog := zerolog.New(os.Stdout).With().\n    Timestamp().\n    Str(\"role\", \"my-service\").\n    Str(\"host\", host).\n    Logger()\n\nc := alice.New()\n\n\u002F\u002F Install the logger handler with default output on the console\nc = c.Append(hlog.NewHandler(log))\n\n\u002F\u002F Install some provided extra handler to set some request's context fields.\n\u002F\u002F Thanks to that handler, all our logs will come with some prepopulated fields.\nc = c.Append(hlog.AccessHandler(func(r *http.Request, status, size int, duration time.Duration) {\n    hlog.FromRequest(r).Info().\n        Str(\"method\", r.Method).\n        Stringer(\"url\", r.URL).\n        Int(\"status\", status).\n        Int(\"size\", size).\n        Dur(\"duration\", duration).\n        Msg(\"\")\n}))\nc = c.Append(hlog.RemoteAddrHandler(\"ip\"))\nc = c.Append(hlog.UserAgentHandler(\"user_agent\"))\nc = c.Append(hlog.RefererHandler(\"referer\"))\nc = c.Append(hlog.RequestIDHandler(\"req_id\", \"Request-Id\"))\n\n\u002F\u002F Here is your final handler\nh := c.Then(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {\n    \u002F\u002F Get the logger from the request's context. You can safely assume it\n    \u002F\u002F will be always there: if the handler is removed, hlog.FromRequest\n    \u002F\u002F will return a no-op logger.\n    hlog.FromRequest(r).Info().\n        Str(\"user\", \"current user\").\n        Str(\"status\", \"ok\").\n        Msg(\"Something happened\")\n\n    \u002F\u002F Output: {\"level\":\"info\",\"time\":\"2001-02-03T04:05:06Z\",\"role\":\"my-service\",\"host\":\"local-hostname\",\"req_id\":\"b4g0l5t6tfid6dtrapu0\",\"user\":\"current user\",\"status\":\"ok\",\"message\":\"Something happened\"}\n}))\nhttp.Handle(\"\u002F\", h)\n\nif err := http.ListenAndServe(\":8080\", nil); err != nil {\n    log.Fatal().Err(err).Msg(\"Startup failed\")\n}\n```\n\n## Multiple Log Output\n\n`zerolog.MultiLevelWriter` may be used to send the log message to multiple outputs.\n\nIn this example, we send the log message to both `os.Stdout` and the in-built `ConsoleWriter`.\n\n```go\nfunc main() {\n    consoleWriter := zerolog.ConsoleWriter{Out: os.Stdout}\n    multi := zerolog.MultiLevelWriter(consoleWriter, os.Stdout)\n    logger := zerolog.New(multi).With().Timestamp().Logger()\n    logger.Info().Msg(\"Hello World!\")\n}\n\n\u002F\u002F Output (Line 1: Console; Line 2: Stdout)\n\u002F\u002F 12:36PM INF Hello World!\n\u002F\u002F {\"level\":\"info\",\"time\":\"2019-11-07T12:36:38+03:00\",\"message\":\"Hello World!\"}\n```\n\n## Global Settings\n\nSome settings can be changed and will be applied to all loggers:\n\n- `log.Logger`: You can set this value to customize the global logger (the one used by package level methods).\n- `zerolog.SetGlobalLevel`: Can raise the minimum level of all loggers. Call this with `zerolog.Disabled` to disable logging altogether (quiet mode).\n- `zerolog.DisableSampling`: If argument is `true`, all sampled loggers will stop sampling and issue 100% of their log events.\n- `zerolog.TimestampFieldName`: Can be set to customize `Timestamp` field name.\n- `zerolog.LevelFieldName`: Can be set to customize level field name.\n- `zerolog.MessageFieldName`: Can be set to customize message field name.\n- `zerolog.ErrorFieldName`: Can be set to customize `Err` field name.\n- `zerolog.TimeFieldFormat`: Can be set to customize `Time` field value formatting. If set with `zerolog.TimeFormatUnix`, `zerolog.TimeFormatUnixMs` or `zerolog.TimeFormatUnixMicro`, times are formatted as UNIX timestamp.\n- `zerolog.DurationFieldUnit`: Can be set to customize the unit for time.Duration type fields added by `Dur` (default: `time.Millisecond`).\n- `zerolog.DurationFieldFormat`: Can be set to `DurationFormatFloat`, `DurationFormatInt`, or `DurationFormatString` (default: `DurationFormatFloat`) to append the `Duration` as a `Float64`, `Int64`, or by calling `String()` (respectively).\n- `zerolog.DurationFieldInteger`: If set to `true`, `Dur` fields are formatted as integers instead of floats (default: `false`). Deprecated: Use `zerolog.DurationFieldFormat = DurationFormatInt` instead.\n- `zerolog.ErrorHandler`: Called whenever zerolog fails to write an event on its output. If not set, an error is printed on the stderr. This handler must be thread safe and non-blocking.\n- `zerolog.FloatingPointPrecision`: If set to a value other than -1, controls the number of digits when formatting float numbers in JSON. See [strconv.FormatFloat](https:\u002F\u002Fpkg.go.dev\u002Fstrconv#FormatFloat)\n  for more details.\n\n## Field Types\n\n### Standard Types\n\n- `Str`\n- `Bool`\n- `Int`, `Int8`, `Int16`, `Int32`, `Int64`\n- `Uint`, `Uint8`, `Uint16`, `Uint32`, `Uint64`\n- `Float32`, `Float64`\n\n### Advanced Fields\n\n- `Err`: Takes an `error` and renders it as a string using the `zerolog.ErrorFieldName` field name.\n- `Func`: Run a `func` only if the level is enabled.\n- `Timestamp`: Inserts a timestamp field with `zerolog.TimestampFieldName` field name, formatted using `zerolog.TimeFieldFormat`.\n- `Time`: Adds a field with time formatted with `zerolog.TimeFieldFormat`.\n- `Dur`: Adds a field with `time.Duration`.\n- `Dict`: Adds a sub-key\u002Fvalue as a field of the event.\n- `RawJSON`: Adds a field with an already encoded JSON (`[]byte`)\n- `Hex`: Adds a field with value formatted as a hexadecimal string (`[]byte`)\n- `Interface`: Uses reflection to marshal the type.\n- `IPAddr`: Adds a field with `net.IP`.\n- `IPPrefix`: Adds a field with `net.IPNet`.\n- `MACAddr`: Adds a field with `net.HardwareAddr`\n\nMost fields are also available in the slice format (`Strs` for `[]string`, `Errs` for `[]error` etc.)\n\n## Binary Encoding\n\nIn addition to the default JSON encoding, `zerolog` can produce binary logs using [CBOR](https:\u002F\u002Fcbor.io) encoding. The choice of encoding can be decided at compile time using the build tag `binary_log` as follows:\n\n```bash\ngo build -tags binary_log .\n```\n\nTo decode binary encoded log files you can use any CBOR decoder. One has been tested to work\nwith zerolog library is [CSD](https:\u002F\u002Fgithub.com\u002Ftoravir\u002Fcsd\u002F).\n\n## Integration with `log\u002Fslog`\n\nzerolog provides a `slog.Handler` implementation that routes `log\u002Fslog` records through a zerolog logger. This lets you use the standard library's `slog` API while keeping zerolog's performance and encoding:\n\n```go\npackage main\n\nimport (\n    \"log\u002Fslog\"\n\n    \"github.com\u002Frs\u002Fzerolog\"\n    \"github.com\u002Frs\u002Fzerolog\u002Flog\"\n)\n\nfunc main() {\n    zl := log.Logger\n    handler := zerolog.NewSlogHandler(zl)\n    logger := slog.New(handler)\n\n    logger.Info(\"user logged in\", \"user\", \"alice\", \"role\", \"admin\")\n}\n\n\u002F\u002F Output: {\"level\":\"info\",\"user\":\"alice\",\"role\":\"admin\",\"time\":\"...\",\"message\":\"user logged in\"}\n```\n\nThe handler supports all `slog` features including `WithAttrs`, `WithGroup`, nested groups, and `LogValuer` resolution. slog levels are mapped to zerolog levels (e.g. `slog.LevelDebug` to `zerolog.DebugLevel`).\n\n## Related Projects\n\n- [grpc-zerolog](https:\u002F\u002Fgithub.com\u002FcheapRoc\u002Fgrpc-zerolog): Implementation of `grpclog.LoggerV2` interface using `zerolog`\n- [overlog](https:\u002F\u002Fgithub.com\u002FTrendyol\u002Foverlog): Implementation of `Mapped Diagnostic Context` interface using `zerolog`\n- [zerologr](https:\u002F\u002Fgithub.com\u002Fgo-logr\u002Fzerologr): Implementation of `logr.LogSink` interface using `zerolog`\n- [logze](https:\u002F\u002Fgithub.com\u002Fmaxbolgarin\u002Flogze): Implementation of `log\u002Fslog` interface using `zerolog`\n\n## Benchmarks\n\nSee [logbench](http:\u002F\u002Fbench.zerolog.io\u002F) for more comprehensive and up-to-date benchmarks.\n\nAll operations are allocation free (those numbers _include_ JSON encoding):\n\n```text\nBenchmarkLogEmpty-8        100000000    19.1 ns\u002Fop     0 B\u002Fop       0 allocs\u002Fop\nBenchmarkDisabled-8        500000000    4.07 ns\u002Fop     0 B\u002Fop       0 allocs\u002Fop\nBenchmarkInfo-8            30000000     42.5 ns\u002Fop     0 B\u002Fop       0 allocs\u002Fop\nBenchmarkContextFields-8   30000000     44.9 ns\u002Fop     0 B\u002Fop       0 allocs\u002Fop\nBenchmarkLogFields-8       10000000     184 ns\u002Fop      0 B\u002Fop       0 allocs\u002Fop\n```\n\nThere are a few Go logging benchmarks and comparisons that include zerolog.\n\n- [imkira\u002Fgo-loggers-bench](https:\u002F\u002Fgithub.com\u002Fimkira\u002Fgo-loggers-bench)\n- [uber-common\u002Fzap](https:\u002F\u002Fgithub.com\u002Fuber-go\u002Fzap#performance)\n\nUsing Uber's zap comparison benchmark:\n\nLog a message and 10 fields:\n\n| Library             |    Time     | Bytes Allocated | Objects Allocated |\n| :------------------ | :---------: | :-------------: | :---------------: |\n| zerolog             |  767 ns\u002Fop  |    552 B\u002Fop     |    6 allocs\u002Fop    |\n| :zap: zap           |  848 ns\u002Fop  |    704 B\u002Fop     |    2 allocs\u002Fop    |\n| :zap: zap (sugared) | 1363 ns\u002Fop  |    1610 B\u002Fop    |   20 allocs\u002Fop    |\n| go-kit              | 3614 ns\u002Fop  |    2895 B\u002Fop    |   66 allocs\u002Fop    |\n| lion                | 5392 ns\u002Fop  |    5807 B\u002Fop    |   63 allocs\u002Fop    |\n| logrus              | 5661 ns\u002Fop  |    6092 B\u002Fop    |   78 allocs\u002Fop    |\n| apex\u002Flog            | 15332 ns\u002Fop |    3832 B\u002Fop    |   65 allocs\u002Fop    |\n| log15               | 20657 ns\u002Fop |    5632 B\u002Fop    |   93 allocs\u002Fop    |\n\nLog a message with a logger that already has 10 fields of context:\n\n| Library             |    Time     | Bytes Allocated | Objects Allocated |\n| :------------------ | :---------: | :-------------: | :---------------: |\n| zerolog             |  52 ns\u002Fop   |     0 B\u002Fop      |    0 allocs\u002Fop    |\n| :zap: zap           |  283 ns\u002Fop  |     0 B\u002Fop      |    0 allocs\u002Fop    |\n| :zap: zap (sugared) |  337 ns\u002Fop  |     80 B\u002Fop     |    2 allocs\u002Fop    |\n| lion                | 2702 ns\u002Fop  |    4074 B\u002Fop    |   38 allocs\u002Fop    |\n| go-kit              | 3378 ns\u002Fop  |    3046 B\u002Fop    |   52 allocs\u002Fop    |\n| logrus              | 4309 ns\u002Fop  |    4564 B\u002Fop    |   63 allocs\u002Fop    |\n| apex\u002Flog            | 13456 ns\u002Fop |    2898 B\u002Fop    |   51 allocs\u002Fop    |\n| log15               | 14179 ns\u002Fop |    2642 B\u002Fop    |   44 allocs\u002Fop    |\n\nLog a static string, without any context or `printf`-style templating:\n\n| Library             |    Time    | Bytes Allocated | Objects Allocated |\n| :------------------ | :--------: | :-------------: | :---------------: |\n| zerolog             |  50 ns\u002Fop  |     0 B\u002Fop      |    0 allocs\u002Fop    |\n| :zap: zap           | 236 ns\u002Fop  |     0 B\u002Fop      |    0 allocs\u002Fop    |\n| standard library    | 453 ns\u002Fop  |     80 B\u002Fop     |    2 allocs\u002Fop    |\n| :zap: zap (sugared) | 337 ns\u002Fop  |     80 B\u002Fop     |    2 allocs\u002Fop    |\n| go-kit              | 508 ns\u002Fop  |    656 B\u002Fop     |   13 allocs\u002Fop    |\n| lion                | 771 ns\u002Fop  |    1224 B\u002Fop    |   10 allocs\u002Fop    |\n| logrus              | 1244 ns\u002Fop |    1505 B\u002Fop    |   27 allocs\u002Fop    |\n| apex\u002Flog            | 2751 ns\u002Fop |    584 B\u002Fop     |   11 allocs\u002Fop    |\n| log15               | 5181 ns\u002Fop |    1592 B\u002Fop    |   26 allocs\u002Fop    |\n\n## Caveats\n\n### Field duplication\n\nNote that zerolog does no de-duplication of fields. Using the same key multiple times creates multiple keys in final JSON:\n\n```go\nlogger := zerolog.New(os.Stderr).With().Timestamp().Logger()\nlogger.Info().\n       Timestamp().\n       Msg(\"dup\")\n\u002F\u002F Output: {\"level\":\"info\",\"time\":1494567715,\"time\":1494567715,\"message\":\"dup\"}\n```\n\nIn this case, many consumers will take the last value, but this is not guaranteed; check yours if in doubt.\n\n### Concurrency safety\n\nBe careful when calling `UpdateContext`. It is not concurrency safe. Use the `With()` method to create a child logger:\n\n```go\nfunc handler(w http.ResponseWriter, r *http.Request) {\n    \u002F\u002F Create a child logger for concurrency safety\n    logger := log.Logger.With().Logger()\n\n    \u002F\u002F Add context fields, for example User-Agent from HTTP headers\n    logger.UpdateContext(func(c zerolog.Context) zerolog.Context {\n        ...\n    })\n}\n```\n\nThe `Event` object returned from the `Logger` level-specific message functions (e.g. `Log()`, `Trace()`, `Debug()`, etc.)\nis allocated in `sync.Pool` memory that will be returned to the pool as soon as the `Msg()`, `Msgf()`, `Send()`,\nor `MsgFunc()` writes the message and **must not** be accessed afterwards.\n\n**Do not** hold a reference to the `*Event` while in callback functions or your own code. This is especially important in\n`Hook.Run()` and `HookFunc` functions or `MarshalZerologObject(e *Event)` callback (e.g. `LogObjectMarshaler` implementations).\n\nAny `Array` objects returned from `Context.CreateArray()` or `Event.CreateArray()` are from a `sync.Pool` so **do not** hold\nreferences to them from within any `MarshalZerologArray(a *Array)` callback (e.g. `LogArrayMarshaler` implementations) or your\nown code as they will be cleared and returned to the pool after being buffered by a call to `Context.Array()` or `Event.Array()`.\n\nAny _dictionary_ `Event` returned from `Context.CreateDict()` or `Event.CreateDict()` **must not** be referenced after being\nbuffered by a call to `Array.Dict()`, `Context.Dict()`, or `Event.Dict()` as they will be cleared and returned to the pool.\n","zerolog 是一个专为 JSON 输出设计的高性能日志库，使用 Go 语言编写。它通过独特的链式 API 实现了零分配和无反射的日志记录，从而在保证易用性的同时提供卓越性能。主要功能包括多级日志记录、采样、钩子支持、上下文字段集成以及与 `context.Context` 和 `net\u002Fhttp` 的无缝对接等。此外，zerolog 还支持 JSON 和 CBOR 编码格式，并且提供了开发阶段使用的美化输出选项。适用于需要高效结构化日志记录的各种 Go 应用场景，尤其是对性能有较高要求的服务端应用。","2026-06-11 03:01:51","top_language"]