Showing preview only (628K chars total). Download the full file or copy to clipboard to get everything.
Repository: rs/zerolog
Branch: master
Commit: 2f5b8a91be2c
Files: 97
Total size: 599.0 KB
Directory structure:
gitextract_uhbtc_lf/
├── .github/
│ ├── dependabot.yml
│ └── workflows/
│ └── test.yml
├── .gitignore
├── CONTRIBUTING.md
├── LICENSE
├── README.md
├── array.go
├── array_test.go
├── benchmark_test.go
├── binary_test.go
├── cmd/
│ ├── lint/
│ │ ├── README.md
│ │ ├── go.mod
│ │ ├── go.sum
│ │ └── lint.go
│ └── prettylog/
│ ├── README.md
│ └── prettylog.go
├── console.go
├── console_test.go
├── context.go
├── context_test.go
├── ctx.go
├── ctx_test.go
├── diode/
│ ├── diode.go
│ ├── diode_example_test.go
│ ├── diode_test.go
│ └── internal/
│ └── diodes/
│ ├── README
│ ├── many_to_one.go
│ ├── one_to_one.go
│ ├── poller.go
│ └── waiter.go
├── encoder.go
├── encoder_cbor.go
├── encoder_json.go
├── error_marshal_test.go
├── event.go
├── event_test.go
├── example.jsonl
├── fields.go
├── fixtures_test.go
├── globals.go
├── go.mod
├── go.sum
├── go112.go
├── hlog/
│ ├── hlog.go
│ ├── hlog_example_test.go
│ ├── hlog_test.go
│ └── internal/
│ └── mutil/
│ ├── LICENSE
│ ├── mutil.go
│ └── writer_proxy.go
├── hook.go
├── hook_test.go
├── internal/
│ ├── cbor/
│ │ ├── README.md
│ │ ├── base.go
│ │ ├── base_test.go
│ │ ├── cbor.go
│ │ ├── decode_stream.go
│ │ ├── decoder_test.go
│ │ ├── examples/
│ │ │ ├── genLog.go
│ │ │ └── makefile
│ │ ├── string.go
│ │ ├── string_test.go
│ │ ├── time.go
│ │ ├── time_test.go
│ │ ├── types.go
│ │ ├── types_64_test.go
│ │ └── types_test.go
│ ├── json/
│ │ ├── base.go
│ │ ├── base_test.go
│ │ ├── bytes.go
│ │ ├── bytes_test.go
│ │ ├── float_test.go
│ │ ├── int_test.go
│ │ ├── string.go
│ │ ├── string_test.go
│ │ ├── time.go
│ │ ├── time_test.go
│ │ ├── types.go
│ │ └── types_test.go
│ └── testcases.go
├── journald/
│ ├── journald.go
│ └── journald_test.go
├── log/
│ ├── log.go
│ └── log_example_test.go
├── log.go
├── log_example_test.go
├── log_test.go
├── not_go112.go
├── pkgerrors/
│ ├── stacktrace.go
│ └── stacktrace_test.go
├── sampler.go
├── sampler_test.go
├── slog.go
├── slog_test.go
├── syslog.go
├── syslog_test.go
├── writer.go
└── writer_test.go
================================================
FILE CONTENTS
================================================
================================================
FILE: .github/dependabot.yml
================================================
version: 2
updates:
- package-ecosystem: github-actions
directory: /
schedule:
interval: weekly
- package-ecosystem: gomod
directory: /
schedule:
interval: weekly
================================================
FILE: .github/workflows/test.yml
================================================
on: [push, pull_request]
name: Test
jobs:
test:
strategy:
matrix:
go-version: [1.21.x, 1.24.x]
os: [ubuntu-latest, macos-latest]
runs-on: ${{ matrix.os }}
steps:
- name: Install Go
uses: actions/setup-go@v5
with:
go-version: ${{ matrix.go-version }}
- name: Checkout code
uses: actions/checkout@v6
- uses: actions/cache@v4
with:
path: ~/go/pkg/mod
key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }}
restore-keys: |
${{ runner.os }}-go-
- name: Test
run: go test -race -bench . -benchmem ./...
- name: Test CBOR
run: go test -tags binary_log ./...
coverage:
runs-on: ubuntu-latest
steps:
- name: Update coverage report
uses: ncruces/go-coverage-report@main
with:
report: 'true'
chart: 'true'
amend: 'true'
continue-on-error: true
================================================
FILE: .gitignore
================================================
# Compiled Object files, Static and Dynamic libs (Shared Objects)
*.o
*.a
*.so
# Folders
_obj
_test
tmp
# Architecture specific extensions/prefixes
*.[568vq]
[568vq].out
*.cgo1.go
*.cgo2.c
_cgo_defun.c
_cgo_gotypes.go
_cgo_export.*
_testmain.go
*.exe
*.test
*.prof
coverage.out
================================================
FILE: CONTRIBUTING.md
================================================
# Contributing to Zerolog
Thank you for your interest in contributing to **Zerolog**!
Zerolog is a **feature-complete**, high-performance logging library designed to be **lean** and **non-bloated**. The focus of ongoing development is on **bug fixes**, **performance improvements**, and **modernization efforts** (such as keeping up with Go best practices and compatibility with newer Go versions).
## What We're Looking For
We welcome contributions in the following areas:
- **Bug Fixes**: If you find an issue or unexpected behavior, please open an issue and/or submit a fix.
- **Performance Optimizations**: Improvements that reduce memory usage, allocation count, or CPU cycles without introducing complexity are appreciated.
- **Modernization**: Compatibility updates for newer Go versions or idiomatic improvements that do not increase library size or complexity.
- **Documentation Enhancements**: Corrections, clarifications, and improvements to documentation or code comments.
## What We're *Not* Looking For
Zerolog is intended to remain **minimalistic and efficient**. Therefore, we are **not accepting**:
- New features that add optional behaviors or extend API surface area.
- Built-in support for frameworks or external systems (e.g., bindings, integrations).
- General-purpose abstractions or configuration helpers.
If you're unsure whether a change aligns with the project's philosophy, feel free to open an issue for discussion before submitting a PR.
## Contributing Guidelines
1. **Fork the repository**
2. **Create a branch** for your fix or improvement
3. **Write tests** to cover your changes
4. Ensure `go test ./...` passes
5. Run `go fmt` and `go vet` to ensure code consistency
6. **Submit a pull request** with a clear explanation of the motivation and impact
## Code Style
- Keep the code simple, efficient, and idiomatic.
- Avoid introducing new dependencies.
- Preserve backwards compatibility unless explicitly discussed.
---
We appreciate your effort in helping us keep Zerolog fast, minimal, and reliable!
================================================
FILE: LICENSE
================================================
MIT License
Copyright (c) 2017 Olivier Poitrey
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
================================================
FILE: README.md
================================================
# Zero Allocation JSON Logger
[](https://godoc.org/github.com/rs/zerolog) [](https://raw.githubusercontent.com/rs/zerolog/master/LICENSE) [](https://github.com/rs/zerolog/actions/workflows/test.yml) [](https://raw.githack.com/wiki/rs/zerolog/coverage.html)
The zerolog package provides a fast and simple logger dedicated to JSON output.
Zerolog'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.
Uber's [zap](https://godoc.org/go.uber.org/zap) library pioneered this approach. Zerolog is taking this concept to the next level with a simpler to use API and even better performance.
To 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).

## Who uses zerolog
Find out [who uses zerolog](https://github.com/rs/zerolog/wiki/Who-uses-zerolog) and add your company / project to the list.
## Features
- [Blazing fast](#benchmarks)
- [Low to zero allocation](#benchmarks)
- [Leveled logging](#leveled-logging)
- [Sampling](#log-sampling)
- [Hooks](#hooks)
- [Contextual fields](#contextual-logging)
- [`context.Context` integration](#contextcontext-integration)
- [Integration with `net/http`](#integration-with-nethttp)
- [JSON and CBOR encoding formats](#binary-encoding)
- [Pretty logging for development](#pretty-logging)
- [Error Logging (with optional Stacktrace)](#error-logging)
- [`log/slog` integration](#integration-with-logslog)
## Installation
```bash
go get -u github.com/rs/zerolog/log
```
## Getting Started
### Simple Logging Example
For simple logging, import the global logger package **github.com/rs/zerolog/log**
```go
package main
import (
"github.com/rs/zerolog"
"github.com/rs/zerolog/log"
)
func main() {
// UNIX Time is faster and smaller than most timestamps
zerolog.TimeFieldFormat = zerolog.TimeFormatUnix
log.Print("hello world")
}
// Output: {"time":1516134303,"level":"debug","message":"hello world"}
```
> Note: By default log writes to `os.Stderr`
> Note: The default log level for `log.Print` is _trace_
### Contextual Logging
**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:
```go
package main
import (
"github.com/rs/zerolog"
"github.com/rs/zerolog/log"
)
func main() {
zerolog.TimeFieldFormat = zerolog.TimeFormatUnix
log.Debug().
Str("Scale", "833 cents").
Float64("Interval", 833.09).
Msg("Fibonacci is everywhere")
log.Debug().
Str("Name", "Tom").
Send()
}
// Output: {"level":"debug","Scale":"833 cents","Interval":833.09,"time":1562212768,"message":"Fibonacci is everywhere"}
// Output: {"level":"debug","Name":"Tom","time":1562212768}
```
> 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)
### Leveled Logging
#### Simple Leveled Logging Example
```go
package main
import (
"github.com/rs/zerolog"
"github.com/rs/zerolog/log"
)
func main() {
zerolog.TimeFieldFormat = zerolog.TimeFormatUnix
log.Info().Msg("hello world")
}
// Output: {"time":1516134303,"level":"info","message":"hello world"}
```
> 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.
**zerolog** allows for logging at the following levels (from highest to lowest):
- panic (`zerolog.PanicLevel`, 5)
- fatal (`zerolog.FatalLevel`, 4)
- error (`zerolog.ErrorLevel`, 3)
- warn (`zerolog.WarnLevel`, 2)
- info (`zerolog.InfoLevel`, 1)
- debug (`zerolog.DebugLevel`, 0)
- trace (`zerolog.TraceLevel`, -1)
You 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.
#### Setting Global Log Level
This example uses command-line flags to demonstrate various outputs depending on the chosen log level.
```go
package main
import (
"flag"
"github.com/rs/zerolog"
"github.com/rs/zerolog/log"
)
func main() {
zerolog.TimeFieldFormat = zerolog.TimeFormatUnix
debug := flag.Bool("debug", false, "sets log level to debug")
flag.Parse()
// Default level for this example is info, unless debug flag is present
zerolog.SetGlobalLevel(zerolog.InfoLevel)
if *debug {
zerolog.SetGlobalLevel(zerolog.DebugLevel)
}
log.Debug().Msg("This message appears only when log level set to Debug")
log.Info().Msg("This message appears when log level set to Debug or Info")
if e := log.Debug(); e.Enabled() {
// Compute log output only if enabled.
value := "bar"
e.Str("foo", value).Msg("some debug message")
}
}
```
Info Output (no flag)
```bash
$ ./logLevelExample
{"time":1516387492,"level":"info","message":"This message appears when log level set to Debug or Info"}
```
Debug Output (debug flag set)
```bash
$ ./logLevelExample -debug
{"time":1516387573,"level":"debug","message":"This message appears only when log level set to Debug"}
{"time":1516387573,"level":"info","message":"This message appears when log level set to Debug or Info"}
{"time":1516387573,"level":"debug","foo":"bar","message":"some debug message"}
```
#### Logging without Level or Message
You 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.
```go
package main
import (
"github.com/rs/zerolog"
"github.com/rs/zerolog/log"
)
func main() {
zerolog.TimeFieldFormat = zerolog.TimeFormatUnix
log.Log().
Str("foo", "bar").
Msg("")
}
// Output: {"time":1494567715,"foo":"bar"}
```
### Error Logging
You can log errors using the `Err` method
```go
package main
import (
"errors"
"github.com/rs/zerolog"
"github.com/rs/zerolog/log"
)
func main() {
zerolog.TimeFieldFormat = zerolog.TimeFormatUnix
err := errors.New("seems we have an error here")
log.Error().Err(err).Msg("")
}
// Output: {"level":"error","error":"seems we have an error here","time":1609085256}
```
> The default field name for errors is `error`, you can change this by setting `zerolog.ErrorFieldName` to meet your needs.
#### Error Logging with Stacktrace
Using `github.com/pkg/errors`, you can add a formatted stacktrace to your errors.
```go
package main
import (
"github.com/pkg/errors"
"github.com/rs/zerolog/pkgerrors"
"github.com/rs/zerolog"
"github.com/rs/zerolog/log"
)
func main() {
zerolog.TimeFieldFormat = zerolog.TimeFormatUnix
zerolog.ErrorStackMarshaler = pkgerrors.MarshalStack
err := outer()
log.Error().Stack().Err(err).Msg("")
}
func inner() error {
return errors.New("seems we have an error here")
}
func middle() error {
err := inner()
if err != nil {
return err
}
return nil
}
func outer() error {
err := middle()
if err != nil {
return err
}
return nil
}
// 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}
```
> zerolog.ErrorStackMarshaler must be set in order for the stack to output anything.
#### Logging Fatal Messages
```go
package main
import (
"errors"
"github.com/rs/zerolog"
"github.com/rs/zerolog/log"
)
func main() {
err := errors.New("A repo man spends his life getting into tense situations")
service := "myservice"
zerolog.TimeFieldFormat = zerolog.TimeFormatUnix
log.Fatal().
Err(err).
Str("service", service).
Msgf("Cannot start %s", service)
}
// Output: {"time":1516133263,"level":"fatal","error":"A repo man spends his life getting into tense situations","service":"myservice","message":"Cannot start myservice"}
// exit status 1
```
> NOTE: Using `Msgf` generates one allocation even when the logger is disabled.
### Create logger instance to manage different outputs
```go
logger := zerolog.New(os.Stderr).With().Timestamp().Logger()
logger.Info().Str("foo", "bar").Msg("hello world")
// Output: {"level":"info","time":1494567715,"message":"hello world","foo":"bar"}
```
### Sub-loggers let you chain loggers with additional context
```go
sublogger := log.With().
Str("component", "foo").
Logger()
sublogger.Info().Msg("hello world")
// Output: {"level":"info","time":1494567715,"message":"hello world","component":"foo"}
```
### Pretty logging
To log a human-friendly, colorized output, use `zerolog.ConsoleWriter`:
```go
log.Logger = log.Output(zerolog.ConsoleWriter{Out: os.Stderr})
log.Info().Str("foo", "bar").Msg("Hello world")
// Output: 3:04PM INF Hello World foo=bar
```
To customize the configuration and formatting:
```go
output := zerolog.ConsoleWriter{Out: os.Stdout, TimeFormat: time.RFC3339}
output.FormatLevel = func(i interface{}) string {
return strings.ToUpper(fmt.Sprintf("| %-6s|", i))
}
output.FormatMessage = func(i interface{}) string {
return fmt.Sprintf("***%s****", i)
}
output.FormatFieldName = func(i interface{}) string {
return fmt.Sprintf("%s:", i)
}
output.FormatFieldValue = func(i interface{}) string {
return strings.ToUpper(fmt.Sprintf("%s", i))
}
log := zerolog.New(output).With().Timestamp().Logger()
log.Info().Str("foo", "bar").Msg("Hello World")
// Output: 2006-01-02T15:04:05Z07:00 | INFO | ***Hello World**** foo:BAR
```
To use custom advanced formatting:
```go
output := zerolog.ConsoleWriter{Out: os.Stdout, NoColor: true,
PartsOrder: []string{"level", "one", "two", "three", "message"},
FieldsExclude: []string{"one", "two", "three"}}
output.FormatLevel = func(i interface{}) string { return strings.ToUpper(fmt.Sprintf("%-6s", i)) }
output.FormatFieldName = func(i interface{}) string { return fmt.Sprintf("%s:", i) }
output.FormatPartValueByName = func(i interface{}, s string) string {
var ret string
switch s {
case "one":
ret = strings.ToUpper(fmt.Sprintf("%s", i))
case "two":
ret = strings.ToLower(fmt.Sprintf("%s", i))
case "three":
ret = strings.ToLower(fmt.Sprintf("(%s)", i))
}
return ret
}
log := zerolog.New(output)
log.Info().Str("foo", "bar").
Str("two", "TEST_TWO").
Str("one", "test_one").
Str("three", "test_three").
Msg("Hello World")
// Output: INFO TEST_ONE test_two (test_three) Hello World foo:bar
```
### Sub dictionary
```go
log.Info().
Str("foo", "bar").
Dict("dict", zerolog.Dict().
Str("bar", "baz").
Int("n", 1),
).Msg("hello world")
// Output: {"level":"info","time":1494567715,"foo":"bar","dict":{"bar":"baz","n":1},"message":"hello world"}
```
### Customize automatic field names
```go
zerolog.TimestampFieldName = "t"
zerolog.LevelFieldName = "l"
zerolog.MessageFieldName = "m"
log.Info().Msg("hello world")
// Output: {"l":"info","t":1494567715,"m":"hello world"}
```
### Add contextual fields to the global logger
```go
log.Logger = log.With().Str("foo", "bar").Logger()
```
### Add file and line number to log
Equivalent of `Llongfile`:
```go
log.Logger = log.With().Caller().Logger()
log.Info().Msg("hello world")
// Output: {"level": "info", "message": "hello world", "caller": "/go/src/your_project/some_file:21"}
```
Equivalent of `Lshortfile`:
```go
zerolog.CallerMarshalFunc = func(pc uintptr, file string, line int) string {
return filepath.Base(file) + ":" + strconv.Itoa(line)
}
log.Logger = log.With().Caller().Logger()
log.Info().Msg("hello world")
// Output: {"level": "info", "message": "hello world", "caller": "some_file:21"}
```
### Thread-safe, lock-free, non-blocking writer
If 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:
```go
wr := diode.NewWriter(os.Stdout, 1000, 10*time.Millisecond, func(missed int) {
fmt.Printf("Logger Dropped %d messages", missed)
})
log := zerolog.New(wr)
log.Print("test")
```
You will need to install `code.cloudfoundry.org/go-diodes` to use this feature.
### Log Sampling
```go
sampled := log.Sample(&zerolog.BasicSampler{N: 10})
sampled.Info().Msg("will be logged every 10 messages")
// Output: {"time":1494567715,"level":"info","message":"will be logged every 10 messages"}
```
More advanced sampling:
```go
// Will let 5 debug messages per period of 1 second.
// Over 5 debug message, 1 every 100 debug messages are logged.
// Other levels are not sampled.
sampled := log.Sample(zerolog.LevelSampler{
DebugSampler: &zerolog.BurstSampler{
Burst: 5,
Period: 1*time.Second,
NextSampler: &zerolog.BasicSampler{N: 100},
},
})
sampled.Debug().Msg("hello world")
// Output: {"time":1494567715,"level":"debug","message":"hello world"}
```
### Hooks
```go
type SeverityHook struct{}
func (h SeverityHook) Run(e *zerolog.Event, level zerolog.Level, msg string) {
if level != zerolog.NoLevel {
e.Str("severity", level.String())
}
}
hooked := log.Hook(SeverityHook{})
hooked.Warn().Msg("")
// Output: {"level":"warn","severity":"warn"}
```
### Pass a sub-logger by context
```go
ctx := log.With().Str("component", "module").Logger().WithContext(ctx)
log.Ctx(ctx).Info().Msg("hello world")
// Output: {"component":"module","level":"info","message":"hello world"}
```
### Set as standard logger output
```go
log := zerolog.New(os.Stdout).With().
Str("foo", "bar").
Logger()
stdlog.SetFlags(0)
stdlog.SetOutput(log)
stdlog.Print("hello world")
// Output: {"foo":"bar","message":"hello world"}
```
### context.Context integration
Go contexts are commonly passed throughout Go code, and this can help you pass
your Logger into places it might otherwise be hard to inject. The `Logger`
instance may be attached to Go context (`context.Context`) using
`Logger.WithContext(ctx)` and extracted from it using `zerolog.Ctx(ctx)`.
For example:
```go
func f() {
logger := zerolog.New(os.Stdout)
ctx := context.Background()
// Attach the Logger to the context.Context
ctx = logger.WithContext(ctx)
someFunc(ctx)
}
func someFunc(ctx context.Context) {
// Get Logger from the go Context. if it's nil, then
// `zerolog.DefaultContextLogger` is returned, if
// `DefaultContextLogger` is nil, then a disabled logger is returned.
logger := zerolog.Ctx(ctx)
logger.Info().Msg("Hello")
}
```
A second form of `context.Context` integration allows you to pass the current
`context.Context` into the logged event, and retrieve it from hooks. This can be
useful to log trace and span IDs or other information stored in the go context,
and facilitates the unification of logging and tracing in some systems:
```go
type TracingHook struct{}
func (h TracingHook) Run(e *zerolog.Event, level zerolog.Level, msg string) {
ctx := e.GetCtx()
spanId := getSpanIdFromContext(ctx) // as per your tracing framework
e.Str("span-id", spanId)
}
func f() {
// Setup the logger
logger := zerolog.New(os.Stdout)
logger = logger.Hook(TracingHook{})
ctx := context.Background()
// Use the Ctx function to make the context available to the hook
logger.Info().Ctx(ctx).Msg("Hello")
}
```
### Integration with `net/http`
The `github.com/rs/zerolog/hlog` package provides some helpers to integrate zerolog with `http.Handler`.
In this example we use [alice](https://github.com/justinas/alice) to install logger for better readability.
```go
log := zerolog.New(os.Stdout).With().
Timestamp().
Str("role", "my-service").
Str("host", host).
Logger()
c := alice.New()
// Install the logger handler with default output on the console
c = c.Append(hlog.NewHandler(log))
// Install some provided extra handler to set some request's context fields.
// Thanks to that handler, all our logs will come with some prepopulated fields.
c = c.Append(hlog.AccessHandler(func(r *http.Request, status, size int, duration time.Duration) {
hlog.FromRequest(r).Info().
Str("method", r.Method).
Stringer("url", r.URL).
Int("status", status).
Int("size", size).
Dur("duration", duration).
Msg("")
}))
c = c.Append(hlog.RemoteAddrHandler("ip"))
c = c.Append(hlog.UserAgentHandler("user_agent"))
c = c.Append(hlog.RefererHandler("referer"))
c = c.Append(hlog.RequestIDHandler("req_id", "Request-Id"))
// Here is your final handler
h := c.Then(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
// Get the logger from the request's context. You can safely assume it
// will be always there: if the handler is removed, hlog.FromRequest
// will return a no-op logger.
hlog.FromRequest(r).Info().
Str("user", "current user").
Str("status", "ok").
Msg("Something happened")
// 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"}
}))
http.Handle("/", h)
if err := http.ListenAndServe(":8080", nil); err != nil {
log.Fatal().Err(err).Msg("Startup failed")
}
```
## Multiple Log Output
`zerolog.MultiLevelWriter` may be used to send the log message to multiple outputs.
In this example, we send the log message to both `os.Stdout` and the in-built `ConsoleWriter`.
```go
func main() {
consoleWriter := zerolog.ConsoleWriter{Out: os.Stdout}
multi := zerolog.MultiLevelWriter(consoleWriter, os.Stdout)
logger := zerolog.New(multi).With().Timestamp().Logger()
logger.Info().Msg("Hello World!")
}
// Output (Line 1: Console; Line 2: Stdout)
// 12:36PM INF Hello World!
// {"level":"info","time":"2019-11-07T12:36:38+03:00","message":"Hello World!"}
```
## Global Settings
Some settings can be changed and will be applied to all loggers:
- `log.Logger`: You can set this value to customize the global logger (the one used by package level methods).
- `zerolog.SetGlobalLevel`: Can raise the minimum level of all loggers. Call this with `zerolog.Disabled` to disable logging altogether (quiet mode).
- `zerolog.DisableSampling`: If argument is `true`, all sampled loggers will stop sampling and issue 100% of their log events.
- `zerolog.TimestampFieldName`: Can be set to customize `Timestamp` field name.
- `zerolog.LevelFieldName`: Can be set to customize level field name.
- `zerolog.MessageFieldName`: Can be set to customize message field name.
- `zerolog.ErrorFieldName`: Can be set to customize `Err` field name.
- `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.
- `zerolog.DurationFieldUnit`: Can be set to customize the unit for time.Duration type fields added by `Dur` (default: `time.Millisecond`).
- `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).
- `zerolog.DurationFieldInteger`: If set to `true`, `Dur` fields are formatted as integers instead of floats (default: `false`). Deprecated: Use `zerolog.DurationFieldFormat = DurationFormatInt` instead.
- `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.
- `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://pkg.go.dev/strconv#FormatFloat)
for more details.
## Field Types
### Standard Types
- `Str`
- `Bool`
- `Int`, `Int8`, `Int16`, `Int32`, `Int64`
- `Uint`, `Uint8`, `Uint16`, `Uint32`, `Uint64`
- `Float32`, `Float64`
### Advanced Fields
- `Err`: Takes an `error` and renders it as a string using the `zerolog.ErrorFieldName` field name.
- `Func`: Run a `func` only if the level is enabled.
- `Timestamp`: Inserts a timestamp field with `zerolog.TimestampFieldName` field name, formatted using `zerolog.TimeFieldFormat`.
- `Time`: Adds a field with time formatted with `zerolog.TimeFieldFormat`.
- `Dur`: Adds a field with `time.Duration`.
- `Dict`: Adds a sub-key/value as a field of the event.
- `RawJSON`: Adds a field with an already encoded JSON (`[]byte`)
- `Hex`: Adds a field with value formatted as a hexadecimal string (`[]byte`)
- `Interface`: Uses reflection to marshal the type.
- `IPAddr`: Adds a field with `net.IP`.
- `IPPrefix`: Adds a field with `net.IPNet`.
- `MACAddr`: Adds a field with `net.HardwareAddr`
Most fields are also available in the slice format (`Strs` for `[]string`, `Errs` for `[]error` etc.)
## Binary Encoding
In addition to the default JSON encoding, `zerolog` can produce binary logs using [CBOR](https://cbor.io) encoding. The choice of encoding can be decided at compile time using the build tag `binary_log` as follows:
```bash
go build -tags binary_log .
```
To decode binary encoded log files you can use any CBOR decoder. One has been tested to work
with zerolog library is [CSD](https://github.com/toravir/csd/).
## Integration with `log/slog`
zerolog provides a `slog.Handler` implementation that routes `log/slog` records through a zerolog logger. This lets you use the standard library's `slog` API while keeping zerolog's performance and encoding:
```go
package main
import (
"log/slog"
"github.com/rs/zerolog"
"github.com/rs/zerolog/log"
)
func main() {
zl := log.Logger
handler := zerolog.NewSlogHandler(zl)
logger := slog.New(handler)
logger.Info("user logged in", "user", "alice", "role", "admin")
}
// Output: {"level":"info","user":"alice","role":"admin","time":"...","message":"user logged in"}
```
The 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`).
## Related Projects
- [grpc-zerolog](https://github.com/cheapRoc/grpc-zerolog): Implementation of `grpclog.LoggerV2` interface using `zerolog`
- [overlog](https://github.com/Trendyol/overlog): Implementation of `Mapped Diagnostic Context` interface using `zerolog`
- [zerologr](https://github.com/go-logr/zerologr): Implementation of `logr.LogSink` interface using `zerolog`
- [logze](https://github.com/maxbolgarin/logze): Implementation of `log/slog` interface using `zerolog`
## Benchmarks
See [logbench](http://bench.zerolog.io/) for more comprehensive and up-to-date benchmarks.
All operations are allocation free (those numbers _include_ JSON encoding):
```text
BenchmarkLogEmpty-8 100000000 19.1 ns/op 0 B/op 0 allocs/op
BenchmarkDisabled-8 500000000 4.07 ns/op 0 B/op 0 allocs/op
BenchmarkInfo-8 30000000 42.5 ns/op 0 B/op 0 allocs/op
BenchmarkContextFields-8 30000000 44.9 ns/op 0 B/op 0 allocs/op
BenchmarkLogFields-8 10000000 184 ns/op 0 B/op 0 allocs/op
```
There are a few Go logging benchmarks and comparisons that include zerolog.
- [imkira/go-loggers-bench](https://github.com/imkira/go-loggers-bench)
- [uber-common/zap](https://github.com/uber-go/zap#performance)
Using Uber's zap comparison benchmark:
Log a message and 10 fields:
| Library | Time | Bytes Allocated | Objects Allocated |
| :------------------ | :---------: | :-------------: | :---------------: |
| zerolog | 767 ns/op | 552 B/op | 6 allocs/op |
| :zap: zap | 848 ns/op | 704 B/op | 2 allocs/op |
| :zap: zap (sugared) | 1363 ns/op | 1610 B/op | 20 allocs/op |
| go-kit | 3614 ns/op | 2895 B/op | 66 allocs/op |
| lion | 5392 ns/op | 5807 B/op | 63 allocs/op |
| logrus | 5661 ns/op | 6092 B/op | 78 allocs/op |
| apex/log | 15332 ns/op | 3832 B/op | 65 allocs/op |
| log15 | 20657 ns/op | 5632 B/op | 93 allocs/op |
Log a message with a logger that already has 10 fields of context:
| Library | Time | Bytes Allocated | Objects Allocated |
| :------------------ | :---------: | :-------------: | :---------------: |
| zerolog | 52 ns/op | 0 B/op | 0 allocs/op |
| :zap: zap | 283 ns/op | 0 B/op | 0 allocs/op |
| :zap: zap (sugared) | 337 ns/op | 80 B/op | 2 allocs/op |
| lion | 2702 ns/op | 4074 B/op | 38 allocs/op |
| go-kit | 3378 ns/op | 3046 B/op | 52 allocs/op |
| logrus | 4309 ns/op | 4564 B/op | 63 allocs/op |
| apex/log | 13456 ns/op | 2898 B/op | 51 allocs/op |
| log15 | 14179 ns/op | 2642 B/op | 44 allocs/op |
Log a static string, without any context or `printf`-style templating:
| Library | Time | Bytes Allocated | Objects Allocated |
| :------------------ | :--------: | :-------------: | :---------------: |
| zerolog | 50 ns/op | 0 B/op | 0 allocs/op |
| :zap: zap | 236 ns/op | 0 B/op | 0 allocs/op |
| standard library | 453 ns/op | 80 B/op | 2 allocs/op |
| :zap: zap (sugared) | 337 ns/op | 80 B/op | 2 allocs/op |
| go-kit | 508 ns/op | 656 B/op | 13 allocs/op |
| lion | 771 ns/op | 1224 B/op | 10 allocs/op |
| logrus | 1244 ns/op | 1505 B/op | 27 allocs/op |
| apex/log | 2751 ns/op | 584 B/op | 11 allocs/op |
| log15 | 5181 ns/op | 1592 B/op | 26 allocs/op |
## Caveats
### Field duplication
Note that zerolog does no de-duplication of fields. Using the same key multiple times creates multiple keys in final JSON:
```go
logger := zerolog.New(os.Stderr).With().Timestamp().Logger()
logger.Info().
Timestamp().
Msg("dup")
// Output: {"level":"info","time":1494567715,"time":1494567715,"message":"dup"}
```
In this case, many consumers will take the last value, but this is not guaranteed; check yours if in doubt.
### Concurrency safety
Be careful when calling `UpdateContext`. It is not concurrency safe. Use the `With()` method to create a child logger:
```go
func handler(w http.ResponseWriter, r *http.Request) {
// Create a child logger for concurrency safety
logger := log.Logger.With().Logger()
// Add context fields, for example User-Agent from HTTP headers
logger.UpdateContext(func(c zerolog.Context) zerolog.Context {
...
})
}
```
The `Event` object returned from the `Logger` level-specific message functions (e.g. `Log()`, `Trace()`, `Debug()`, etc.)
is allocated in `sync.Pool` memory that will be returned to the pool as soon as the `Msg()`, `Msgf()`, `Send()`,
or `MsgFunc()` writes the message and **must not** be accessed afterwards.
**Do not** hold a reference to the `*Event` while in callback functions or your own code. This is especially important in
`Hook.Run()` and `HookFunc` functions or `MarshalZerologObject(e *Event)` callback (e.g. `LogObjectMarshaler` implementations).
Any `Array` objects returned from `Context.CreateArray()` or `Event.CreateArray()` are from a `sync.Pool` so **do not** hold
references to them from within any `MarshalZerologArray(a *Array)` callback (e.g. `LogArrayMarshaler` implementations) or your
own code as they will be cleared and returned to the pool after being buffered by a call to `Context.Array()` or `Event.Array()`.
Any _dictionary_ `Event` returned from `Context.CreateDict()` or `Event.CreateDict()` **must not** be referenced after being
buffered by a call to `Array.Dict()`, `Context.Dict()`, or `Event.Dict()` as they will be cleared and returned to the pool.
================================================
FILE: array.go
================================================
package zerolog
import (
"context"
"net"
"sync"
"time"
)
var arrayPool = &sync.Pool{
New: func() interface{} {
return &Array{
buf: make([]byte, 0, 500),
}
},
}
// Array is used to prepopulate an array of items
// which can be re-used to add to log messages.
type Array struct {
buf []byte
stack bool // enable error stack trace
ctx context.Context // Optional Go context
ch []Hook // hooks
}
func putArray(a *Array) {
// prevent any subsequent use of the Array contextual state and truncate the buffer
a.stack = false
a.ctx = nil
a.ch = nil
a.buf = a.buf[:0]
// Proper usage of a sync.Pool requires each entry to have approximately
// the same memory cost. To obtain this property when the stored type
// contains a variably-sized buffer, we add a hard limit on the maximum buffer
// to place back in the pool.
//
// See https://golang.org/issue/23199
const maxSize = 1 << 16 // 64KiB
if cap(a.buf) <= maxSize {
arrayPool.Put(a)
}
}
// Arr creates an array to be added to an Event or Context.
// WARNING: This function is deprecated because it does not preserve
// the stack, hooks, and context from the parent event.
// Deprecated: Use Event.CreateArray or Context.CreateArray instead.
func Arr() *Array {
a := arrayPool.Get().(*Array)
a.buf = a.buf[:0]
a.stack = false
a.ctx = nil
a.ch = nil
return a
}
// MarshalZerologArray method here is no-op - since data is
// already in the needed format.
func (*Array) MarshalZerologArray(*Array) {
// untestable: there's no code to be covered
}
func (a *Array) write(dst []byte) []byte {
dst = enc.AppendArrayStart(dst)
if len(a.buf) > 0 {
dst = append(dst, a.buf...)
}
dst = enc.AppendArrayEnd(dst)
putArray(a)
return dst
}
// Object marshals an object that implement the LogObjectMarshaler
// interface and appends it to the array.
func (a *Array) Object(obj LogObjectMarshaler) *Array {
a.buf = appendObject(enc.AppendArrayDelim(a.buf), obj, a.stack, a.ctx, a.ch)
return a
}
// Str appends the val as a string to the array.
func (a *Array) Str(val string) *Array {
a.buf = enc.AppendString(enc.AppendArrayDelim(a.buf), val)
return a
}
// Bytes appends the val as a string to the array.
func (a *Array) Bytes(val []byte) *Array {
a.buf = enc.AppendBytes(enc.AppendArrayDelim(a.buf), val)
return a
}
// Hex appends the val as a hex string to the array.
func (a *Array) Hex(val []byte) *Array {
a.buf = enc.AppendHex(enc.AppendArrayDelim(a.buf), val)
return a
}
// RawJSON adds already encoded JSON to the array.
func (a *Array) RawJSON(val []byte) *Array {
a.buf = appendJSON(enc.AppendArrayDelim(a.buf), val)
return a
}
// Err serializes and appends the err to the array.
func (a *Array) Err(err error) *Array {
switch m := ErrorMarshalFunc(err).(type) {
case nil:
a.buf = enc.AppendNil(enc.AppendArrayDelim(a.buf))
case LogObjectMarshaler:
a = a.Object(m)
case error:
if !isNilValue(m) {
a.buf = enc.AppendString(enc.AppendArrayDelim(a.buf), m.Error())
}
case string:
a.buf = enc.AppendString(enc.AppendArrayDelim(a.buf), m)
default:
a.buf = enc.AppendInterface(enc.AppendArrayDelim(a.buf), m)
}
return a
}
// Errs serializes and appends errors to the array.
func (a *Array) Errs(errs []error) *Array {
for _, err := range errs {
switch m := ErrorMarshalFunc(err).(type) {
case nil:
a = a.Interface(nil)
case LogObjectMarshaler:
a = a.Object(m)
case error:
if !isNilValue(m) {
a = a.Str(m.Error())
}
case string:
a = a.Str(m)
default:
a = a.Interface(m)
}
}
return a
}
// Bool appends the val as a bool to the array.
func (a *Array) Bool(b bool) *Array {
a.buf = enc.AppendBool(enc.AppendArrayDelim(a.buf), b)
return a
}
// Int appends i as a int to the array.
func (a *Array) Int(i int) *Array {
a.buf = enc.AppendInt(enc.AppendArrayDelim(a.buf), i)
return a
}
// Int8 appends i as a int8 to the array.
func (a *Array) Int8(i int8) *Array {
a.buf = enc.AppendInt8(enc.AppendArrayDelim(a.buf), i)
return a
}
// Int16 appends i as a int16 to the array.
func (a *Array) Int16(i int16) *Array {
a.buf = enc.AppendInt16(enc.AppendArrayDelim(a.buf), i)
return a
}
// Int32 appends i as a int32 to the array.
func (a *Array) Int32(i int32) *Array {
a.buf = enc.AppendInt32(enc.AppendArrayDelim(a.buf), i)
return a
}
// Int64 appends i as a int64 to the array.
func (a *Array) Int64(i int64) *Array {
a.buf = enc.AppendInt64(enc.AppendArrayDelim(a.buf), i)
return a
}
// Uint appends i as a uint to the array.
func (a *Array) Uint(i uint) *Array {
a.buf = enc.AppendUint(enc.AppendArrayDelim(a.buf), i)
return a
}
// Uint8 appends i as a uint8 to the array.
func (a *Array) Uint8(i uint8) *Array {
a.buf = enc.AppendUint8(enc.AppendArrayDelim(a.buf), i)
return a
}
// Uint16 appends i as a uint16 to the array.
func (a *Array) Uint16(i uint16) *Array {
a.buf = enc.AppendUint16(enc.AppendArrayDelim(a.buf), i)
return a
}
// Uint32 appends i as a uint32 to the array.
func (a *Array) Uint32(i uint32) *Array {
a.buf = enc.AppendUint32(enc.AppendArrayDelim(a.buf), i)
return a
}
// Uint64 appends i as a uint64 to the array.
func (a *Array) Uint64(i uint64) *Array {
a.buf = enc.AppendUint64(enc.AppendArrayDelim(a.buf), i)
return a
}
// Float32 appends f as a float32 to the array.
func (a *Array) Float32(f float32) *Array {
a.buf = enc.AppendFloat32(enc.AppendArrayDelim(a.buf), f, FloatingPointPrecision)
return a
}
// Float64 appends f as a float64 to the array.
func (a *Array) Float64(f float64) *Array {
a.buf = enc.AppendFloat64(enc.AppendArrayDelim(a.buf), f, FloatingPointPrecision)
return a
}
// Time appends t formatted as string using zerolog.TimeFieldFormat.
func (a *Array) Time(t time.Time) *Array {
a.buf = enc.AppendTime(enc.AppendArrayDelim(a.buf), t, TimeFieldFormat)
return a
}
// Dur appends d to the array.
func (a *Array) Dur(d time.Duration) *Array {
a.buf = enc.AppendDuration(enc.AppendArrayDelim(a.buf), d, DurationFieldUnit, DurationFieldFormat, DurationFieldInteger, FloatingPointPrecision)
return a
}
// Interface appends i marshaled using reflection.
func (a *Array) Interface(i interface{}) *Array {
if obj, ok := i.(LogObjectMarshaler); ok {
return a.Object(obj)
}
a.buf = enc.AppendInterface(enc.AppendArrayDelim(a.buf), i)
return a
}
// IPAddr adds a net.IP IPv4 or IPv6 address to the array
func (a *Array) IPAddr(ip net.IP) *Array {
a.buf = enc.AppendIPAddr(enc.AppendArrayDelim(a.buf), ip)
return a
}
// IPPrefix adds a net.IPNet IPv4 or IPv6 Prefix (IP + mask) to the array
func (a *Array) IPPrefix(pfx net.IPNet) *Array {
a.buf = enc.AppendIPPrefix(enc.AppendArrayDelim(a.buf), pfx)
return a
}
// MACAddr adds a net.HardwareAddr MAC (Ethernet) address to the array
func (a *Array) MACAddr(ha net.HardwareAddr) *Array {
a.buf = enc.AppendMACAddr(enc.AppendArrayDelim(a.buf), ha)
return a
}
// Dict adds the dict Event to the array
func (a *Array) Dict(dict *Event) *Array {
dict.buf = enc.AppendEndMarker(dict.buf)
a.buf = append(enc.AppendArrayDelim(a.buf), dict.buf...)
putEvent(dict)
return a
}
// Type adds the val's type using reflection to the array.
func (a *Array) Type(val interface{}) *Array {
a.buf = enc.AppendType(enc.AppendArrayDelim(a.buf), val)
return a
}
================================================
FILE: array_test.go
================================================
package zerolog
import (
"fmt"
"net"
"testing"
"time"
)
func TestArray(t *testing.T) {
a := Arr().
Bool(true).
Int(1).
Int8(2).
Int16(3).
Int32(4).
Int64(5).
Uint(6).
Uint8(7).
Uint16(8).
Uint32(9).
Uint64(10).
Float32(11.98122).
Float64(12.987654321).
Str("a").
Bytes([]byte("b")).
Hex([]byte{0x1f}).
RawJSON([]byte(`{"some":"json"}`)).
RawJSON([]byte(`{"longer":[1111,2222,3333,4444,5555]}`)).
Time(time.Time{}).
IPAddr(net.IP{192, 168, 0, 10}).
IPPrefix(net.IPNet{IP: net.IP{127, 0, 0, 0}, Mask: net.CIDRMask(24, 32)}).
MACAddr(net.HardwareAddr{0x01, 0x23, 0x45, 0x67, 0x89, 0xab}).
Interface(struct {
Pub string
Tag string `json:"tag"`
priv int
}{"A", "j", -5}).
Interface(logObjectMarshalerImpl{
name: "ZOT",
age: 35,
}).
Dur(0).
Dict(Dict().
Str("bar", "baz").
Int("n", 1),
).
Err(nil).
Err(fmt.Errorf("failure")).
Err(loggableError{fmt.Errorf("oops")}).
Object(logObjectMarshalerImpl{
name: "ZIT",
age: 22,
}).
Type(3.14)
want := `[true,1,2,3,4,5,6,7,8,9,10,11.98122,12.987654321,"a","b","1f",{"some":"json"},{"longer":[1111,2222,3333,4444,5555]},"0001-01-01T00:00:00Z","192.168.0.10","127.0.0.0/24","01:23:45:67:89:ab",{"Pub":"A","tag":"j"},{"name":"zot","age":-35},0,{"bar":"baz","n":1},null,"failure",{"l":"OOPS"},{"name":"zit","age":-22},"float64"]`
if got := decodeObjectToStr(a.write([]byte{})); got != want {
t.Errorf("Array.write()\ngot: %s\nwant: %s", got, want)
}
}
func TestArray_MarshalZerologArray(t *testing.T) {
a := Arr()
a.MarshalZerologArray(nil) // no-op method, should not panic
}
================================================
FILE: benchmark_test.go
================================================
package zerolog
import (
"errors"
"io"
"testing"
"time"
)
var (
errExample = errors.New("fail")
fakeMessage = "Test logging, but use a somewhat realistic message length."
)
func BenchmarkLogEmpty(b *testing.B) {
logger := New(io.Discard)
b.ResetTimer()
b.RunParallel(func(pb *testing.PB) {
for pb.Next() {
logger.Log().Msg("")
}
})
}
func BenchmarkDisabled(b *testing.B) {
logger := New(io.Discard).Level(Disabled)
b.ResetTimer()
b.RunParallel(func(pb *testing.PB) {
for pb.Next() {
logger.Info().Msg(fakeMessage)
}
})
}
func BenchmarkInfo(b *testing.B) {
logger := New(io.Discard)
b.ResetTimer()
b.RunParallel(func(pb *testing.PB) {
for pb.Next() {
logger.Info().Msg(fakeMessage)
}
})
}
func BenchmarkContextFields(b *testing.B) {
logger := New(io.Discard).With().
Str("string", "four!").
Time("time", time.Time{}).
Int("int", 123).
Float32("float", -2.203230293249593).
Logger()
b.ResetTimer()
b.RunParallel(func(pb *testing.PB) {
for pb.Next() {
logger.Info().Msg(fakeMessage)
}
})
}
func BenchmarkContextAppend(b *testing.B) {
logger := New(io.Discard).With().
Str("foo", "bar").
Logger()
b.ResetTimer()
b.RunParallel(func(pb *testing.PB) {
for pb.Next() {
logger.With().Str("bar", "baz")
}
})
}
func BenchmarkLogFields(b *testing.B) {
logger := New(io.Discard)
b.ResetTimer()
b.RunParallel(func(pb *testing.PB) {
for pb.Next() {
logger.Info().
Str("string", "four!").
Time("time", time.Time{}).
Int("int", 123).
Float32("float", -2.203230293249593).
Msg(fakeMessage)
}
})
}
func BenchmarkLogArrayObject(b *testing.B) {
obj1 := fixtureObj{"a", "b", 2}
obj2 := fixtureObj{"c", "d", 3}
obj3 := fixtureObj{"e", "f", 4}
logger := New(io.Discard)
b.ResetTimer()
b.ReportAllocs()
for i := 0; i < b.N; i++ {
arr := Arr()
arr.Object(&obj1)
arr.Object(&obj2)
arr.Object(&obj3)
logger.Info().Array("objects", arr).Msg("test")
}
}
func BenchmarkLogFieldType(b *testing.B) {
fixtures := makeFieldFixtures()
types := map[string]func(e *Event) *Event{
"Any": func(e *Event) *Event {
return e.Any("k", fixtures.Interfaces[0])
},
"Bool": func(e *Event) *Event {
return e.Bool("k", fixtures.Bools[0])
},
"Bools": func(e *Event) *Event {
return e.Bools("k", fixtures.Bools)
},
"Bytes": func(e *Event) *Event {
return e.Bytes("k", fixtures.Bytes)
},
"Hex": func(e *Event) *Event {
return e.Hex("k", fixtures.Bytes)
},
"Int": func(e *Event) *Event {
return e.Int("k", fixtures.Ints[0])
},
"Ints": func(e *Event) *Event {
return e.Ints("k", fixtures.Ints)
},
"Float32": func(e *Event) *Event {
return e.Float32("k", fixtures.Floats32[0])
},
"Floats32": func(e *Event) *Event {
return e.Floats32("k", fixtures.Floats32)
},
"Float64": func(e *Event) *Event {
return e.Float64("k", fixtures.Floats64[0])
},
"Floats64": func(e *Event) *Event {
return e.Floats64("k", fixtures.Floats64)
},
"Str": func(e *Event) *Event {
return e.Str("k", fixtures.Strings[0])
},
"Strs": func(e *Event) *Event {
return e.Strs("k", fixtures.Strings)
},
"Stringer": func(e *Event) *Event {
return e.Stringer("k", fixtures.Stringers[0])
},
"Stringers": func(e *Event) *Event {
return e.Stringers("k", fixtures.Stringers)
},
"Err": func(e *Event) *Event {
return e.Err(fixtures.Errs[0])
},
"Errs": func(e *Event) *Event {
return e.Errs("k", fixtures.Errs)
},
"Ctx": func(e *Event) *Event {
return e.Ctx(fixtures.Ctx)
},
"Time": func(e *Event) *Event {
return e.Time("k", fixtures.Times[0])
},
"Times": func(e *Event) *Event {
return e.Times("k", fixtures.Times)
},
"Dur": func(e *Event) *Event {
return e.Dur("k", fixtures.Durations[0])
},
"Durs": func(e *Event) *Event {
return e.Durs("k", fixtures.Durations)
},
"Interface": func(e *Event) *Event {
return e.Interface("k", fixtures.Interfaces[0])
},
"Interfaces": func(e *Event) *Event {
return e.Interface("k", fixtures.Interfaces)
},
"Interface(Object)": func(e *Event) *Event {
return e.Interface("k", fixtures.Objects[0])
},
"Interface(Objects)": func(e *Event) *Event {
return e.Interface("k", fixtures.Objects)
},
"Object": func(e *Event) *Event {
return e.Object("k", fixtures.Objects[0])
},
"Objects": func(e *Event) *Event {
return e.Objects("k", fixtures.Objects)
},
"Timestamp": func(e *Event) *Event {
return e.Timestamp()
},
"IPAddr": func(e *Event) *Event {
return e.IPAddr("k", fixtures.IPAddrs[0])
},
"IPAddrs": func(e *Event) *Event {
return e.IPAddrs("k", fixtures.IPAddrs)
},
"IPPrefix": func(e *Event) *Event {
return e.IPPrefix("k", fixtures.IPPfxs[0])
},
"IPPrefixes": func(e *Event) *Event {
return e.IPPrefixes("k", fixtures.IPPfxs)
},
"MACAddr": func(e *Event) *Event {
return e.MACAddr("k", fixtures.MACAddr)
},
"Type": func(e *Event) *Event {
return e.Type("k", fixtures.Type)
},
}
logger := New(io.Discard)
b.ResetTimer()
for name := range types {
f := types[name]
b.Run(name, func(b *testing.B) {
b.RunParallel(func(pb *testing.PB) {
for pb.Next() {
f(logger.Info()).Msg("")
}
})
})
}
}
func BenchmarkContextFieldType(b *testing.B) {
oldFormat := TimeFieldFormat
TimeFieldFormat = TimeFormatUnix
defer func() { TimeFieldFormat = oldFormat }()
fixtures := makeFieldFixtures()
types := map[string]func(c Context) Context{
"Any": func(c Context) Context {
return c.Any("k", fixtures.Interfaces[0])
},
"Bool": func(c Context) Context {
return c.Bool("k", fixtures.Bools[0])
},
"Bools": func(c Context) Context {
return c.Bools("k", fixtures.Bools)
},
"Bytes": func(c Context) Context {
return c.Bytes("k", fixtures.Bytes)
},
"Hex": func(c Context) Context {
return c.Hex("k", fixtures.Bytes)
},
"Int": func(c Context) Context {
return c.Int("k", fixtures.Ints[0])
},
"Ints": func(c Context) Context {
return c.Ints("k", fixtures.Ints)
},
"Float32": func(c Context) Context {
return c.Float32("k", fixtures.Floats32[0])
},
"Floats32": func(c Context) Context {
return c.Floats32("k", fixtures.Floats32)
},
"Float64": func(c Context) Context {
return c.Float64("k", fixtures.Floats64[0])
},
"Floats64": func(c Context) Context {
return c.Floats64("k", fixtures.Floats64)
},
"Str": func(c Context) Context {
return c.Str("k", fixtures.Strings[0])
},
"Strs": func(c Context) Context {
return c.Strs("k", fixtures.Strings)
},
"Stringer": func(c Context) Context {
return c.Stringer("k", fixtures.Stringers[0])
},
"Stringers": func(c Context) Context {
return c.Stringers("k", fixtures.Stringers)
},
"Err": func(c Context) Context {
return c.Err(fixtures.Errs[0])
},
"Errs": func(c Context) Context {
return c.Errs("k", fixtures.Errs)
},
"Ctx": func(c Context) Context {
return c.Ctx(fixtures.Ctx)
},
"Time": func(c Context) Context {
return c.Time("k", fixtures.Times[0])
},
"Times": func(c Context) Context {
return c.Times("k", fixtures.Times)
},
"Dur": func(c Context) Context {
return c.Dur("k", fixtures.Durations[0])
},
"Durs": func(c Context) Context {
return c.Durs("k", fixtures.Durations)
},
"Interface": func(c Context) Context {
return c.Interface("k", fixtures.Interfaces[0])
},
"Interfaces": func(c Context) Context {
return c.Interface("k", fixtures.Interfaces)
},
"Interface(Object)": func(c Context) Context {
return c.Interface("k", fixtures.Objects[0])
},
"Interface(Objects)": func(c Context) Context {
return c.Interface("k", fixtures.Objects)
},
"Object": func(c Context) Context {
return c.Object("k", fixtures.Objects[0])
},
"Objects": func(c Context) Context {
return c.Objects("k", fixtures.Objects)
},
"Timestamp": func(c Context) Context {
return c.Timestamp()
},
"IPAddr": func(c Context) Context {
return c.IPAddr("k", fixtures.IPAddrs[0])
},
"IPAddrs": func(c Context) Context {
return c.IPAddrs("k", fixtures.IPAddrs)
},
"IPPrefix": func(c Context) Context {
return c.IPPrefix("k", fixtures.IPPfxs[0])
},
"IPPrefixes": func(c Context) Context {
return c.IPPrefixes("k", fixtures.IPPfxs)
},
"MACAddr": func(c Context) Context {
return c.MACAddr("k", fixtures.MACAddr)
},
"Type": func(c Context) Context {
return c.Type("k", fixtures.Type)
},
}
logger := New(io.Discard)
b.ResetTimer()
for name := range types {
f := types[name]
b.Run(name, func(b *testing.B) {
b.RunParallel(func(pb *testing.PB) {
for pb.Next() {
l := f(logger.With()).Logger()
l.Info().Msg("")
}
})
})
}
}
================================================
FILE: binary_test.go
================================================
//go:build binary_log
// +build binary_log
package zerolog
import (
"bytes"
"errors"
"fmt"
"net"
stdlog "log"
"time"
)
func ExampleLogger_With() {
dst := bytes.Buffer{}
log := New(&dst).
With().
Str("foo", "bar").
Logger()
log.Info().Msg("hello world")
fmt.Println(decodeIfBinaryToString(dst.Bytes()))
// Output: {"level":"info","foo":"bar","message":"hello world"}
}
func ExampleLogger_Level() {
dst := bytes.Buffer{}
log := New(&dst).Level(WarnLevel)
log.Info().Msg("filtered out message")
log.Error().Msg("kept message")
fmt.Println(decodeIfBinaryToString(dst.Bytes()))
// Output: {"level":"error","message":"kept message"}
}
func ExampleLogger_Sample() {
dst := bytes.Buffer{}
log := New(&dst).Sample(&BasicSampler{N: 2})
log.Info().Msg("message 1")
log.Info().Msg("message 2")
log.Info().Msg("message 3")
log.Info().Msg("message 4")
fmt.Println(decodeIfBinaryToString(dst.Bytes()))
// Output: {"level":"info","message":"message 1"}
// {"level":"info","message":"message 3"}
}
type LevelNameHook1 struct{}
func (h LevelNameHook1) Run(e *Event, l Level, msg string) {
if l != NoLevel {
e.Str("level_name", l.String())
} else {
e.Str("level_name", "NoLevel")
}
}
type MessageHook string
func (h MessageHook) Run(e *Event, l Level, msg string) {
e.Str("the_message", msg)
}
func ExampleLogger_Hook() {
var levelNameHook LevelNameHook1
var messageHook MessageHook = "The message"
dst := bytes.Buffer{}
log := New(&dst).Hook(levelNameHook).Hook(messageHook)
log.Info().Msg("hello world")
fmt.Println(decodeIfBinaryToString(dst.Bytes()))
// Output: {"level":"info","level_name":"info","the_message":"hello world","message":"hello world"}
}
func ExampleLogger_Print() {
dst := bytes.Buffer{}
log := New(&dst)
log.Print("hello world")
fmt.Println(decodeIfBinaryToString(dst.Bytes()))
// Output: {"level":"debug","message":"hello world"}
}
func ExampleLogger_Printf() {
dst := bytes.Buffer{}
log := New(&dst)
log.Printf("hello %s", "world")
fmt.Println(decodeIfBinaryToString(dst.Bytes()))
// Output: {"level":"debug","message":"hello world"}
}
func ExampleLogger_Trace() {
dst := bytes.Buffer{}
log := New(&dst)
log.Trace().
Str("foo", "bar").
Int("n", 123).
Msg("hello world")
fmt.Println(decodeIfBinaryToString(dst.Bytes()))
// Output: {"level":"trace","foo":"bar","n":123,"message":"hello world"}
}
func ExampleLogger_Debug() {
dst := bytes.Buffer{}
log := New(&dst)
log.Debug().
Str("foo", "bar").
Int("n", 123).
Msg("hello world")
fmt.Println(decodeIfBinaryToString(dst.Bytes()))
// Output: {"level":"debug","foo":"bar","n":123,"message":"hello world"}
}
func ExampleLogger_Info() {
dst := bytes.Buffer{}
log := New(&dst)
log.Info().
Str("foo", "bar").
Int("n", 123).
Msg("hello world")
fmt.Println(decodeIfBinaryToString(dst.Bytes()))
// Output: {"level":"info","foo":"bar","n":123,"message":"hello world"}
}
func ExampleLogger_Warn() {
dst := bytes.Buffer{}
log := New(&dst)
log.Warn().
Str("foo", "bar").
Msg("a warning message")
fmt.Println(decodeIfBinaryToString(dst.Bytes()))
// Output: {"level":"warn","foo":"bar","message":"a warning message"}
}
func ExampleLogger_Error() {
dst := bytes.Buffer{}
log := New(&dst)
log.Error().
Err(errors.New("some error")).
Msg("error doing something")
fmt.Println(decodeIfBinaryToString(dst.Bytes()))
// Output: {"level":"error","error":"some error","message":"error doing something"}
}
func ExampleLogger_WithLevel() {
dst := bytes.Buffer{}
log := New(&dst)
log.WithLevel(InfoLevel).
Msg("hello world")
fmt.Println(decodeIfBinaryToString(dst.Bytes()))
// Output: {"level":"info","message":"hello world"}
}
func ExampleLogger_Write() {
dst := bytes.Buffer{}
log := New(&dst).With().
Str("foo", "bar").
Logger()
stdlog.SetFlags(0)
stdlog.SetOutput(log)
stdlog.Print("hello world")
fmt.Println(decodeIfBinaryToString(dst.Bytes()))
// Output: {"foo":"bar","message":"hello world"}
}
func ExampleLogger_Log() {
dst := bytes.Buffer{}
log := New(&dst)
log.Log().
Str("foo", "bar").
Str("bar", "baz").
Msg("")
fmt.Println(decodeIfBinaryToString(dst.Bytes()))
// Output: {"foo":"bar","bar":"baz"}
}
func ExampleEvent_Dict() {
dst := bytes.Buffer{}
log := New(&dst)
e := log.Log().
Str("foo", "bar")
e.Dict("dict", e.CreateDict().
Str("bar", "baz").
Int("n", 1),
).
Msg("hello world")
fmt.Println(decodeIfBinaryToString(dst.Bytes()))
// Output: {"foo":"bar","dict":{"bar":"baz","n":1},"message":"hello world"}
}
type User struct {
Name string
Age int
Created time.Time
}
func (u User) MarshalZerologObject(e *Event) {
e.Str("name", u.Name).
Int("age", u.Age).
Time("created", u.Created)
}
type Users []User
// User implements LogObjectMarshaler
func (uu Users) MarshalZerologArray(a *Array) {
for _, u := range uu {
a.Object(u)
}
}
func ExampleEvent_Array() {
dst := bytes.Buffer{}
log := New(&dst)
e := log.Log().
Str("foo", "bar")
e.Array("array", e.CreateArray().
Str("baz").
Int(1),
).
Msg("hello world")
fmt.Println(decodeIfBinaryToString(dst.Bytes()))
// Output: {"foo":"bar","array":["baz",1],"message":"hello world"}
}
func ExampleEvent_Array_object() {
dst := bytes.Buffer{}
log := New(&dst)
// Users implements LogArrayMarshaler
u := Users{
User{"John", 35, time.Time{}},
User{"Bob", 55, time.Time{}},
}
log.Log().
Str("foo", "bar").
Array("users", u).
Msg("hello world")
fmt.Println(decodeIfBinaryToString(dst.Bytes()))
// Output: {"foo":"bar","users":[{"name":"John","age":35,"created":"0001-01-01T00:00:00Z"},{"name":"Bob","age":55,"created":"0001-01-01T00:00:00Z"}],"message":"hello world"}
}
func ExampleEvent_Object() {
dst := bytes.Buffer{}
log := New(&dst)
// User implements LogObjectMarshaler
u := User{"John", 35, time.Time{}}
log.Log().
Str("foo", "bar").
Object("user", u).
Msg("hello world")
fmt.Println(decodeIfBinaryToString(dst.Bytes()))
// Output: {"foo":"bar","user":{"name":"John","age":35,"created":"0001-01-01T00:00:00Z"},"message":"hello world"}
}
func ExampleContext_Objects() {
// In go, arrays are type invariant so even if you have a variable u of type []User array and User implements
// the LogObjectMarshaler interface, you cannot pass that to func that takes an []LogObjectMarshaler array in the
// Objects call. In 1.24+ it allows passing the variadic covariant slice (e.g. u...) but the unit test needs to
// work in earlier versions so we'll declare the array as []LogObjectMarshaler here.
u := []LogObjectMarshaler{User{"John", 35, time.Time{}}, User{"Bob", 55, time.Time{}}}
dst := bytes.Buffer{}
log := New(&dst).With().
Str("foo", "bar").
Objects("users", u).
Logger()
log.Log().Msg("hello world")
fmt.Println(decodeIfBinaryToString(dst.Bytes()))
// Output: {"foo":"bar","users":[{"name":"John","age":35,"created":"0001-01-01T00:00:00Z"},{"name":"Bob","age":55,"created":"0001-01-01T00:00:00Z"}],"message":"hello world"}
}
func ExampleEvent_EmbedObject() {
price := Price{val: 6449, prec: 2, unit: "$"}
dst := bytes.Buffer{}
log := New(&dst)
log.Log().
Str("foo", "bar").
EmbedObject(price).
Msg("hello world")
fmt.Println(decodeIfBinaryToString(dst.Bytes()))
// Output: {"foo":"bar","price":"$64.49","message":"hello world"}
}
func ExampleEvent_Interface() {
dst := bytes.Buffer{}
log := New(&dst)
obj := struct {
Name string `json:"name"`
}{
Name: "john",
}
log.Log().
Str("foo", "bar").
Interface("obj", obj).
Msg("hello world")
fmt.Println(decodeIfBinaryToString(dst.Bytes()))
// Output: {"foo":"bar","obj":{"name":"john"},"message":"hello world"}
}
func ExampleEvent_Dur() {
d := time.Duration(10 * time.Second)
dst := bytes.Buffer{}
log := New(&dst)
log.Log().
Str("foo", "bar").
Dur("dur", d).
Msg("hello world")
fmt.Println(decodeIfBinaryToString(dst.Bytes()))
// Output: {"foo":"bar","dur":10000,"message":"hello world"}
}
func ExampleEvent_Durs() {
d := []time.Duration{
time.Duration(10 * time.Second),
time.Duration(20 * time.Second),
}
dst := bytes.Buffer{}
log := New(&dst)
log.Log().
Str("foo", "bar").
Durs("durs", d).
Msg("hello world")
fmt.Println(decodeIfBinaryToString(dst.Bytes()))
// Output: {"foo":"bar","durs":[10000,20000],"message":"hello world"}
}
func ExampleEvent_Fields_map() {
fields := map[string]interface{}{
"bar": "baz",
"n": 1,
}
dst := bytes.Buffer{}
log := New(&dst)
log.Log().
Str("foo", "bar").
Fields(fields).
Msg("hello world")
fmt.Println(decodeIfBinaryToString(dst.Bytes()))
// Output: {"foo":"bar","bar":"baz","n":1,"message":"hello world"}
}
func ExampleEvent_Fields_slice() {
fields := []interface{}{
"bar", "baz",
"n", 1,
}
dst := bytes.Buffer{}
log := New(&dst)
log.Log().
Str("foo", "bar").
Fields(fields).
Msg("hello world")
fmt.Println(decodeIfBinaryToString(dst.Bytes()))
// Output: {"foo":"bar","bar":"baz","n":1,"message":"hello world"}
}
func ExampleContext_Dict() {
dst := bytes.Buffer{}
ctx := New(&dst).With().
Str("foo", "bar")
logger := ctx.Dict("dict", ctx.CreateDict().
Str("bar", "baz").
Int("n", 1),
).Logger()
logger.Log().Msg("hello world")
fmt.Println(decodeIfBinaryToString(dst.Bytes()))
// Output: {"foo":"bar","dict":{"bar":"baz","n":1},"message":"hello world"}
}
func ExampleContext_Array() {
dst := bytes.Buffer{}
ctx := New(&dst).With().
Str("foo", "bar")
logger := ctx.Array("array", ctx.CreateArray().
Str("baz").
Int(1),
).Logger()
logger.Log().Msg("hello world")
fmt.Println(decodeIfBinaryToString(dst.Bytes()))
// Output: {"foo":"bar","array":["baz",1],"message":"hello world"}
}
func ExampleContext_Array_object() {
// Users implements LogArrayMarshaler
u := Users{
User{"John", 35, time.Time{}},
User{"Bob", 55, time.Time{}},
}
dst := bytes.Buffer{}
log := New(&dst).With().
Str("foo", "bar").
Array("users", u).
Logger()
log.Log().Msg("hello world")
fmt.Println(decodeIfBinaryToString(dst.Bytes()))
// Output: {"foo":"bar","users":[{"name":"John","age":35,"created":"0001-01-01T00:00:00Z"},{"name":"Bob","age":55,"created":"0001-01-01T00:00:00Z"}],"message":"hello world"}
}
type Price struct {
val uint64
prec int
unit string
}
func (p Price) MarshalZerologObject(e *Event) {
denom := uint64(1)
for i := 0; i < p.prec; i++ {
denom *= 10
}
result := []byte(p.unit)
result = append(result, fmt.Sprintf("%d.%d", p.val/denom, p.val%denom)...)
e.Str("price", string(result))
}
func ExampleContext_EmbedObject() {
price := Price{val: 6449, prec: 2, unit: "$"}
dst := bytes.Buffer{}
log := New(&dst).With().
Str("foo", "bar").
EmbedObject(price).
Logger()
log.Log().Msg("hello world")
fmt.Println(decodeIfBinaryToString(dst.Bytes()))
// Output: {"foo":"bar","price":"$64.49","message":"hello world"}
}
func ExampleContext_Object() {
// User implements LogObjectMarshaler
u := User{"John", 35, time.Time{}}
dst := bytes.Buffer{}
log := New(&dst).With().
Str("foo", "bar").
Object("user", u).
Logger()
log.Log().Msg("hello world")
fmt.Println(decodeIfBinaryToString(dst.Bytes()))
// Output: {"foo":"bar","user":{"name":"John","age":35,"created":"0001-01-01T00:00:00Z"},"message":"hello world"}
}
func ExampleContext_Interface() {
obj := struct {
Name string `json:"name"`
}{
Name: "john",
}
dst := bytes.Buffer{}
log := New(&dst).With().
Str("foo", "bar").
Interface("obj", obj).
Logger()
log.Log().Msg("hello world")
fmt.Println(decodeIfBinaryToString(dst.Bytes()))
// Output: {"foo":"bar","obj":{"name":"john"},"message":"hello world"}
}
func ExampleContext_Dur() {
d := time.Duration(10 * time.Second)
dst := bytes.Buffer{}
log := New(&dst).With().
Str("foo", "bar").
Dur("dur", d).
Logger()
log.Log().Msg("hello world")
fmt.Println(decodeIfBinaryToString(dst.Bytes()))
// Output: {"foo":"bar","dur":10000,"message":"hello world"}
}
func ExampleContext_Durs() {
d := []time.Duration{
time.Duration(10 * time.Second),
time.Duration(20 * time.Second),
}
dst := bytes.Buffer{}
log := New(&dst).With().
Str("foo", "bar").
Durs("durs", d).
Logger()
log.Log().Msg("hello world")
fmt.Println(decodeIfBinaryToString(dst.Bytes()))
// Output: {"foo":"bar","durs":[10000,20000],"message":"hello world"}
}
func ExampleContext_Fields_map() {
fields := map[string]interface{}{
"bar": "baz",
"n": 1,
}
dst := bytes.Buffer{}
log := New(&dst).With().
Str("foo", "bar").
Fields(fields).
Logger()
log.Log().Msg("hello world")
fmt.Println(decodeIfBinaryToString(dst.Bytes()))
// Output: {"foo":"bar","bar":"baz","n":1,"message":"hello world"}
}
func ExampleContext_Fields_slice() {
fields := []interface{}{
"bar", "baz",
"n", 1,
}
dst := bytes.Buffer{}
log := New(&dst).With().
Str("foo", "bar").
Fields(fields).
Logger()
log.Log().Msg("hello world")
fmt.Println(decodeIfBinaryToString(dst.Bytes()))
// Output: {"foo":"bar","bar":"baz","n":1,"message":"hello world"}
}
func ExampleContext_IPAddr() {
ipV4 := net.IP{192, 168, 0, 1}
ipV6 := net.IP{0x20, 0x01, 0x0d, 0xb8, 0x85, 0xa3, 0x00, 0x00, 0x00, 0x00, 0x8a, 0x2e, 0x03, 0x70, 0x73, 0x34}
dst := bytes.Buffer{}
log := New(&dst).With().
Str("foo", "bar").
IPAddr("v4", ipV4).
IPAddr("v6", ipV6).
Logger()
log.Log().Msg("hello world")
fmt.Println(decodeIfBinaryToString(dst.Bytes()))
// Output: {"foo":"bar","v4":"192.168.0.1","v6":"2001:db8:85a3::8a2e:370:7334","message":"hello world"}
}
func ExampleContext_IPPrefix() {
pfxV4 := net.IPNet{IP: net.IP{192, 168, 0, 100}, Mask: net.CIDRMask(24, 32)}
pfxV6 := net.IPNet{IP: net.IP{0x20, 0x01, 0x0d, 0xb8, 0x85, 0xa3, 0x00, 0x00, 0x00, 0x00, 0x8a, 0x2e, 0x03, 0x70, 0x73, 0x00}, Mask: net.CIDRMask(64, 128)}
dst := bytes.Buffer{}
log := New(&dst).With().
Str("foo", "bar").
IPPrefix("v4", pfxV4).
IPPrefix("v6", pfxV6).
Logger()
log.Log().Msg("hello world")
fmt.Println(decodeIfBinaryToString(dst.Bytes()))
// Output: {"foo":"bar","v4":"192.168.0.100/24","v6":"2001:db8:85a3::8a2e:370:7300/64","message":"hello world"}
}
func ExampleContext_MACAddr() {
mac := net.HardwareAddr{0x12, 0x34, 0x56, 0x78, 0x90, 0xab}
dst := bytes.Buffer{}
log := New(&dst).With().
Str("foo", "bar").
MACAddr("mac", mac).
Logger()
log.Log().Msg("hello world")
fmt.Println(decodeIfBinaryToString(dst.Bytes()))
// Output: {"foo":"bar","mac":"12:34:56:78:90:ab","message":"hello world"}
}
================================================
FILE: cmd/lint/README.md
================================================
# Zerolog Lint
**DEPRECATED: In favor of https://github.com/ykadowak/zerologlint which is integrated with `go vet` and [golangci-lint](https://golangci-lint.run/).**
This is a basic linter that checks for missing log event finishers. Finds errors like: `log.Error().Int64("userID": 5)` - missing the `Msg`/`Msgf` finishers.
## Problem
When using zerolog it's easy to forget to finish the log event chain by calling a finisher - the `Msg` or `Msgf` function that will schedule the event for writing. The problem with this is that it doesn't warn/panic during compilation and it's not easily found by grep or other general tools. It's even prominently mentioned in the project's readme, that:
> 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.
## Solution
A basic linter like this one here that looks for method invocations on `zerolog.Event` can examine the last call in a method call chain and check if it is a finisher, thus pointing out these errors.
## Usage
Just compile this and then run it. Or just run it via `go run` command via something like `go run cmd/lint/lint.go`.
The command accepts only one argument - the package to be inspected - and 4 optional flags, all of which can occur multiple times. The standard synopsis of the command is:
`lint [-finisher value] [-ignoreFile value] [-ignorePkg value] [-ignorePkgRecursively value] package`
#### Flags
- finisher
- specify which finishers to accept, defaults to `Msg` and `Msgf`
- ignoreFile
- which files to ignore, either by full path or by go path (package/file.go)
- ignorePkg
- do not inspect the specified package if found in the dependency tree
- ignorePkgRecursively
- do not inspect the specified package or its subpackages if found in the dependency tree
## Drawbacks
As it is, linter can generate a false positives in a specific case. These false positives come from the fact that if you have a method that returns a `zerolog.Event` the linter will flag it because you are obviously not finishing the event. This will be solved in later release.
================================================
FILE: cmd/lint/go.mod
================================================
module github.com/rs/zerolog/cmd/lint
go 1.15
require golang.org/x/tools v0.1.8
================================================
FILE: cmd/lint/go.sum
================================================
github.com/yuin/goldmark v1.4.1/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/mod v0.5.1 h1:OJxoQ/rynoF0dcCdI7cLPktw/hR2cueqYfjm43oqK38=
golang.org/x/mod v0.5.1/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20211019181941-9d821ace8654 h1:id054HUawV2/6IGm2IV8KZQjqtwAOo2CYlOToYqa0d0=
golang.org/x/sys v0.0.0-20211019181941-9d821ace8654/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.1.8 h1:P1HhGGuLW4aAclzjtmJdf0mJOjVUZUzOTqkAkWL+l6w=
golang.org/x/tools v0.1.8/go.mod h1:nABZi5QlRsZVlzPpHl034qft6wpY4eDcsTt5AaioBiU=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
================================================
FILE: cmd/lint/lint.go
================================================
package main
import (
"flag"
"fmt"
"go/ast"
"go/token"
"go/types"
"os"
"path/filepath"
"strings"
"golang.org/x/tools/go/loader"
)
var (
recursivelyIgnoredPkgs arrayFlag
ignoredPkgs arrayFlag
ignoredFiles arrayFlag
allowedFinishers arrayFlag = []string{"Msg", "Msgf"}
rootPkg string
)
// parse input flags and args
func init() {
flag.Var(&recursivelyIgnoredPkgs, "ignorePkgRecursively", "ignore the specified package and all subpackages recursively")
flag.Var(&ignoredPkgs, "ignorePkg", "ignore the specified package")
flag.Var(&ignoredFiles, "ignoreFile", "ignore the specified file by its path and/or go path (package/file.go)")
flag.Var(&allowedFinishers, "finisher", "allowed finisher for the event chain")
flag.Parse()
// add zerolog to recursively ignored packages
recursivelyIgnoredPkgs = append(recursivelyIgnoredPkgs, "github.com/rs/zerolog")
args := flag.Args()
if len(args) != 1 {
fmt.Fprintln(os.Stderr, "you must provide exactly one package path")
os.Exit(1)
}
rootPkg = args[0]
}
func main() {
// load the package and all its dependencies
conf := loader.Config{}
conf.Import(rootPkg)
p, err := conf.Load()
if err != nil {
fmt.Fprintf(os.Stderr, "Error: unable to load the root package. %s\n", err.Error())
os.Exit(1)
}
// get the github.com/rs/zerolog.Event type
event := getEvent(p)
if event == nil {
fmt.Fprintln(os.Stderr, "Error: github.com/rs/zerolog.Event declaration not found, maybe zerolog is not imported in the scanned package?")
os.Exit(1)
}
// get all selections (function calls) with the github.com/rs/zerolog.Event (or pointer) receiver
selections := getSelectionsWithReceiverType(p, event)
// print the violations (if any)
hasViolations := false
for _, s := range selections {
if hasBadFinisher(p, s) {
hasViolations = true
fmt.Printf("Error: missing or bad finisher for log chain, last call: %q at: %s:%v\n", s.fn.Name(), p.Fset.File(s.Pos()).Name(), p.Fset.Position(s.Pos()).Line)
}
}
// if no violations detected, return normally
if !hasViolations {
fmt.Println("No violations found")
return
}
// if violations were detected, return error code
os.Exit(1)
}
func getEvent(p *loader.Program) types.Type {
for _, pkg := range p.AllPackages {
if strings.HasSuffix(pkg.Pkg.Path(), "github.com/rs/zerolog") {
for _, d := range pkg.Defs {
if d != nil && d.Name() == "Event" {
return d.Type()
}
}
}
}
return nil
}
func getSelectionsWithReceiverType(p *loader.Program, targetType types.Type) map[token.Pos]selection {
selections := map[token.Pos]selection{}
for _, z := range p.AllPackages {
for i, t := range z.Selections {
switch o := t.Obj().(type) {
case *types.Func:
// this is not a bug, o.Type() is always *types.Signature, see docs
if vt := o.Type().(*types.Signature).Recv(); vt != nil {
typ := vt.Type()
if pointer, ok := typ.(*types.Pointer); ok {
typ = pointer.Elem()
}
if typ == targetType {
if s, ok := selections[i.Pos()]; !ok || i.End() > s.End() {
selections[i.Pos()] = selection{i, o, z.Pkg}
}
}
}
default:
// skip
}
}
}
return selections
}
func hasBadFinisher(p *loader.Program, s selection) bool {
pkgPath := strings.TrimPrefix(s.pkg.Path(), rootPkg+"/vendor/")
absoluteFilePath := strings.TrimPrefix(p.Fset.File(s.Pos()).Name(), rootPkg+"/vendor/")
goFilePath := pkgPath + "/" + filepath.Base(p.Fset.Position(s.Pos()).Filename)
for _, f := range allowedFinishers {
if f == s.fn.Name() {
return false
}
}
for _, ignoredPkg := range recursivelyIgnoredPkgs {
if strings.HasPrefix(pkgPath, ignoredPkg) {
return false
}
}
for _, ignoredPkg := range ignoredPkgs {
if pkgPath == ignoredPkg {
return false
}
}
for _, ignoredFile := range ignoredFiles {
if absoluteFilePath == ignoredFile {
return false
}
if goFilePath == ignoredFile {
return false
}
}
return true
}
type arrayFlag []string
func (i *arrayFlag) String() string {
return fmt.Sprintf("%v", []string(*i))
}
func (i *arrayFlag) Set(value string) error {
*i = append(*i, value)
return nil
}
type selection struct {
*ast.SelectorExpr
fn *types.Func
pkg *types.Package
}
================================================
FILE: cmd/prettylog/README.md
================================================
# Zerolog PrettyLog
This is a basic CLI utility that will colorize and pretty print your structured JSON logs.
## Usage
You can compile it or run it directly. The only issue is that by default Zerolog does not output to `stdout`
but rather to `stderr` so we must pipe `stderr` stream to this CLI tool.
### Linux
These commands will redirect `stderr` to our `prettylog` tool and `stdout` will remain unaffected.
1. Compiled version
```shell
some_program_with_zerolog 2> >(prettylog)
```
2. Run it directly with `go run`
```shell
some_program_with_zerolog 2> >(go run cmd/prettylog/prettylog.go)
```
### Windows
These commands will redirect `stderr` to `stdout` and then pipe it to our `prettylog` tool.
1. Compiled version
```shell
some_program_with_zerolog 2>&1 | prettylog
```
2. Run it directly with `go run`
```shell
some_program_with_zerolog 2>&1 | go run cmd/prettylog/prettylog.go
```
================================================
FILE: cmd/prettylog/prettylog.go
================================================
package main
import (
"bufio"
"errors"
"flag"
"fmt"
"io"
"os"
"time"
"github.com/rs/zerolog"
)
func isInputFromPipe() bool {
fileInfo, _ := os.Stdin.Stat()
return fileInfo.Mode()&os.ModeCharDevice == 0
}
func processInput(reader io.Reader, writer io.Writer) error {
scanner := bufio.NewScanner(reader)
for scanner.Scan() {
bytesToWrite := scanner.Bytes()
_, err := writer.Write(bytesToWrite)
if err != nil {
if errors.Is(err, io.EOF) {
break
}
fmt.Printf("%s\n", bytesToWrite)
}
}
return scanner.Err()
}
func main() {
timeFormats := map[string]string{
"default": time.Kitchen,
"full": time.RFC1123,
}
timeFormatFlag := flag.String(
"time-format",
"default",
"Time format, either 'default' or 'full'",
)
flag.Parse()
timeFormat, ok := timeFormats[*timeFormatFlag]
if !ok {
panic("Invalid time-format provided")
}
writer := zerolog.NewConsoleWriter()
writer.TimeFormat = timeFormat
if isInputFromPipe() {
_ = processInput(os.Stdin, writer)
} else if flag.NArg() >= 1 {
for _, filename := range flag.Args() {
// Scan each line from filename and write it into writer
reader, err := os.Open(filename)
if err != nil {
fmt.Printf("%s open: %v", filename, err)
os.Exit(1)
}
if err := processInput(reader, writer); err != nil {
fmt.Printf("%s scan: %v", filename, err)
os.Exit(1)
}
}
} else {
fmt.Println("Usage:")
fmt.Println(" app_with_zerolog | 2> >(prettylog)")
fmt.Println(" prettylog zerolog_output.jsonl")
os.Exit(1)
return
}
}
================================================
FILE: console.go
================================================
package zerolog
import (
"bytes"
"encoding/json"
"fmt"
"io"
"os"
"path/filepath"
"sort"
"strconv"
"strings"
"sync"
"time"
"github.com/mattn/go-colorable"
)
const (
colorBlack = iota + 30
colorRed
colorGreen
colorYellow
colorBlue
colorMagenta
colorCyan
colorWhite
colorBold = 1
colorDarkGray = 90
unknownLevel = "???"
)
var (
consoleBufPool = sync.Pool{
New: func() interface{} {
return bytes.NewBuffer(make([]byte, 0, 100))
},
}
)
const (
consoleDefaultTimeFormat = time.Kitchen
)
// Formatter transforms the input into a formatted string.
type Formatter func(interface{}) string
// FormatterByFieldName transforms the input into a formatted string,
// being able to differentiate formatting based on field name.
type FormatterByFieldName func(interface{}, string) string
// ConsoleWriter parses the JSON input and writes it in an
// (optionally) colorized, human-friendly format to Out.
type ConsoleWriter struct {
// Out is the output destination.
Out io.Writer
// NoColor disables the colorized output.
NoColor bool
// TimeFormat specifies the format for timestamp in output.
TimeFormat string
// TimeLocation tells ConsoleWriter’s default FormatTimestamp
// how to localize the time.
TimeLocation *time.Location
// PartsOrder defines the order of parts in output.
PartsOrder []string
// PartsExclude defines parts to not display in output.
PartsExclude []string
// FieldsOrder defines the order of contextual fields in output.
FieldsOrder []string
fieldIsOrdered map[string]int
// FieldsExclude defines contextual fields to not display in output.
FieldsExclude []string
FormatTimestamp Formatter
FormatLevel Formatter
FormatCaller Formatter
FormatMessage Formatter
FormatFieldName Formatter
FormatFieldValue Formatter
FormatErrFieldName Formatter
FormatErrFieldValue Formatter
// If this is configured it is used for "part" values and
// has precedence on FormatFieldValue
FormatPartValueByName FormatterByFieldName
FormatExtra func(map[string]interface{}, *bytes.Buffer) error
FormatPrepare func(map[string]interface{}) error
}
// NewConsoleWriter creates and initializes a new ConsoleWriter.
func NewConsoleWriter(options ...func(w *ConsoleWriter)) ConsoleWriter {
w := ConsoleWriter{
Out: os.Stdout,
TimeFormat: consoleDefaultTimeFormat,
PartsOrder: consoleDefaultPartsOrder(),
}
for _, opt := range options {
opt(&w)
}
// Fix color on Windows
if w.Out == os.Stdout || w.Out == os.Stderr {
w.Out = colorable.NewColorable(w.Out.(*os.File))
}
return w
}
// Write transforms the JSON input with formatters and appends to w.Out.
func (w ConsoleWriter) Write(p []byte) (n int, err error) {
// Fix color on Windows
if w.Out == os.Stdout || w.Out == os.Stderr {
w.Out = colorable.NewColorable(w.Out.(*os.File))
}
if w.PartsOrder == nil {
w.PartsOrder = consoleDefaultPartsOrder()
}
var buf = consoleBufPool.Get().(*bytes.Buffer)
defer func() {
buf.Reset()
consoleBufPool.Put(buf)
}()
var evt map[string]interface{}
p = decodeIfBinaryToBytes(p)
d := json.NewDecoder(bytes.NewReader(p))
d.UseNumber()
err = d.Decode(&evt)
if err != nil {
return n, fmt.Errorf("cannot decode event: %s", err)
}
if w.FormatPrepare != nil {
err = w.FormatPrepare(evt)
if err != nil {
return n, err
}
}
for _, p := range w.PartsOrder {
w.writePart(buf, evt, p)
}
w.writeFields(evt, buf)
if w.FormatExtra != nil {
err = w.FormatExtra(evt, buf)
if err != nil {
return n, err
}
}
err = buf.WriteByte('\n')
if err != nil {
return n, err
}
_, err = buf.WriteTo(w.Out)
return len(p), err
}
// Call the underlying writer's Close method if it is an io.Closer. Otherwise
// does nothing.
func (w ConsoleWriter) Close() error {
if closer, ok := w.Out.(io.Closer); ok {
return closer.Close()
}
return nil
}
// writeFields appends formatted key-value pairs to buf.
func (w ConsoleWriter) writeFields(evt map[string]interface{}, buf *bytes.Buffer) {
var fields = make([]string, 0, len(evt))
for field := range evt {
var isExcluded bool
for _, excluded := range w.FieldsExclude {
if field == excluded {
isExcluded = true
break
}
}
if isExcluded {
continue
}
switch field {
case LevelFieldName, TimestampFieldName, MessageFieldName, CallerFieldName:
continue
}
fields = append(fields, field)
}
if len(w.FieldsOrder) > 0 {
w.orderFields(fields)
} else {
sort.Strings(fields)
}
// Write space only if something has already been written to the buffer, and if there are fields.
if buf.Len() > 0 && len(fields) > 0 {
buf.WriteByte(' ')
}
// Move the "error" field to the front
ei := sort.Search(len(fields), func(i int) bool { return fields[i] >= ErrorFieldName })
if ei < len(fields) && fields[ei] == ErrorFieldName {
fields[ei] = ""
fields = append([]string{ErrorFieldName}, fields...)
var xfields = make([]string, 0, len(fields))
for _, field := range fields {
if field == "" { // Skip empty fields
continue
}
xfields = append(xfields, field)
}
fields = xfields
}
for i, field := range fields {
var fn Formatter
var fv Formatter
if field == ErrorFieldName {
if w.FormatErrFieldName == nil {
fn = consoleDefaultFormatErrFieldName(w.NoColor)
} else {
fn = w.FormatErrFieldName
}
if w.FormatErrFieldValue == nil {
fv = consoleDefaultFormatErrFieldValue(w.NoColor)
} else {
fv = w.FormatErrFieldValue
}
} else {
if w.FormatFieldName == nil {
fn = consoleDefaultFormatFieldName(w.NoColor)
} else {
fn = w.FormatFieldName
}
if w.FormatFieldValue == nil {
fv = consoleDefaultFormatFieldValue
} else {
fv = w.FormatFieldValue
}
}
buf.WriteString(fn(field))
switch fValue := evt[field].(type) {
case string:
if needsQuote(fValue) {
buf.WriteString(fv(strconv.Quote(fValue)))
} else {
buf.WriteString(fv(fValue))
}
case json.Number:
buf.WriteString(fv(fValue))
default:
b, err := InterfaceMarshalFunc(fValue)
if err != nil {
fmt.Fprintf(buf, colorize("[error: %v]", colorRed, w.NoColor), err)
} else {
fmt.Fprint(buf, fv(b))
}
}
if i < len(fields)-1 { // Skip space for last field
buf.WriteByte(' ')
}
}
}
// writePart appends a formatted part to buf.
func (w ConsoleWriter) writePart(buf *bytes.Buffer, evt map[string]interface{}, p string) {
var f Formatter
var fvn FormatterByFieldName
if len(w.PartsExclude) > 0 {
for _, exclude := range w.PartsExclude {
if exclude == p {
return
}
}
}
switch p {
case LevelFieldName:
if w.FormatLevel == nil {
f = consoleDefaultFormatLevel(w.NoColor)
} else {
f = w.FormatLevel
}
case TimestampFieldName:
if w.FormatTimestamp == nil {
f = consoleDefaultFormatTimestamp(w.TimeFormat, w.TimeLocation, w.NoColor)
} else {
f = w.FormatTimestamp
}
case MessageFieldName:
if w.FormatMessage == nil {
f = consoleDefaultFormatMessage(w.NoColor, evt[LevelFieldName])
} else {
f = w.FormatMessage
}
case CallerFieldName:
if w.FormatCaller == nil {
f = consoleDefaultFormatCaller(w.NoColor)
} else {
f = w.FormatCaller
}
default:
if w.FormatPartValueByName != nil {
fvn = w.FormatPartValueByName
} else if w.FormatFieldValue != nil {
f = w.FormatFieldValue
} else {
f = consoleDefaultFormatFieldValue
}
}
var s string
if f == nil {
s = fvn(evt[p], p)
} else {
s = f(evt[p])
}
if len(s) > 0 {
if buf.Len() > 0 {
buf.WriteByte(' ') // Write space only if not the first part
}
buf.WriteString(s)
}
}
// orderFields takes an array of field names and an array representing field order
// and returns an array with any ordered fields at the beginning, in order,
// and the remaining fields after in their original order.
func (w ConsoleWriter) orderFields(fields []string) {
if w.fieldIsOrdered == nil {
w.fieldIsOrdered = make(map[string]int)
for i, fieldName := range w.FieldsOrder {
w.fieldIsOrdered[fieldName] = i
}
}
sort.Slice(fields, func(i, j int) bool {
ii, iOrdered := w.fieldIsOrdered[fields[i]]
jj, jOrdered := w.fieldIsOrdered[fields[j]]
if iOrdered && jOrdered {
return ii < jj
}
if iOrdered {
return true
}
if jOrdered {
return false
}
return fields[i] < fields[j]
})
}
// needsQuote returns true when the string s should be quoted in output.
func needsQuote(s string) bool {
for i := range s {
if s[i] < 0x20 || s[i] > 0x7e || s[i] == ' ' || s[i] == '\\' || s[i] == '"' {
return true
}
}
return false
}
// colorize returns the string s wrapped in ANSI code c, unless disabled is true or c is 0.
func colorize(s interface{}, c int, disabled bool) string {
e := os.Getenv("NO_COLOR")
if e != "" || c == 0 {
disabled = true
}
if disabled {
return fmt.Sprintf("%s", s)
}
return fmt.Sprintf("\x1b[%dm%v\x1b[0m", c, s)
}
// ----- DEFAULT FORMATTERS ---------------------------------------------------
func consoleDefaultPartsOrder() []string {
return []string{
TimestampFieldName,
LevelFieldName,
CallerFieldName,
MessageFieldName,
}
}
func consoleDefaultFormatTimestamp(timeFormat string, location *time.Location, noColor bool) Formatter {
if timeFormat == "" {
timeFormat = consoleDefaultTimeFormat
}
if location == nil {
location = time.Local
}
return func(i interface{}) string {
t := "<nil>"
switch tt := i.(type) {
case string:
ts, err := time.ParseInLocation(TimeFieldFormat, tt, location)
if err != nil {
t = tt
} else {
t = ts.In(location).Format(timeFormat)
}
case json.Number:
i, err := tt.Int64()
if err != nil {
t = tt.String()
} else {
var sec, nsec int64
switch TimeFieldFormat {
case TimeFormatUnixNano:
sec, nsec = 0, i
case TimeFormatUnixMicro:
sec, nsec = 0, int64(time.Duration(i)*time.Microsecond)
case TimeFormatUnixMs:
sec, nsec = 0, int64(time.Duration(i)*time.Millisecond)
default:
sec, nsec = i, 0
}
ts := time.Unix(sec, nsec)
t = ts.In(location).Format(timeFormat)
}
}
return colorize(t, colorDarkGray, noColor)
}
}
func stripLevel(ll string) string {
if len(ll) == 0 {
return unknownLevel
}
if len(ll) > 3 {
ll = ll[:3]
}
return strings.ToUpper(ll)
}
func consoleDefaultFormatLevel(noColor bool) Formatter {
return func(i interface{}) string {
if ll, ok := i.(string); ok {
level, _ := ParseLevel(ll)
fl, ok := FormattedLevels[level]
if ok {
return colorize(fl, LevelColors[level], noColor)
}
return stripLevel(ll)
}
if i == nil {
return unknownLevel
}
return stripLevel(fmt.Sprintf("%s", i))
}
}
func consoleDefaultFormatCaller(noColor bool) Formatter {
return func(i interface{}) string {
var c string
if cc, ok := i.(string); ok {
c = cc
}
if len(c) > 0 {
if cwd, err := os.Getwd(); err == nil {
if rel, err := filepath.Rel(cwd, c); err == nil {
c = rel
}
}
c = colorize(c, colorBold, noColor) + colorize(" >", colorCyan, noColor)
}
return c
}
}
func consoleDefaultFormatMessage(noColor bool, level interface{}) Formatter {
return func(i interface{}) string {
if i == nil || i == "" {
return ""
}
switch level {
case LevelInfoValue, LevelWarnValue, LevelErrorValue, LevelFatalValue, LevelPanicValue:
return colorize(fmt.Sprintf("%s", i), colorBold, noColor)
default:
return fmt.Sprintf("%s", i)
}
}
}
func consoleDefaultFormatFieldName(noColor bool) Formatter {
return func(i interface{}) string {
return colorize(fmt.Sprintf("%s=", i), colorCyan, noColor)
}
}
func consoleDefaultFormatFieldValue(i interface{}) string {
return fmt.Sprintf("%s", i)
}
func consoleDefaultFormatErrFieldName(noColor bool) Formatter {
return func(i interface{}) string {
return colorize(fmt.Sprintf("%s=", i), colorCyan, noColor)
}
}
func consoleDefaultFormatErrFieldValue(noColor bool) Formatter {
return func(i interface{}) string {
return colorize(colorize(fmt.Sprintf("%s", i), colorBold, noColor), colorRed, noColor)
}
}
================================================
FILE: console_test.go
================================================
package zerolog_test
import (
"bytes"
"encoding/json"
"fmt"
"io"
"os"
"path/filepath"
"strings"
"testing"
"time"
"github.com/rs/zerolog"
)
func ExampleConsoleWriter() {
log := zerolog.New(zerolog.ConsoleWriter{Out: os.Stdout, NoColor: true})
log.Info().Str("foo", "bar").Msg("Hello World")
// Output: <nil> INF Hello World foo=bar
}
func ExampleConsoleWriter_customFormatters() {
out := zerolog.ConsoleWriter{Out: os.Stdout, NoColor: true}
out.FormatLevel = func(i interface{}) string { return strings.ToUpper(fmt.Sprintf("%-6s|", i)) }
out.FormatFieldName = func(i interface{}) string { return fmt.Sprintf("%s:", i) }
out.FormatFieldValue = func(i interface{}) string { return strings.ToUpper(fmt.Sprintf("%s", i)) }
log := zerolog.New(out)
log.Info().Str("foo", "bar").Msg("Hello World")
// Output: <nil> INFO | Hello World foo:BAR
}
func ExampleConsoleWriter_partValueFormatter() {
out := zerolog.ConsoleWriter{Out: os.Stdout, NoColor: true,
PartsOrder: []string{"level", "one", "two", "three", "message"},
FieldsExclude: []string{"one", "two", "three"}}
out.FormatLevel = func(i interface{}) string { return strings.ToUpper(fmt.Sprintf("%-6s", i)) }
out.FormatFieldName = func(i interface{}) string { return fmt.Sprintf("%s:", i) }
out.FormatPartValueByName = func(i interface{}, s string) string {
var ret string
switch s {
case "one":
ret = strings.ToUpper(fmt.Sprintf("%s", i))
case "two":
ret = strings.ToLower(fmt.Sprintf("%s", i))
case "three":
ret = strings.ToLower(fmt.Sprintf("(%s)", i))
}
return ret
}
log := zerolog.New(out)
log.Info().Str("foo", "bar").
Str("two", "TEST_TWO").
Str("one", "test_one").
Str("three", "test_three").
Msg("Hello World")
// Output: INFO TEST_ONE test_two (test_three) Hello World foo:bar
}
func ExampleNewConsoleWriter() {
out := zerolog.NewConsoleWriter()
out.NoColor = true // For testing purposes only
log := zerolog.New(out)
log.Debug().Str("foo", "bar").Msg("Hello World")
// Output: <nil> DBG Hello World foo=bar
}
func ExampleNewConsoleWriter_customFormatters() {
out := zerolog.NewConsoleWriter(
func(w *zerolog.ConsoleWriter) {
// Customize time format
w.TimeFormat = time.RFC822
// Customize level formatting
w.FormatLevel = func(i interface{}) string { return strings.ToUpper(fmt.Sprintf("[%-5s]", i)) }
},
)
out.NoColor = true // For testing purposes only
log := zerolog.New(out)
log.Info().Str("foo", "bar").Msg("Hello World")
// Output: <nil> [INFO ] Hello World foo=bar
}
func TestConsoleLogger(t *testing.T) {
t.Run("Numbers", func(t *testing.T) {
buf := &bytes.Buffer{}
log := zerolog.New(zerolog.ConsoleWriter{Out: buf, NoColor: true})
log.Info().
Float64("float", 1.23).
Uint64("small", 123).
Uint64("big", 1152921504606846976).
Msg("msg")
if got, want := strings.TrimSpace(buf.String()), "<nil> INF msg big=1152921504606846976 float=1.23 small=123"; got != want {
t.Errorf("\ngot:\n%s\nwant:\n%s", got, want)
}
})
}
func TestConsoleWriter(t *testing.T) {
t.Run("Default field formatter", func(t *testing.T) {
buf := &bytes.Buffer{}
w := zerolog.ConsoleWriter{Out: buf, NoColor: true, PartsOrder: []string{"foo"}}
_, err := w.Write([]byte(`{"foo": "DEFAULT"}`))
if err != nil {
t.Errorf("Unexpected error when writing output: %s", err)
}
expectedOutput := "DEFAULT foo=DEFAULT\n"
actualOutput := buf.String()
if actualOutput != expectedOutput {
t.Errorf("Unexpected output %q, want: %q", actualOutput, expectedOutput)
}
})
t.Run("Write colorized", func(t *testing.T) {
buf := &bytes.Buffer{}
w := zerolog.ConsoleWriter{Out: buf, NoColor: false}
_, err := w.Write([]byte(`{"level": "warn", "message": "Foobar"}`))
if err != nil {
t.Errorf("Unexpected error when writing output: %s", err)
}
expectedOutput := "\x1b[90m<nil>\x1b[0m \x1b[33mWRN\x1b[0m \x1b[1mFoobar\x1b[0m\n"
actualOutput := buf.String()
if actualOutput != expectedOutput {
t.Errorf("Unexpected output %q, want: %q", actualOutput, expectedOutput)
}
})
t.Run("NO_COLOR = true", func(t *testing.T) {
os.Setenv("NO_COLOR", "anything")
buf := &bytes.Buffer{}
w := zerolog.ConsoleWriter{Out: buf}
_, err := w.Write([]byte(`{"level": "warn", "message": "Foobar"}`))
if err != nil {
t.Errorf("Unexpected error when writing output: %s", err)
}
expectedOutput := "<nil> WRN Foobar\n"
actualOutput := buf.String()
if actualOutput != expectedOutput {
t.Errorf("Unexpected output %q, want: %q", actualOutput, expectedOutput)
}
os.Unsetenv("NO_COLOR")
})
t.Run("Write fields", func(t *testing.T) {
buf := &bytes.Buffer{}
w := zerolog.ConsoleWriter{Out: buf, NoColor: true}
ts := time.Unix(0, 0)
d := ts.UTC().Format(time.RFC3339)
_, err := w.Write([]byte(`{"time": "` + d + `", "level": "debug", "message": "Foobar", "foo": "bar"}`))
if err != nil {
t.Errorf("Unexpected error when writing output: %s", err)
}
expectedOutput := ts.Format(time.Kitchen) + " DBG Foobar foo=bar\n"
actualOutput := buf.String()
if actualOutput != expectedOutput {
t.Errorf("Unexpected output %q, want: %q", actualOutput, expectedOutput)
}
})
t.Run("Unix timestamp input format", func(t *testing.T) {
of := zerolog.TimeFieldFormat
defer func() {
zerolog.TimeFieldFormat = of
}()
zerolog.TimeFieldFormat = zerolog.TimeFormatUnix
buf := &bytes.Buffer{}
w := zerolog.ConsoleWriter{Out: buf, TimeFormat: time.StampMilli, NoColor: true}
_, err := w.Write([]byte(`{"time": 1234, "level": "debug", "message": "Foobar", "foo": "bar"}`))
if err != nil {
t.Errorf("Unexpected error when writing output: %s", err)
}
expectedOutput := time.Unix(1234, 0).Format(time.StampMilli) + " DBG Foobar foo=bar\n"
actualOutput := buf.String()
if actualOutput != expectedOutput {
t.Errorf("Unexpected output %q, want: %q", actualOutput, expectedOutput)
}
})
t.Run("Unix timestamp ms input format", func(t *testing.T) {
of := zerolog.TimeFieldFormat
defer func() {
zerolog.TimeFieldFormat = of
}()
zerolog.TimeFieldFormat = zerolog.TimeFormatUnixMs
buf := &bytes.Buffer{}
w := zerolog.ConsoleWriter{Out: buf, TimeFormat: time.StampMilli, NoColor: true}
_, err := w.Write([]byte(`{"time": 1234567, "level": "debug", "message": "Foobar", "foo": "bar"}`))
if err != nil {
t.Errorf("Unexpected error when writing output: %s", err)
}
expectedOutput := time.Unix(1234, 567000000).Format(time.StampMilli) + " DBG Foobar foo=bar\n"
actualOutput := buf.String()
if actualOutput != expectedOutput {
t.Errorf("Unexpected output %q, want: %q", actualOutput, expectedOutput)
}
})
t.Run("Unix timestamp us input format", func(t *testing.T) {
of := zerolog.TimeFieldFormat
defer func() {
zerolog.TimeFieldFormat = of
}()
zerolog.TimeFieldFormat = zerolog.TimeFormatUnixMicro
buf := &bytes.Buffer{}
w := zerolog.ConsoleWriter{Out: buf, TimeFormat: time.StampMicro, NoColor: true}
_, err := w.Write([]byte(`{"time": 1234567891, "level": "debug", "message": "Foobar", "foo": "bar"}`))
if err != nil {
t.Errorf("Unexpected error when writing output: %s", err)
}
expectedOutput := time.Unix(1234, 567891000).Format(time.StampMicro) + " DBG Foobar foo=bar\n"
actualOutput := buf.String()
if actualOutput != expectedOutput {
t.Errorf("Unexpected output %q, want: %q", actualOutput, expectedOutput)
}
})
t.Run("No message field", func(t *testing.T) {
buf := &bytes.Buffer{}
w := zerolog.ConsoleWriter{Out: buf, NoColor: true}
_, err := w.Write([]byte(`{"level": "debug", "foo": "bar"}`))
if err != nil {
t.Errorf("Unexpected error when writing output: %s", err)
}
expectedOutput := "<nil> DBG foo=bar\n"
actualOutput := buf.String()
if actualOutput != expectedOutput {
t.Errorf("Unexpected output %q, want: %q", actualOutput, expectedOutput)
}
})
t.Run("No level field", func(t *testing.T) {
buf := &bytes.Buffer{}
w := zerolog.ConsoleWriter{Out: buf, NoColor: true}
_, err := w.Write([]byte(`{"message": "Foobar", "foo": "bar"}`))
if err != nil {
t.Errorf("Unexpected error when writing output: %s", err)
}
expectedOutput := "<nil> ??? Foobar foo=bar\n"
actualOutput := buf.String()
if actualOutput != expectedOutput {
t.Errorf("Unexpected output %q, want: %q", actualOutput, expectedOutput)
}
})
t.Run("Write colorized fields", func(t *testing.T) {
buf := &bytes.Buffer{}
w := zerolog.ConsoleWriter{Out: buf, NoColor: false}
_, err := w.Write([]byte(`{"level": "warn", "message": "Foobar", "foo": "bar"}`))
if err != nil {
t.Errorf("Unexpected error when writing output: %s", err)
}
expectedOutput := "\x1b[90m<nil>\x1b[0m \x1b[33mWRN\x1b[0m \x1b[1mFoobar\x1b[0m \x1b[36mfoo=\x1b[0mbar\n"
actualOutput := buf.String()
if actualOutput != expectedOutput {
t.Errorf("Unexpected output %q, want: %q", actualOutput, expectedOutput)
}
})
t.Run("Write error field", func(t *testing.T) {
buf := &bytes.Buffer{}
w := zerolog.ConsoleWriter{Out: buf, NoColor: true}
ts := time.Unix(0, 0)
d := ts.UTC().Format(time.RFC3339)
evt := `{"time": "` + d + `", "level": "error", "message": "Foobar", "aaa": "bbb", "error": "Error"}`
// t.Log(evt)
_, err := w.Write([]byte(evt))
if err != nil {
t.Errorf("Unexpected error when writing output: %s", err)
}
expectedOutput := ts.Format(time.Kitchen) + " ERR Foobar error=Error aaa=bbb\n"
actualOutput := buf.String()
if actualOutput != expectedOutput {
t.Errorf("Unexpected output %q, want: %q", actualOutput, expectedOutput)
}
})
t.Run("Write caller field", func(t *testing.T) {
buf := &bytes.Buffer{}
w := zerolog.ConsoleWriter{Out: buf, NoColor: true}
cwd, err := os.Getwd()
if err != nil {
t.Fatalf("Cannot get working directory: %s", err)
}
ts := time.Unix(0, 0)
d := ts.UTC().Format(time.RFC3339)
fields := map[string]interface{}{
"time": d,
"level": "debug",
"message": "Foobar",
"foo": "bar",
"caller": filepath.Join(cwd, "foo", "bar.go"),
}
evt, err := json.Marshal(fields)
if err != nil {
t.Fatalf("Cannot marshal fields: %s", err)
}
_, err = w.Write(evt)
if err != nil {
t.Errorf("Unexpected error when writing output: %s", err)
}
// Define the expected output with forward slashes
expectedOutput := ts.Format(time.Kitchen) + " DBG foo/bar.go > Foobar foo=bar\n"
// Get the actual output and normalize path separators to forward slashes
actualOutput := buf.String()
actualOutput = strings.ReplaceAll(actualOutput, string(os.PathSeparator), "/")
// Compare the normalized actual output to the expected output
if actualOutput != expectedOutput {
t.Errorf("Unexpected output %q, want: %q", actualOutput, expectedOutput)
}
})
t.Run("Write JSON field", func(t *testing.T) {
buf := &bytes.Buffer{}
w := zerolog.ConsoleWriter{Out: buf, NoColor: true}
evt := `{"level": "debug", "message": "Foobar", "foo": [1, 2, 3], "bar": true}`
// t.Log(evt)
_, err := w.Write([]byte(evt))
if err != nil {
t.Errorf("Unexpected error when writing output: %s", err)
}
expectedOutput := "<nil> DBG Foobar bar=true foo=[1,2,3]\n"
actualOutput := buf.String()
if actualOutput != expectedOutput {
t.Errorf("Unexpected output %q, want: %q", actualOutput, expectedOutput)
}
})
t.Run("With an extra 'level' field", func(t *testing.T) {
t.Run("malformed string", func(t *testing.T) {
cases := []struct {
field string
output string
}{
{"", "<nil> ??? Hello World foo=bar\n"},
{"-", "<nil> - Hello World foo=bar\n"},
{"1", "<nil> " + zerolog.FormattedLevels[1] + " Hello World foo=bar\n"},
{"a", "<nil> A Hello World foo=bar\n"},
{"12", "<nil> 12 Hello World foo=bar\n"},
{"a2", "<nil> A2 Hello World foo=bar\n"},
{"2a", "<nil> 2A Hello World foo=bar\n"},
{"ab", "<nil> AB Hello World foo=bar\n"},
{"12a", "<nil> 12A Hello World foo=bar\n"},
{"a12", "<nil> A12 Hello World foo=bar\n"},
{"abc", "<nil> ABC Hello World foo=bar\n"},
{"123", "<nil> 123 Hello World foo=bar\n"},
{"abcd", "<nil> ABC Hello World foo=bar\n"},
{"1234", "<nil> 123 Hello World foo=bar\n"},
{"123d", "<nil> 123 Hello World foo=bar\n"},
{"01", "<nil> " + zerolog.FormattedLevels[1] + " Hello World foo=bar\n"},
{"001", "<nil> " + zerolog.FormattedLevels[1] + " Hello World foo=bar\n"},
{"0001", "<nil> " + zerolog.FormattedLevels[1] + " Hello World foo=bar\n"},
}
for i, c := range cases {
c := c
t.Run(fmt.Sprintf("case %d", i), func(t *testing.T) {
buf := &bytes.Buffer{}
out := zerolog.NewConsoleWriter()
out.NoColor = true
out.Out = buf
log := zerolog.New(out)
log.Debug().Str("level", c.field).Str("foo", "bar").Msg("Hello World")
actualOutput := buf.String()
if actualOutput != c.output {
t.Errorf("Unexpected output %q, want: %q", actualOutput, c.output)
}
})
}
})
t.Run("weird value", func(t *testing.T) {
cases := []struct {
field interface{}
output string
}{
{0, "<nil> 0 Hello World foo=bar\n"},
{1, "<nil> 1 Hello World foo=bar\n"},
{-1, "<nil> -1 Hello World foo=bar\n"},
{-3, "<nil> -3 Hello World foo=bar\n"},
{-32, "<nil> -32 Hello World foo=bar\n"},
{-321, "<nil> -32 Hello World foo=bar\n"},
{12, "<nil> 12 Hello World foo=bar\n"},
{123, "<nil> 123 Hello World foo=bar\n"},
{1234, "<nil> 123 Hello World foo=bar\n"},
}
for i, c := range cases {
c := c
t.Run(fmt.Sprintf("case %d", i), func(t *testing.T) {
buf := &bytes.Buffer{}
out := zerolog.NewConsoleWriter()
out.NoColor = true
out.Out = buf
log := zerolog.New(out)
log.Debug().Interface("level", c.field).Str("foo", "bar").Msg("Hello World")
actualOutput := buf.String()
if actualOutput != c.output {
t.Errorf("Unexpected output %q, want: %q", actualOutput, c.output)
}
})
}
})
})
}
func TestConsoleWriterConfiguration(t *testing.T) {
t.Run("Sets TimeFormat", func(t *testing.T) {
buf := &bytes.Buffer{}
w := zerolog.ConsoleWriter{Out: buf, NoColor: true, TimeFormat: time.RFC3339}
ts := time.Unix(0, 0)
d := ts.UTC().Format(time.RFC3339)
evt := `{"time": "` + d + `", "level": "info", "message": "Foobar"}`
_, err := w.Write([]byte(evt))
if err != nil {
t.Errorf("Unexpected error when writing output: %s", err)
}
expectedOutput := ts.Format(time.RFC3339) + " INF Foobar\n"
actualOutput := buf.String()
if actualOutput != expectedOutput {
t.Errorf("Unexpected output %q, want: %q", actualOutput, expectedOutput)
}
})
t.Run("Sets TimeFormat and TimeLocation", func(t *testing.T) {
locs := []*time.Location{time.Local, time.UTC}
for _, location := range locs {
buf := &bytes.Buffer{}
w := zerolog.ConsoleWriter{
Out: buf,
NoColor: true,
TimeFormat: time.RFC3339,
TimeLocation: location,
}
ts := time.Unix(0, 0)
d := ts.UTC().Format(time.RFC3339)
evt := `{"time": "` + d + `", "level": "info", "message": "Foobar"}`
_, err := w.Write([]byte(evt))
if err != nil {
t.Errorf("Unexpected error when writing output: %s", err)
}
expectedOutput := ts.In(location).Format(time.RFC3339) + " INF Foobar\n"
actualOutput := buf.String()
if actualOutput != expectedOutput {
t.Errorf("Unexpected output %q, want: %q (location=%s)", actualOutput, expectedOutput, location)
}
}
})
t.Run("Sets PartsOrder", func(t *testing.T) {
buf := &bytes.Buffer{}
w := zerolog.ConsoleWriter{Out: buf, NoColor: true, PartsOrder: []string{"message", "level"}}
evt := `{"level": "info", "message": "Foobar"}`
_, err := w.Write([]byte(evt))
if err != nil {
t.Errorf("Unexpected error when writing output: %s", err)
}
expectedOutput := "Foobar INF\n"
actualOutput := buf.String()
if actualOutput != expectedOutput {
t.Errorf("Unexpected output %q, want: %q", actualOutput, expectedOutput)
}
})
t.Run("Sets PartsExclude", func(t *testing.T) {
buf := &bytes.Buffer{}
w := zerolog.ConsoleWriter{Out: buf, NoColor: true, PartsExclude: []string{"time"}}
d := time.Unix(0, 0).UTC().Format(time.RFC3339)
evt := `{"time": "` + d + `", "level": "info", "message": "Foobar"}`
_, err := w.Write([]byte(evt))
if err != nil {
t.Errorf("Unexpected error when writing output: %s", err)
}
expectedOutput := "INF Foobar\n"
actualOutput := buf.String()
if actualOutput != expectedOutput {
t.Errorf("Unexpected output %q, want: %q", actualOutput, expectedOutput)
}
})
t.Run("Sets FieldsOrder", func(t *testing.T) {
buf := &bytes.Buffer{}
w := zerolog.ConsoleWriter{Out: buf, NoColor: true, FieldsOrder: []string{"zebra", "aardvark"}}
evt := `{"level": "info", "message": "Zoo", "aardvark": "Able", "mussel": "Mountain", "zebra": "Zulu"}`
_, err := w.Write([]byte(evt))
if err != nil {
t.Errorf("Unexpected error when writing output: %s", err)
}
expectedOutput := "<nil> INF Zoo zebra=Zulu aardvark=Able mussel=Mountain\n"
actualOutput := buf.String()
if actualOutput != expectedOutput {
t.Errorf("Unexpected output %q, want: %q", actualOutput, expectedOutput)
}
})
t.Run("Sets FieldsExclude", func(t *testing.T) {
buf := &bytes.Buffer{}
w := zerolog.ConsoleWriter{Out: buf, NoColor: true, FieldsExclude: []string{"foo"}}
evt := `{"level": "info", "message": "Foobar", "foo":"bar", "baz":"quux"}`
_, err := w.Write([]byte(evt))
if err != nil {
t.Errorf("Unexpected error when writing output: %s", err)
}
expectedOutput := "<nil> INF Foobar baz=quux\n"
actualOutput := buf.String()
if actualOutput != expectedOutput {
t.Errorf("Unexpected output %q, want: %q", actualOutput, expectedOutput)
}
})
t.Run("Sets FormatExtra", func(t *testing.T) {
buf := &bytes.Buffer{}
w := zerolog.ConsoleWriter{
Out: buf, NoColor: true, PartsOrder: []string{"level", "message"},
FormatExtra: func(evt map[string]interface{}, buf *bytes.Buffer) error {
buf.WriteString("\nAdditional stacktrace")
return nil
},
}
evt := `{"level": "info", "message": "Foobar"}`
_, err := w.Write([]byte(evt))
if err != nil {
t.Errorf("Unexpected error when writing output: %s", err)
}
expectedOutput := "INF Foobar\nAdditional stacktrace\n"
actualOutput := buf.String()
if actualOutput != expectedOutput {
t.Errorf("Unexpected output %q, want: %q", actualOutput, expectedOutput)
}
})
t.Run("Sets FormatPrepare", func(t *testing.T) {
buf := &bytes.Buffer{}
w := zerolog.ConsoleWriter{
Out: buf, NoColor: true, PartsOrder: []string{"level", "message"},
FormatPrepare: func(evt map[string]interface{}) error {
evt["message"] = fmt.Sprintf("msg=%s", evt["message"])
return nil
},
}
evt := `{"level": "info", "message": "Foobar"}`
_, err := w.Write([]byte(evt))
if err != nil {
t.Errorf("Unexpected error when writing output: %s", err)
}
expectedOutput := "INF msg=Foobar\n"
actualOutput := buf.String()
if actualOutput != expectedOutput {
t.Errorf("Unexpected output %q, want: %q", actualOutput, expectedOutput)
}
})
t.Run("Uses local time for console writer without time zone", func(t *testing.T) {
// Regression test for issue #483 (check there for more details)
timeFormat := "2006-01-02 15:04:05"
expectedOutput := "2022-10-20 20:24:50 INF Foobar\n"
evt := `{"time": "2022-10-20 20:24:50", "level": "info", "message": "Foobar"}`
of := zerolog.TimeFieldFormat
defer func() {
zerolog.TimeFieldFormat = of
}()
zerolog.TimeFieldFormat = timeFormat
buf := &bytes.Buffer{}
w := zerolog.ConsoleWriter{Out: buf, NoColor: true, TimeFormat: timeFormat}
_, err := w.Write([]byte(evt))
if err != nil {
t.Errorf("Unexpected error when writing output: %s", err)
}
actualOutput := buf.String()
if actualOutput != expectedOutput {
t.Errorf("Unexpected output %q, want: %q", actualOutput, expectedOutput)
}
})
}
func BenchmarkConsoleWriter(b *testing.B) {
b.ResetTimer()
b.ReportAllocs()
var msg = []byte(`{"level": "info", "foo": "bar", "message": "HELLO", "time": "1990-01-01"}`)
w := zerolog.ConsoleWriter{Out: io.Discard, NoColor: false}
for i := 0; i < b.N; i++ {
w.Write(msg)
}
}
================================================
FILE: context.go
================================================
package zerolog
import (
"context"
"fmt"
"math"
"net"
"time"
)
// Context configures a new sub-logger with contextual fields.
type Context struct {
l Logger
}
// Logger returns the logger with the context previously set.
func (c Context) Logger() Logger {
return c.l
}
// Fields is a helper function to use a map or slice to set fields using type assertion.
// Only map[string]interface{} and []interface{} are accepted. []interface{} must
// alternate string keys and arbitrary values, and extraneous ones are ignored.
func (c Context) Fields(fields interface{}) Context {
c.l.context = appendFields(c.l.context, fields, c.l.stack, c.l.ctx, c.l.hooks)
return c
}
// Dict adds the field key with the dict to the logger context.
func (c Context) Dict(key string, dict *Event) Context {
dict.buf = enc.AppendEndMarker(dict.buf)
c.l.context = append(enc.AppendKey(c.l.context, key), dict.buf...)
putEvent(dict)
return c
}
// CreateDict creates an Event to be used with the Context.Dict method.
// It preserves the stack, hooks, and context from the logger.
// Call usual field methods like Str, Int etc to add fields to this
// event and give it as argument the Context.Dict method.
func (c Context) CreateDict() *Event {
return newEvent(nil, DebugLevel, c.l.stack, c.l.ctx, c.l.hooks)
}
// CreateArray creates an Array to be used with the Context.Array method.
// It preserves the stack, hooks, and context from the logger.
// Call usual field methods like Str, Int etc to add elements to this
// array and give it as argument the Context.Array method.
func (c Context) CreateArray() *Array {
a := Arr()
a.stack = c.l.stack
a.ctx = c.l.ctx
a.ch = c.l.hooks
return a
}
// Array adds the field key with an array to the event context.
// Use c.CreateArray() to create the array or pass a type that
// implement the LogArrayMarshaler interface.
func (c Context) Array(key string, arr LogArrayMarshaler) Context {
c.l.context = enc.AppendKey(c.l.context, key)
if arr, ok := arr.(*Array); ok {
c.l.context = arr.write(c.l.context)
return c
}
a := c.CreateArray()
arr.MarshalZerologArray(a)
c.l.context = a.write(c.l.context)
return c
}
// Object marshals an object that implement the LogObjectMarshaler interface.
func (c Context) Object(key string, obj LogObjectMarshaler) Context {
e := c.l.scratchEvent()
e.Object(key, obj)
c.l.context = enc.AppendObjectData(c.l.context, e.buf)
putEvent(e)
return c
}
// Object marshals an object that implement the LogObjectMarshaler interface.
func (c Context) Objects(key string, objs []LogObjectMarshaler) Context {
e := c.l.scratchEvent()
e.Objects(key, objs)
c.l.context = enc.AppendObjectData(c.l.context, e.buf)
putEvent(e)
return c
}
// EmbedObject marshals and Embeds an object that implement the LogObjectMarshaler interface.
func (c Context) EmbedObject(obj LogObjectMarshaler) Context {
e := c.l.scratchEvent()
e.EmbedObject(obj)
c.l.context = enc.AppendObjectData(c.l.context, e.buf)
putEvent(e)
return c
}
// Str adds the field key with val as a string to the logger context.
func (c Context) Str(key, val string) Context {
c.l.context = enc.AppendString(enc.AppendKey(c.l.context, key), val)
return c
}
// Strs adds the field key with val as a string to the logger context.
func (c Context) Strs(key string, vals []string) Context {
c.l.context = enc.AppendStrings(enc.AppendKey(c.l.context, key), vals)
return c
}
// Stringer adds the field key with val.String() (or null if val is nil) to the logger context.
func (c Context) Stringer(key string, val fmt.Stringer) Context {
if val != nil {
c.l.context = enc.AppendString(enc.AppendKey(c.l.context, key), val.String())
return c
}
c.l.context = enc.AppendInterface(enc.AppendKey(c.l.context, key), nil)
return c
}
// Stringers adds the field key with vals as an array of strings by calling .String() on each entry
// to the logger context.
func (c Context) Stringers(key string, vals []fmt.Stringer) Context {
if vals != nil {
c.l.context = enc.AppendStringers(enc.AppendKey(c.l.context, key), vals)
return c
}
c.l.context = enc.AppendInterface(enc.AppendKey(c.l.context, key), nil)
return c
}
// Bytes adds the field key with val as a []byte to the logger context.
func (c Context) Bytes(key string, val []byte) Context {
c.l.context = enc.AppendBytes(enc.AppendKey(c.l.context, key), val)
return c
}
// Hex adds the field key with val as a hex string to the logger context.
func (c Context) Hex(key string, val []byte) Context {
c.l.context = enc.AppendHex(enc.AppendKey(c.l.context, key), val)
return c
}
// RawJSON adds already encoded JSON to context.
//
// No sanity check is performed on b; it must not contain carriage returns and
// be valid JSON.
func (c Context) RawJSON(key string, b []byte) Context {
c.l.context = appendJSON(enc.AppendKey(c.l.context, key), b)
return c
}
// AnErr adds the field key with serialized err to the logger context.
// If err is nil, no field is added.
func (c Context) AnErr(key string, err error) Context {
switch m := ErrorMarshalFunc(err).(type) {
case nil:
return c
case LogObjectMarshaler:
return c.Object(key, m)
case error:
if isNilValue(m) {
return c
}
return c.Str(key, m.Error())
case string:
return c.Str(key, m)
default:
return c.Interface(key, m)
}
}
// Errs adds the field key with errs as an array of serialized errors to the
// logger context.
func (c Context) Errs(key string, errs []error) Context {
arr := c.CreateArray().Errs(errs)
return c.Array(key, arr)
}
// Err adds the field "error" with serialized err to the logger context.
func (c Context) Err(err error) Context {
if c.l.stack && ErrorStackMarshaler != nil {
switch m := ErrorStackMarshaler(err).(type) {
case nil:
return c // do nothing with nil errors
case LogObjectMarshaler:
c = c.Object(ErrorStackFieldName, m)
case error:
c = c.Str(ErrorStackFieldName, m.Error())
case string:
c = c.Str(ErrorStackFieldName, m)
default:
c = c.Interface(ErrorStackFieldName, m)
}
}
return c.AnErr(ErrorFieldName, err)
}
// Ctx adds the context.Context to the logger context. The context.Context is
// not rendered in the error message, but is made available for hooks to use.
// A typical use case is to extract tracing information from the
// context.Context.
func (c Context) Ctx(ctx context.Context) Context {
c.l.ctx = ctx
return c
}
// Bool adds the field key with val as a bool to the logger context.
func (c Context) Bool(key string, b bool) Context {
c.l.context = enc.AppendBool(enc.AppendKey(c.l.context, key), b)
return c
}
// Bools adds the field key with val as a []bool to the logger context.
func (c Context) Bools(key string, b []bool) Context {
c.l.context = enc.AppendBools(enc.AppendKey(c.l.context, key), b)
return c
}
// Int adds the field key with i as a int to the logger context.
func (c Context) Int(key string, i int) Context {
c.l.context = enc.AppendInt(enc.AppendKey(c.l.context, key), i)
return c
}
// Ints adds the field key with i as a []int to the logger context.
func (c Context) Ints(key string, i []int) Context {
c.l.context = enc.AppendInts(enc.AppendKey(c.l.context, key), i)
return c
}
// Int8 adds the field key with i as a int8 to the logger context.
func (c Context) Int8(key string, i int8) Context {
c.l.context = enc.AppendInt8(enc.AppendKey(c.l.context, key), i)
return c
}
// Ints8 adds the field key with i as a []int8 to the logger context.
func (c Context) Ints8(key string, i []int8) Context {
c.l.context = enc.AppendInts8(enc.AppendKey(c.l.context, key), i)
return c
}
// Int16 adds the field key with i as a int16 to the logger context.
func (c Context) Int16(key string, i int16) Context {
c.l.context = enc.AppendInt16(enc.AppendKey(c.l.context, key), i)
return c
}
// Ints16 adds the field key with i as a []int16 to the logger context.
func (c Context) Ints16(key string, i []int16) Context {
c.l.context = enc.AppendInts16(enc.AppendKey(c.l.context, key), i)
return c
}
// Int32 adds the field key with i as a int32 to the logger context.
func (c Context) Int32(key string, i int32) Context {
c.l.context = enc.AppendInt32(enc.AppendKey(c.l.context, key), i)
return c
}
// Ints32 adds the field key with i as a []int32 to the logger context.
func (c Context) Ints32(key string, i []int32) Context {
c.l.context = enc.AppendInts32(enc.AppendKey(c.l.context, key), i)
return c
}
// Int64 adds the field key with i as a int64 to the logger context.
func (c Context) Int64(key string, i int64) Context {
c.l.context = enc.AppendInt64(enc.AppendKey(c.l.context, key), i)
return c
}
// Ints64 adds the field key with i as a []int64 to the logger context.
func (c Context) Ints64(key string, i []int64) Context {
c.l.context = enc.AppendInts64(enc.AppendKey(c.l.context, key), i)
return c
}
// Uint adds the field key with i as a uint to the logger context.
func (c Context) Uint(key string, i uint) Context {
c.l.context = enc.AppendUint(enc.AppendKey(c.l.context, key), i)
return c
}
// Uints adds the field key with i as a []uint to the logger context.
func (c Context) Uints(key string, i []uint) Context {
c.l.context = enc.AppendUints(enc.AppendKey(c.l.context, key), i)
return c
}
// Uint8 adds the field key with i as a uint8 to the logger context.
func (c Context) Uint8(key string, i uint8) Context {
c.l.context = enc.AppendUint8(enc.AppendKey(c.l.context, key), i)
return c
}
// Uints8 adds the field key with i as a []uint8 to the logger context.
func (c Context) Uints8(key string, i []uint8) Context {
c.l.context = enc.AppendUints8(enc.AppendKey(c.l.context, key), i)
return c
}
// Uint16 adds the field key with i as a uint16 to the logger context.
func (c Context) Uint16(key string, i uint16) Context {
c.l.context = enc.AppendUint16(enc.AppendKey(c.l.context, key), i)
return c
}
// Uints16 adds the field key with i as a []uint16 to the logger context.
func (c Context) Uints16(key string, i []uint16) Context {
c.l.context = enc.AppendUints16(enc.AppendKey(c.l.context, key), i)
return c
}
// Uint32 adds the field key with i as a uint32 to the logger context.
func (c Context) Uint32(key string, i uint32) Context {
c.l.context = enc.AppendUint32(enc.AppendKey(c.l.context, key), i)
return c
}
// Uints32 adds the field key with i as a []uint32 to the logger context.
func (c Context) Uints32(key string, i []uint32) Context {
c.l.context = enc.AppendUints32(enc.AppendKey(c.l.context, key), i)
return c
}
// Uint64 adds the field key with i as a uint64 to the logger context.
func (c Context) Uint64(key string, i uint64) Context {
c.l.context = enc.AppendUint64(enc.AppendKey(c.l.context, key), i)
return c
}
// Uints64 adds the field key with i as a []uint64 to the logger context.
func (c Context) Uints64(key string, i []uint64) Context {
c.l.context = enc.AppendUints64(enc.AppendKey(c.l.context, key), i)
return c
}
// Float32 adds the field key with f as a float32 to the logger context.
func (c Context) Float32(key string, f float32) Context {
c.l.context = enc.AppendFloat32(enc.AppendKey(c.l.context, key), f, FloatingPointPrecision)
return c
}
// Floats32 adds the field key with f as a []float32 to the logger context.
func (c Context) Floats32(key string, f []float32) Context {
c.l.context = enc.AppendFloats32(enc.AppendKey(c.l.context, key), f, FloatingPointPrecision)
return c
}
// Float64 adds the field key with f as a float64 to the logger context.
func (c Context) Float64(key string, f float64) Context {
c.l.context = enc.AppendFloat64(enc.AppendKey(c.l.context, key), f, FloatingPointPrecision)
return c
}
// Floats64 adds the field key with f as a []float64 to the logger context.
func (c Context) Floats64(key string, f []float64) Context {
c.l.context = enc.AppendFloats64(enc.AppendKey(c.l.context, key), f, FloatingPointPrecision)
return c
}
type timestampHook struct{}
func (ts timestampHook) Run(e *Event, level Level, msg string) {
e.Timestamp()
}
var th = timestampHook{}
// Timestamp adds the current local time to the logger context with the "time" key, formatted using zerolog.TimeFieldFormat.
// To customize the key name, change zerolog.TimestampFieldName.
// To customize the time format, change zerolog.TimeFieldFormat.
//
// NOTE: It won't dedupe the "time" key if the *Context has one already.
func (c Context) Timestamp() Context {
c.l = c.l.Hook(th)
return c
}
// Time adds the field key with t formatted as string using zerolog.TimeFieldFormat.
func (c Context) Time(key string, t time.Time) Context {
c.l.context = enc.AppendTime(enc.AppendKey(c.l.context, key), t, TimeFieldFormat)
return c
}
// Times adds the field key with t formatted as string using zerolog.TimeFieldFormat.
func (c Context) Times(key string, t []time.Time) Context {
c.l.context = enc.AppendTimes(enc.AppendKey(c.l.context, key), t, TimeFieldFormat)
return c
}
// Dur adds the field key with d divided by unit and stored as a float.
func (c Context) Dur(key string, d time.Duration) Context {
c.l.context = enc.AppendDuration(enc.AppendKey(c.l.context, key), d, DurationFieldUnit, DurationFieldFormat, DurationFieldInteger, FloatingPointPrecision)
return c
}
// Durs adds the field key with d divided by unit and stored as a float.
func (c Context) Durs(key string, d []time.Duration) Context {
c.l.context = enc.AppendDurations(enc.AppendKey(c.l.context, key), d, DurationFieldUnit, DurationFieldFormat, DurationFieldInteger, FloatingPointPrecision)
return c
}
// Interface adds the field key with obj marshaled using reflection.
func (c Context) Interface(key string, i interface{}) Context {
if obj, ok := i.(LogObjectMarshaler); ok {
return c.Object(key, obj)
}
c.l.context = enc.AppendInterface(enc.AppendKey(c.l.context, key), i)
return c
}
// Type adds the field key with val's type using reflection.
func (c Context) Type(key string, val interface{}) Context {
c.l.context = enc.AppendType(enc.AppendKey(c.l.context, key), val)
return c
}
// Any is a wrapper around Context.Interface.
func (c Context) Any(key string, i interface{}) Context {
return c.Interface(key, i)
}
// Reset removes all the context fields.
func (c Context) Reset() Context {
c.l.context = enc.AppendBeginMarker(make([]byte, 0, 500))
return c
}
type callerHook struct {
callerSkipFrameCount int
}
func newCallerHook(skipFrameCount int) callerHook {
return callerHook{callerSkipFrameCount: skipFrameCount}
}
func (ch callerHook) Run(e *Event, level Level, msg string) {
switch ch.callerSkipFrameCount {
case useGlobalSkipFrameCount:
// Extra frames to skip (added by hook infra).
e.caller(CallerSkipFrameCount + contextCallerSkipFrameCount)
default:
// Extra frames to skip (added by hook infra).
e.caller(ch.callerSkipFrameCount + contextCallerSkipFrameCount)
}
}
// useGlobalSkipFrameCount acts as a flag to informat callerHook.Run
// to use the global CallerSkipFrameCount.
const useGlobalSkipFrameCount = math.MinInt32
// ch is the default caller hook using the global CallerSkipFrameCount.
var ch = newCallerHook(useGlobalSkipFrameCount)
// Caller adds the file:line of the caller with the zerolog.CallerFieldName key.
func (c Context) Caller() Context {
c.l = c.l.Hook(ch)
return c
}
// CallerWithSkipFrameCount adds the file:line of the caller with the zerolog.CallerFieldName key.
// The specified skipFrameCount int will override the global CallerSkipFrameCount for this context's respective logger.
// If set to -1 the global CallerSkipFrameCount will be used.
func (c Context) CallerWithSkipFrameCount(skipFrameCount int) Context {
c.l = c.l.Hook(newCallerHook(skipFrameCount))
return c
}
// Stack enables stack trace printing for the error passed to Err().
func (c Context) Stack() Context {
c.l.stack = true
return c
}
// IPAddr adds adds the field key with ip as a net.IP IPv4 or IPv6 Address to the context
func (c Context) IPAddr(key string, ip net.IP) Context {
c.l.context = enc.AppendIPAddr(enc.AppendKey(c.l.context, key), ip)
return c
}
// IPAddrs adds the field key with ip as a []net.IP array of IPv4 or IPv6 Address to the context
func (c Context) IPAddrs(key string, ip []net.IP) Context {
c.l.context = enc.AppendIPAddrs(enc.AppendKey(c.l.context, key), ip)
return c
}
// IPPrefix adds adds the field key with pfx as a []net.IPNet IPv4 or IPv6 Prefix (address and mask) to the context
func (c Context) IPPrefix(key string, pfx net.IPNet) Context {
c.l.context = enc.AppendIPPrefix(enc.AppendKey(c.l.context, key), pfx)
return c
}
// IPPrefix adds adds the field key with pfx as a []net.IPNet array of IPv4 or IPv6 Prefix (address and mask) to the context
func (c Context) IPPrefixes(key string, pfx []net.IPNet) Context {
c.l.context = enc.AppendIPPrefixes(enc.AppendKey(c.l.context, key), pfx)
return c
}
// MACAddr adds adds the field key with ha as a net.HardwareAddr MAC address to the context
func (c Context) MACAddr(key string, ha net.HardwareAddr) Context {
c.l.context = enc.AppendMACAddr(enc.AppendKey(c.l.context, key), ha)
return c
}
================================================
FILE: context_test.go
================================================
package zerolog
import (
"bytes"
"errors"
"testing"
)
type myError struct{}
func (e *myError) Error() string { return "test" }
func TestContext_ErrWithStackMarshaler(t *testing.T) {
// Save original
original := ErrorStackMarshaler
defer func() { ErrorStackMarshaler = original }()
// Set a mock marshaler
ErrorStackMarshaler = func(err error) interface{} {
return "stack-trace"
}
var buf bytes.Buffer
log := New(&buf).With().Stack().Err(errors.New("test error")).Logger()
log.Info().Msg("test message")
got := decodeIfBinaryToString(buf.Bytes())
want := `{"level":"info","stack":"stack-trace","error":"test error","message":"test message"}` + "\n"
if got != want {
t.Errorf("Context.Err() with stack marshaler = %q, want %q", got, want)
}
}
func TestContext_AnErrWithNilErrorMarshal(t *testing.T) {
// Save original
original := ErrorMarshalFunc
defer func() { ErrorMarshalFunc = original }()
// Set marshaler to return a nil error pointer
ErrorMarshalFunc = func(err error) interface{} {
return (*myError)(nil) // nil pointer of error type
}
var buf bytes.Buffer
log := New(&buf).With().AnErr("test", errors.New("some error")).Logger()
log.Info().Msg("test message")
got := decodeIfBinaryToString(buf.Bytes())
want := `{"level":"info","message":"test message"}` + "\n" // No "test" field because isNilValue returned true
if got != want {
t.Errorf("Context.AnErr() with nil error marshal = %q, want %q", got, want)
}
}
func TestContext_ErrWithNilStackMarshaler(t *testing.T) {
// Save original
original := ErrorStackMarshaler
defer func() { ErrorStackMarshaler = original }()
// Set marshaler to return nil
ErrorStackMarshaler = func(err error) interface{} {
return nil
}
var buf bytes.Buffer
log := New(&buf).With().Stack().Err(errors.New("test error")).Logger()
log.Info().Msg("test message")
got := decodeIfBinaryToString(buf.Bytes())
want := `{"level":"info","message":"test message"}` + "\n" // No stack or error field because stack marshaler returned nil
if got != want {
t.Errorf("Context.Err() with nil stack marshaler = %q, want %q", got, want)
}
}
func TestContext_ErrWithStackMarshalerObject(t *testing.T) {
// Save original
original := ErrorStackMarshaler
defer func() { ErrorStackMarshaler = original }()
// Set a mock marshaler that returns LogObjectMarshaler
ErrorStackMarshaler = func(err error) interface{} {
return logObjectMarshalerImpl{name: "user", age: 30}
}
var buf bytes.Buffer
log := New(&buf).With().Stack().Err(errors.New("test error")).Logger()
log.Info().Msg("test message")
got := decodeIfBinaryToString(buf.Bytes())
want := `{"level":"info","stack":{"name":"user","age":-30},"error":"test error","message":"test message"}` + "\n"
if got != want {
t.Errorf("Context.Err() with stack marshaler object = %q, want %q", got, want)
}
}
func TestContext_ErrWithStackMarshalerError(t *testing.T) {
// Save original
original := ErrorStackMarshaler
defer func() { ErrorStackMarshaler = original }()
// Set a mock marshaler that returns an error
ErrorStackMarshaler = func(err error) interface{} {
return errors.New("stack error")
}
var buf bytes.Buffer
log := New(&buf).With().Stack().Err(errors.New("test error")).Logger()
log.Info().Msg("test message")
got := decodeIfBinaryToString(buf.Bytes())
want := `{"level":"info","stack":"stack error","error":"test error","message":"test message"}` + "\n"
if got != want {
t.Errorf("Context.Err() with stack marshaler error = %q, want %q", got, want)
}
}
func TestContext_ErrWithStackMarshalerInterface(t *testing.T) {
// Save original
original := ErrorStackMarshaler
defer func() { ErrorStackMarshaler = original }()
// Set a mock marshaler that returns an int
ErrorStackMarshaler = func(err error) interface{} {
return 42
}
var buf bytes.Buffer
log := New(&buf).With().Stack().Err(errors.New("test error")).Logger()
log.Info().Msg("test message")
got := decodeIfBinaryToString(buf.Bytes())
want := `{"level":"info","stack":42,"error":"test error","message":"test message"}` + "\n"
if got != want {
t.Errorf("Context.Err() with stack marshaler interface = %q, want %q", got, want)
}
}
================================================
FILE: ctx.go
================================================
package zerolog
import (
"context"
)
var disabledLogger *Logger
func init() {
SetGlobalLevel(TraceLevel)
l := Nop()
disabledLogger = &l
}
type ctxKey struct{}
// WithContext returns a copy of ctx with the receiver attached. The Logger
// attached to the provided Context (if any) will not be effected. If the
// receiver's log level is Disabled it will only be attached to the returned
// Context if the provided Context has a previously attached Logger. If the
// provided Context has no attached Logger, a Disabled Logger will not be
// attached.
//
// Note: to modify the existing Logger attached to a Context (instead of
// replacing it in a new Context), use UpdateContext with the following
// notation:
//
// ctx := r.Context()
// l := zerolog.Ctx(ctx)
// l.UpdateContext(func(c Context) Context {
// return c.Str("bar", "baz")
// })
func (l Logger) WithContext(ctx context.Context) context.Context {
if _, ok := ctx.Value(ctxKey{}).(*Logger); !ok && l.level == Disabled {
// Do not store disabled logger.
return ctx
}
return context.WithValue(ctx, ctxKey{}, &l)
}
// Ctx returns the Logger associated with the ctx. If no logger
// is associated, DefaultContextLogger is returned, unless DefaultContextLogger
// is nil, in which case a disabled logger is returned.
func Ctx(ctx context.Context) *Logger {
if l, ok := ctx.Value(ctxKey{}).(*Logger); ok {
return l
} else if l = DefaultContextLogger; l != nil {
return l
}
return disabledLogger
}
================================================
FILE: ctx_test.go
================================================
package zerolog
import (
"bytes"
"context"
"io"
"reflect"
"strings"
"testing"
"github.com/rs/zerolog/internal/cbor"
)
func TestCtx(t *testing.T) {
log := New(io.Discard)
ctx := log.WithContext(context.Background())
log2 := Ctx(ctx)
if !reflect.DeepEqual(log, *log2) {
t.Error("Ctx did not return the expected logger")
}
// update
log = log.Level(InfoLevel)
ctx = log.WithContext(ctx)
log2 = Ctx(ctx)
if !reflect.DeepEqual(log, *log2) {
t.Error("Ctx did not return the expected logger")
}
log2 = Ctx(context.Background())
if log2 != disabledLogger {
t.Error("Ctx did not return the expected logger")
}
DefaultContextLogger = &log
t.Cleanup(func() { DefaultContextLogger = nil })
log2 = Ctx(context.Background())
if log2 != &log {
t.Error("Ctx did not return the expected logger")
}
}
func TestCtxDisabled(t *testing.T) {
dl := New(io.Discard).Level(Disabled)
ctx := dl.WithContext(context.Background())
if ctx != context.Background() {
t.Error("WithContext stored a disabled logger")
}
l := New(io.Discard).With().Str("foo", "bar").Logger()
ctx = l.WithContext(ctx)
if !reflect.DeepEqual(Ctx(ctx), &l) {
t.Error("WithContext did not store logger")
}
l.UpdateContext(func(c Context) Context {
return c.Str("bar", "baz")
})
ctx = l.WithContext(ctx)
if !reflect.DeepEqual(Ctx(ctx), &l) {
t.Error("WithContext did not store updated logger")
}
l = l.Level(DebugLevel)
ctx = l.WithContext(ctx)
if !reflect.DeepEqual(Ctx(ctx), &l) {
t.Error("WithContext did not store copied logger")
}
ctx = dl.WithContext(ctx)
if !reflect.DeepEqual(Ctx(ctx), &dl) {
t.Error("WithContext did not override logger with a disabled logger")
}
}
type logObjectMarshalerImpl struct {
name string
age int
}
func (t logObjectMarshalerImpl) MarshalZerologObject(e *Event) {
e.Str("name", strings.ToLower(t.name)).Int("age", -t.age)
}
func Test_InterfaceLogObjectMarshaler(t *testing.T) {
var buf bytes.Buffer
log := New(&buf)
ctx := log.WithContext(context.Background())
log2 := Ctx(ctx)
withLog := log2.With().Interface("obj", &logObjectMarshalerImpl{
name: "FOO",
age: 29,
}).Logger()
withLog.Info().Msg("test")
if got, want := cbor.DecodeIfBinaryToString(buf.Bytes()), `{"level":"info","obj":{"name":"foo","age":-29},"message":"test"}`+"\n"; got != want {
t.Errorf("got %q, want %q", got, want)
}
}
================================================
FILE: diode/diode.go
================================================
// Package diode provides a thread-safe, lock-free, non-blocking io.Writer
// wrapper.
package diode
import (
"context"
"io"
"sync"
"time"
"github.com/rs/zerolog/diode/internal/diodes"
)
var bufPool = &sync.Pool{
New: func() interface{} {
return make([]byte, 0, 500)
},
}
type Alerter func(missed int)
type diodeFetcher interface {
diodes.Diode
Next() diodes.GenericDataType
}
// Writer is a io.Writer wrapper that uses a diode to make Write lock-free,
// non-blocking and thread safe.
type Writer struct {
w io.Writer
d diodeFetcher
c context.CancelFunc
done chan struct{}
}
// NewWriter creates a writer wrapping w with a many-to-one diode in order to
// never block log producers and drop events if the writer can't keep up with
// the flow of data.
//
// Use a diode.Writer when
//
// wr := diode.NewWriter(w, 1000, 0, func(missed int) {
// log.Printf("Dropped %d messages", missed)
// })
// log := zerolog.New(wr)
//
// If pollInterval is greater than 0, a poller is used otherwise a waiter is
// used.
//
// See code.cloudfoundry.org/go-diodes for more info on diode.
func NewWriter(w io.Writer, size int, pollInterval time.Duration, f Alerter) Writer {
ctx, cancel := context.WithCancel(context.Background())
dw := Writer{
w: w,
c: cancel,
done: make(chan struct{}),
}
if f == nil {
f = func(int) {}
}
d := diodes.NewManyToOne(size, diodes.AlertFunc(f))
if pollInterval > 0 {
dw.d = diodes.NewPoller(d,
diodes.WithPollingInterval(pollInterval),
diodes.WithPollingContext(ctx))
} else {
dw.d = diodes.NewWaiter(d,
diodes.WithWaiterContext(ctx))
}
go dw.poll()
return dw
}
func (dw Writer) Write(p []byte) (n int, err error) {
// p is pooled in zerolog so we can't hold it passed this call, hence the
// copy.
p = append(bufPool.Get().([]byte), p...)
dw.d.Set(diodes.GenericDataType(&p))
return len(p), nil
}
// Close releases the diode poller and call Close on the wrapped writer if
// io.Closer is implemented.
func (dw Writer) Close() error {
dw.c()
<-dw.done
if w, ok := dw.w.(io.Closer); ok {
return w.Close()
}
return nil
}
func (dw Writer) poll() {
defer close(dw.done)
for {
d := dw.d.Next()
if d == nil {
return
}
p := *(*[]byte)(d)
dw.w.Write(p)
// Proper usage of a sync.Pool requires each entry to have approximately
// the same memory cost. To obtain this property when the stored type
// contains a variably-sized buffer, we add a hard limit on the maximum buffer
// to place back in the pool.
//
// See https://golang.org/issue/23199
const maxSize = 1 << 16 // 64KiB
if cap(p) <= maxSize {
bufPool.Put(p[:0])
}
}
}
================================================
FILE: diode/diode_example_test.go
================================================
// +build !binary_log
package diode_test
import (
"fmt"
"os"
"github.com/rs/zerolog"
"github.com/rs/zerolog/diode"
)
func ExampleNewWriter() {
w := diode.NewWriter(os.Stdout, 1000, 0, func(missed int) {
fmt.Printf("Dropped %d messages\n", missed)
})
log := zerolog.New(w)
log.Print("test")
w.Close()
// Output: {"level":"debug","message":"test"}
}
================================================
FILE: diode/diode_test.go
================================================
package diode_test
import (
"bytes"
"fmt"
"io"
"log"
"os"
"os/exec"
"sync"
"testing"
"time"
"github.com/rs/zerolog"
"github.com/rs/zerolog/diode"
"github.com/rs/zerolog/internal/cbor"
)
func TestNewWriter(t *testing.T) {
buf := bytes.Buffer{}
w := diode.NewWriter(&buf, 1000, 0, func(missed int) {
fmt.Printf("Dropped %d messages\n", missed)
})
log := zerolog.New(w)
log.Print("test")
w.Close()
want := "{\"level\":\"debug\",\"message\":\"test\"}\n"
got := cbor.DecodeIfBinaryToString(buf.Bytes())
if got != want {
t.Errorf("Diode New Writer Test failed. got:%s, want:%s!", got, want)
}
}
func TestClose(t *testing.T) {
buf := bytes.Buffer{}
w := diode.NewWriter(&buf, 1000, 0, func(missed int) {})
log := zerolog.New(w)
log.Print("test")
w.Close()
}
func TestFatal(t *testing.T) {
if os.Getenv("TEST_FATAL") == "1" {
w := diode.NewWriter(os.Stderr, 1000, 0, func(missed int) {
fmt.Printf("Dropped %d messages\n", missed)
})
defer w.Close()
log := zerolog.New(w)
log.Fatal().Msg("test")
return
}
cmd := exec.Command(os.Args[0], "-test.run=TestFatal")
cmd.Env = append(os.Environ(), "TEST_FATAL=1")
stderr, err := cmd.StderrPipe()
if err != nil {
t.Fatal(err)
}
err = cmd.Start()
if err != nil {
t.Fatal(err)
}
var stderrBuf bytes.Buffer
var wg sync.WaitGroup
wg.Add(1)
go func() {
defer wg.Done()
if _, err := io.Copy(&stderrBuf, stderr); err != nil {
t.Errorf("failed to copy stderr: %v", err)
}
}()
err = cmd.Wait()
if err == nil {
t.Error("Expected log.Fatal to exit with non-zero status")
}
wg.Wait() // Wait for the goroutine to finish copying
slurp := stderrBuf.Bytes()
want := "{\"level\":\"fatal\",\"message\":\"test\"}\n"
got := cbor.DecodeIfBinaryToString(slurp)
if got != want {
t.Errorf("Diode Fatal Test failed. got:%s, want:%s!", got, want)
}
}
type SlowWriter struct{}
func (rw *SlowWriter) Write(p []byte) (n int, err error) {
time.Sleep(200 * time.Millisecond)
fmt.Print(string(p))
return len(p), nil
}
func TestFatalWithFilteredLevelWriter(t *testing.T) {
if os.Getenv("TEST_FATAL_SLOW") == "1" {
slowWriter := SlowWriter{}
diodeWriter := diode.NewWriter(&slowWriter, 500, 0, func(missed int) {
fmt.Printf("Missed %d logs\n", missed)
})
leveledDiodeWriter := zerolog.LevelWriterAdapter{
Writer: &diodeWriter,
}
filteredDiodeWriter := zerolog.FilteredLevelWriter{
Writer: &leveledDiodeWriter,
Level: zerolog.InfoLevel,
}
logger := zerolog.New(&filteredDiodeWriter)
logger.Fatal().Msg("test")
return
}
cmd := exec.Command(os.Args[0], "-test.run=TestFatalWithFilteredLevelWriter")
cmd.Env = append(os.Environ(), "TEST_FATAL_SLOW=1")
stdout, err := cmd.StdoutPipe()
if err != nil {
t.Fatal(err)
}
err = cmd.Start()
if err != nil {
t.Fatal(err)
}
var stdoutBuf bytes.Buffer
var wg sync.WaitGroup
wg.Add(1)
go func() {
defer wg.Done()
_, _ = io.Copy(&stdoutBuf, stdout)
}()
err = cmd.Wait()
if err == nil {
t.Error("Expected log.Fatal to exit with non-zero status")
}
wg.Wait() // Wait for the goroutine to finish copying
slurp := stdoutBuf.Bytes()
got := cbor.DecodeIfBinaryToString(slurp)
want := "{\"level\":\"fatal\",\"message\":\"test\"}\n"
if got != want {
t.Errorf("Expected output %q, got: %q", want, got)
}
}
func Benchmark(b *testing.B) {
log.SetOutput(io.Discard)
defer log.SetOutput(os.Stderr)
benchs := map[string]time.Duration{
"Waiter": 0,
"Pooler": 10 * time.Millisecond,
}
for name, interval := range benchs {
b.Run(name, func(b *testing.B) {
w := diode.NewWriter(io.Discard, 100000, interval, nil)
log := zerolog.New(w)
defer w.Close()
b.SetParallelism(1000)
b.RunParallel(func(pb *testing.PB) {
for pb.Next() {
log.Print("test")
}
})
})
}
}
================================================
FILE: diode/internal/diodes/README
================================================
Copied from https://github.com/cloudfoundry/go-diodes to avoid test dependencies.
================================================
FILE: diode/internal/diodes/many_to_one.go
================================================
package diodes
import (
"log"
"sync/atomic"
"unsafe"
)
// ManyToOne diode is optimal for many writers (go-routines B-n) and a single
// reader (go-routine A). It is not thread safe for multiple readers.
type ManyToOne struct {
writeIndex uint64
readIndex uint64
buffer []unsafe.Pointer
alerter Alerter
}
// NewManyToOne creates a new diode (ring buffer). The ManyToOne diode
// is optimized for many writers (on go-routines B-n) and a single reader
// (on go-routine A). The alerter is invoked on the read's go-routine. It is
// called when it notices that the writer go-routine has passed it and wrote
// over data. A nil can be used to ignore alerts.
func NewManyToOne(size int, alerter Alerter) *ManyToOne {
if alerter == nil {
alerter = AlertFunc(func(int) {})
}
d := &ManyToOne{
buffer: make([]unsafe.Pointer, size),
alerter: alerter,
}
// Start write index at the value before 0
// to allow the first write to use AddUint64
// and still have a beginning index of 0
d.writeIndex = ^d.writeIndex
return d
}
// Set sets the data in the next slot of the ring buffer.
func (d *ManyToOne) Set(data GenericDataType) {
for {
writeIndex := atomic.AddUint64(&d.writeIndex, 1)
idx := writeIndex % uint64(len(d.buffer))
old := atomic.LoadPointer(&d.buffer[idx])
if old != nil &&
(*bucket)(old) != nil &&
(*bucket)(old).seq > writeIndex-uint64(len(d.buffer)) {
log.Println("Diode set collision: consider using a larger diode")
continue
}
newBucket := &bucket{
data: data,
seq: writeIndex,
}
if !atomic.CompareAndSwapPointer(&d.buffer[idx], old, unsafe.Pointer(newBucket)) {
log.Println("Diode set collision: consider using a larger diode")
continue
}
return
}
}
// TryNext will attempt to read from the next slot of the ring buffer.
// If there is no data available, it will return (nil, false).
func (d *ManyToOne) TryNext() (data GenericDataType, ok bool) {
// Read a value from the ring buffer based on the readIndex.
idx := d.readIndex % uint64(len(d.buffer))
result := (*bucket)(atomic.SwapPointer(&d.buffer[idx], nil))
// When the result is nil that means the writer has not had the
// opportunity to write a value into the diode. This value must be ignored
// and the read head must not increment.
if result == nil {
return nil, false
}
// When the seq value is less than the current read index that means a
// value was read from idx that was previously written but since has
// been dropped. This value must be ignored and the read head must not
// increment.
//
// The simulation for this scenario assumes the fast forward occurred as
// detailed below.
//
// 5. The reader reads again getting seq 5. It then reads again expecting
// seq 6 but gets seq 2. This is a read of a stale value that was
// effectively "dropped" so the read fails and the read head stays put.
// `| 4 | 5 | 2 | 3 |` r: 7, w: 6
//
if result.seq < d.readIndex {
return nil, false
}
// When the seq value is greater than the current read index that means a
// value was read from idx that overwrote the value that was expected to
// be at this idx. This happens when the writer has lapped the reader. The
// reader needs to catch up to the writer so it moves its write head to
// the new seq, effectively dropping the messages that were not read in
// between the two values.
//
// Here is a simulation of this scenario:
//
// 1. Both the read and write heads start at 0.
// `| nil | nil | nil | nil |` r: 0, w: 0
// 2. The writer fills the buffer.
// `| 0 | 1 | 2 | 3 |` r: 0, w: 4
// 3. The writer laps the read head.
// `| 4 | 5 | 2 | 3 |` r: 0, w: 6
// 4. The reader reads the first value, expecting a seq of 0 but reads 4,
// this forces the reader to fast forward to 5.
// `| 4 | 5 | 2 | 3 |` r: 5, w: 6
//
if result.seq > d.readIndex {
dropped := result.seq - d.readIndex
d.readIndex = result.seq
d.alerter.Alert(int(dropped))
}
// Only increment read index if a regular read occurred (where seq was
// equal to readIndex) or a value was read that caused a fast forward
// (where seq was greater than readIndex).
//
d.readIndex++
return result.data, true
}
================================================
FILE: diode/internal/diodes/one_to_one.go
================================================
package diodes
import (
"sync/atomic"
"unsafe"
)
// GenericDataType is the data type the diodes operate on.
type GenericDataType unsafe.Pointer
// Alerter is used to report how many values were overwritten since the
// last write.
type Alerter interface {
Alert(missed int)
}
// AlertFunc type is an adapter to allow the use of ordinary functions as
// Alert handlers.
type AlertFunc func(missed int)
// Alert calls f(missed)
func (f AlertFunc) Alert(missed int) {
f(missed)
}
type bucket struct {
data GenericDataType
seq uint64 // seq is the recorded write index at the time of writing
}
// OneToOne diode is meant to be used by a single reader and a single writer.
// It is not thread safe if used otherwise.
type OneToOne struct {
writeIndex uint64
readIndex uint64
buffer []unsafe.Pointer
alerter Alerter
}
// NewOneToOne creates a new diode is meant to be used by a single reader and
// a single writer. The alerter is invoked on the read's go-routine. It is
// called when it notices that the writer go-routine has passed it and wrote
// over data. A nil can be used to ignore alerts.
func NewOneToOne(size int, alerter Alerter) *OneToOne {
if alerter == nil {
alerter = AlertFunc(func(int) {})
}
return &OneToOne{
buffer: make([]unsafe.Pointer, size),
alerter: alerter,
}
}
// Set sets the data in the next slot of the ring buffer.
func (d *OneToOne) Set(data GenericDataType) {
idx := d.writeIndex % uint64(len(d.buffer))
newBucket := &bucket{
data: data,
seq: d.writeIndex,
}
d.writeIndex++
atomic.StorePointer(&d.buffer[idx], unsafe.Pointer(newBucket))
}
// TryNext will attempt to read from the next slot of the ring buffer.
// If there is no data available, it will return (nil, false).
func (d *OneToOne) TryNext() (data GenericDataType, ok bool) {
// Read a value from the ring buffer based on the readIndex.
idx := d.readIndex % uint64(len(d.buffer))
result := (*bucket)(atomic.SwapPointer(&d.buffer[idx], nil))
// When the result is nil that means the writer has not had the
// opportunity to write a value into the diode. This value must be ignored
// and the read head must not increment.
if result == nil {
return nil, false
}
// When the seq value is less than the current read index that means a
// value was read from idx that was previously written but since has
// been dropped. This value must be ignored and the read head must not
// increment.
//
// The simulation for this scenario assumes the fast forward occurred as
// detailed below.
//
// 5. The reader reads again getting seq 5. It then reads again expecting
// seq 6 but gets seq 2. This is a read of a stale value that was
// effectively "dropped" so the read fails and the read head stays put.
// `| 4 | 5 | 2 | 3 |` r: 7, w: 6
//
if result.seq < d.readIndex {
return nil, false
}
// When the seq value is greater than the current read index that means a
// value was read from idx that overwrote the value that was expected to
// be at this idx. This happens when the writer has lapped the reader. The
// reader needs to catch up to the writer so it moves its write head to
// the new seq, effectively dropping the messages that were not read in
// between the two values.
//
// Here is a simulation of this scenario:
//
// 1. Both the read and write heads start at 0.
// `| nil | nil | nil | nil |` r: 0, w: 0
// 2. The writer fills the buffer.
// `| 0 | 1 | 2 | 3 |` r: 0, w: 4
// 3. The writer laps the read head.
// `| 4 | 5 | 2 | 3 |` r: 0, w: 6
// 4. The reader reads the first value, expecting a seq of 0 but reads 4,
// this forces the reader to fast forward to 5.
// `| 4 | 5 | 2 | 3 |` r: 5, w: 6
//
if result.seq > d.readIndex {
dropped := result.seq - d.readIndex
d.readIndex = result.seq
d.alerter.Alert(int(dropped))
}
// Only increment read index if a regular read occurred (where seq was
// equal to readIndex) or a value was read that caused a fast forward
// (where seq was greater than readIndex).
d.readIndex++
return result.data, true
}
================================================
FILE: diode/internal/diodes/poller.go
================================================
package diodes
import (
"context"
"time"
)
// Diode is any implementation of a diode.
type Diode interface {
Set(GenericDataType)
TryNext() (GenericDataType, bool)
}
// Poller will poll a diode until a value is available.
type Poller struct {
Diode
interval time.Duration
ctx context.Context
}
// PollerConfigOption can be used to setup the poller.
type PollerConfigOption func(*Poller)
// WithPollingInterval sets the interval at which the diode is queried
// for new data. The default is 10ms.
func WithPollingInterval(interval time.Duration) PollerConfigOption {
return func(c *Poller) {
c.interval = interval
}
}
// WithPollingContext sets the context to cancel any retrieval (Next()). It
// will not change any results for adding data (Set()). Default is
// context.Background().
func WithPollingContext(ctx context.Context) PollerConfigOption {
return func(c *Poller) {
c.ctx = ctx
}
}
// NewPoller returns a new Poller that wraps the given diode.
func NewPoller(d Diode, opts ...PollerConfigOption) *Poller {
p := &Poller{
Diode: d,
interval: 10 * time.Millisecond,
ctx: context.Background(),
}
for _, o := range opts {
o(p)
}
return p
}
// Next polls the diode until data is available or until the context is done.
// If the context is done, then nil will be returned.
func (p *Poller) Next() GenericDataType {
for {
data, ok := p.Diode.TryNext()
if !ok {
if p.isDone() {
return nil
}
time.Sleep(p.interval)
continue
}
return data
}
}
func (p *Poller) isDone() bool {
select {
case <-p.ctx.Done():
return true
default:
return false
}
}
================================================
FILE: diode/internal/diodes/waiter.go
================================================
package diodes
import (
"context"
"sync"
)
// Waiter will use a conditional mutex to alert the reader to when data is
// available.
type Waiter struct {
Diode
mu sync.Mutex
c *sync.Cond
ctx context.Context
}
// WaiterConfigOption can be used to setup the waiter.
type WaiterConfigOption func(*Waiter)
// WithWaiterContext sets the context to cancel any retrieval (Next()). It
// will not change any results for adding data (Set()). Default is
// context.Background().
func WithWaiterContext(ctx context.Context) WaiterConfigOption {
return func(c *Waiter) {
c.ctx = ctx
}
}
// NewWaiter returns a new Waiter that wraps the given diode.
func NewWaiter(d Diode, opts ...WaiterConfigOption) *Waiter {
w := new(Waiter)
w.Diode = d
w.c = sync.NewCond(&w.mu)
w.ctx = context.Background()
for _, opt := range opts {
opt(w)
}
go func() {
<-w.ctx.Done()
// Mutex is strictly necessary here to avoid a race in Next() (between
// w.isDone() and w.c.Wait()) and w.c.Broadcast() here.
w.mu.Lock()
w.c.Broadcast()
w.mu.Unlock()
}()
return w
}
// Set invokes the wrapped diode's Set with the given data and uses Broadcast
// to wake up any readers.
func (w *Waiter) Set(data GenericDataType) {
w.Diode.Set(data)
w.c.Broadcast()
}
// Next returns the next data point on the wrapped diode. If there is not any
// new data, it will Wait for set to be called or the context to be done.
// If the context is done, then nil will be returned.
func (w *Waiter) Next() GenericDataType {
w.mu.Lock()
defer w.mu.Unlock()
for {
data, ok := w.Diode.TryNext()
if !ok {
if w.isDone() {
return nil
}
w.c.Wait()
continue
}
return data
}
}
func (w *Waiter) isDone() bool {
select {
case <-w.ctx.Done():
return true
default:
return false
}
}
================================================
FILE: encoder.go
================================================
package zerolog
import (
"net"
"time"
)
type encoder interface {
AppendArrayDelim(dst []byte) []byte
AppendArrayEnd(dst []byte) []byte
AppendArrayStart(dst []byte) []byte
AppendBeginMarker(dst []byte) []byte
AppendBool(dst []byte, val bool) []byte
AppendBools(dst []byte, vals []bool) []byte
AppendBytes(dst, s []byte) []byte
AppendDuration(dst []byte, d time.Duration, unit time.Duration, format string, useInt bool, precision int) []byte
AppendDurations(dst []byte, vals []time.Duration, unit time.Duration, format string, useInt bool, precision int) []byte
AppendEndMarker(dst []byte) []byte
AppendFloat32(dst []byte, val float32, precision int) []byte
AppendFloat64(dst []byte, val float64, precision int) []byte
AppendFloats32(dst []byte, vals []float32, precision int) []byte
AppendFloats64(dst []byte, vals []float64, precision int) []byte
AppendHex(dst, s []byte) []byte
AppendIPAddr(dst []byte, ip net.IP) []byte
AppendIPPrefix(dst []byte, pfx net.IPNet) []byte
AppendInt(dst []byte, val int) []byte
AppendInt16(dst []byte, val int16) []byte
AppendInt32(dst []byte, val int32) []byte
AppendInt64(dst []byte, val int64) []byte
AppendInt8(dst []byte, val int8) []byte
AppendInterface(dst []byte, i interface{}) []byte
AppendInts(dst []byte, vals []int) []byte
AppendInts16(dst []byte, vals []int16) []byte
AppendInts32(dst []byte, vals []int32) []byte
AppendInts64(dst []byte, vals []int64) []byte
AppendInts8(dst []byte, vals []int8) []byte
AppendKey(dst []byte, key string) []byte
AppendLineBreak(dst []byte) []byte
AppendMACAddr(dst []byte, ha net.HardwareAddr) []byte
AppendNil(dst []byte) []byte
AppendObjectData(dst []byte, o []byte) []byte
AppendString(dst []byte, s string) []byte
AppendStrings(dst []byte, vals []string) []byte
AppendTime(dst []byte, t time.Time, format string) []byte
AppendTimes(dst []byte, vals []time.Time, format string) []byte
AppendUint(dst []byte, val uint) []byte
AppendUint16(dst []byte, val uint16) []byte
AppendUint32(dst []byte, val uint32) []byte
AppendUint64(dst []byte, val uint64) []byte
AppendUint8(dst []byte, val uint8) []byte
AppendUints(dst []byte, vals []uint) []byte
AppendUints16(dst []byte, vals []uint16) []byte
AppendUints32(dst []byte, vals []uint32) []byte
AppendUints64(dst []byte, vals []uint64) []byte
AppendUints8(dst []byte, vals []uint8) []byte
}
================================================
FILE: encoder_cbor.go
================================================
// +build binary_log
package zerolog
// This file contains bindings to do binary encoding.
import (
"github.com/rs/zerolog/internal/cbor"
)
var (
_ encoder = (*cbor.Encoder)(nil)
enc = cbor.Encoder{}
)
func init() {
// using closure to reflect the changes at runtime.
cbor.JSONMarshalFunc = func(v interface{}) ([]byte, error) {
return InterfaceMarshalFunc(v)
}
}
func appendJSON(dst []byte, j []byte) []byte {
return cbor.AppendEmbeddedJSON(dst, j)
}
func appendCBOR(dst []byte, c []byte) []byte {
return cbor.AppendEmbeddedCBOR(dst, c)
}
// decodeIfBinaryToString - converts a binary formatted log msg to a
// JSON formatted String Log message.
func decodeIfBinaryToString(in []byte) string {
return cbor.DecodeIfBinaryToString(in)
}
func decodeObjectToStr(in []byte) string {
return cbor.DecodeObjectToStr(in)
}
// decodeIfBinaryToBytes - converts a binary formatted log msg to a
// JSON formatted Bytes Log message.
func decodeIfBinaryToBytes(in []byte) []byte {
return cbor.DecodeIfBinaryToBytes(in)
}
================================================
FILE: encoder_json.go
================================================
// +build !binary_log
package zerolog
// encoder_json.go file contains bindings to generate
// JSON encoded byte stream.
import (
"encoding/base64"
"github.com/rs/zerolog/internal/json"
)
var (
_ encoder = (*json.Encoder)(nil)
enc = json.Encoder{}
)
func init() {
// using closure to reflect the changes at runtime.
json.JSONMarshalFunc = func(v interface{}) ([]byte, error) {
return InterfaceMarshalFunc(v)
}
}
func appendJSON(dst []byte, j []byte) []byte {
return append(dst, j...)
}
func appendCBOR(dst []byte, cbor []byte) []byte {
dst = append(dst, []byte("\"data:application/cbor;base64,")...)
l := len(dst)
enc := base64.StdEncoding
n := enc.EncodedLen(len(cbor))
for i := 0; i < n; i++ {
dst = append(dst, '.')
}
enc.Encode(dst[l:], cbor)
return append(dst, '"')
}
func decodeIfBinaryToString(in []byte) string {
return string(in)
}
func decodeObjectToStr(in []byte) string {
return string(in)
}
func decodeIfBinaryToBytes(in []byte) []byte {
return in
}
================================================
FILE: error_marshal_test.go
================================================
package zerolog
import (
"bytes"
"fmt"
"strings"
"testing"
)
type loggableError struct {
error
}
func (l loggableError) MarshalZerologObject(e *Event) {
if l.error == nil {
return
}
e.Str("l", strings.ToUpper(l.error.Error()))
}
type nonLoggableError struct {
error
line int
}
type wrappedError struct {
error
msg string
}
func (w wrappedError) Error() string {
if w.error == nil {
return w.msg
}
return w.error.Error() + ": " + w.msg
}
type interfaceError struct {
val string
}
func TestArrayErrorMarshalFunc(t *testing.T) {
prefixed := func(s, prefix string) string {
if s == "null" {
return ""
}
return prefix + s + `,`
}
errs := []error{
nil,
fmt.Errorf("failure"),
loggableError{fmt.Errorf("whoops")},
nonLoggableError{fmt.Errorf("oops"), 402},
}
type testCase struct {
name string
marshal func(err error) interface{}
want []string
}
testCases := []testCase{
{
name: "default",
marshal: nil,
want: []string{`null`, `"failure"`, `{"l":"WHOOPS"}`, `"oops"`},
},
{
name: "string",
marshal: func(err error) interface{} {
if err == nil {
return nil
}
return err.Error()
},
want: []string{`null`, `"failure"`, `"whoops"`, `"oops"`},
},
{
name: "loggable",
marshal: func(err error) interface{} {
if err == nil {
return nil
}
return loggableError{err}
},
want: []string{`null`, `{"l":"FAILURE"}`, `{"l":"WHOOPS"}`, `{"l":"OOPS"}`},
},
{
name: "non-loggable",
marshal: func(err error) interface{} {
if err == nil {
return nil
}
return nonLoggableError{err, 404}
},
want: []string{`null`, `"failure"`, `"whoops"`, `"oops"`},
},
{
name: "interface",
marshal: func(err error) interface{} {
var some interfaceError
if err != nil {
some.val = err.Error()
}
var interfaceErr interface{} = some
return interfaceErr
},
want: []string{`{}`, `{}`, `{}`, `{}`},
},
{
name: "nilError",
marshal: func(err error) interface{} {
var errNil error = nil
return errNil
},
want: []string{`null`, `null`, `null`, `null`},
},
{
name: "wrapped error",
marshal: func(err error) interface{} {
if err == nil {
return nil
} else if we, ok := err.(wrappedError); ok {
return we
} else {
return wrappedError{err, "addendum"}
}
},
want: []string{`null`, `"failure: addendum"`, `"whoops: addendum"`, `"oops: addendum"`},
},
}
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
originalErrorMarshalFunc := ErrorMarshalFunc
defer func() {
ErrorMarshalFunc = originalErrorMarshalFunc
}()
if tc.marshal != nil {
ErrorMarshalFunc = tc.marshal
}
t.Run("Err", func(t *testing.T) {
for i, err := range errs {
want := tc.want[i]
t.Run("Arr", func(t *testing.T) {
wants := `[` + want + `]`
a := Arr().Err(err)
if got := decodeObjectToStr(a.write([]byte{})); got != wants {
t.Errorf("%s %d Array.Err(%v)\ngot: %s\nwant: %s", tc.name, i, err, got, wants)
}
})
t.Run("Ctx", func(t *testing.T) {
wants := `{` + prefixed(want, `"error":`) + `"message":"msg"}` + "\n"
out := &bytes.Buffer{}
logger := New(out).With().Err(err).Logger()
logger.Log().Msg("msg")
if got := decodeIfBinaryToString(out.Bytes()); got != wants {
t.Errorf("%s %d Ctx.Err(%v)\ngot: %v\nwant: %v", tc.name, i, err, got, wants)
}
})
t.Run("Event", func(t *testing.T) {
wants := `{` + prefixed(want, `"error":`) + `"message":"msg"}` + "\n"
out := &bytes.Buffer{}
logger := New(out)
logger.Log().Err(err).Msg("msg")
if got := decodeIfBinaryToString(out.Bytes()); got != wants {
t.Errorf("%s %d Event.Err(%v)\ngot: %v\nwant: %v", tc.name, i, err, got, wants)
}
})
t.Run("Fields", func(t *testing.T) {
if i == 0 && tc.want[i] == "{}" {
want = `null`
}
wants := `{"err":` + want + `,"message":"msg"}` + "\n"
out := &bytes.Buffer{}
logger := New(out)
logger.Log().Fields(map[string]interface{}{"err": err}).Msg("msg")
if got := decodeIfBinaryToString(out.Bytes()); got != wants {
t.Errorf("%s %d Event.Fields(%v)\ngot: %v\nwant: %v", tc.name, i, err, got, wants)
}
})
}
})
t.Run("Errs", func(t *testing.T) {
want := `[` + strings.Join(tc.want, ",") + `]`
t.Run("Arr", func(t *testing.T) {
a := Arr().Errs(errs)
if got := decodeObjectToStr(a.write([]byte{})); got != want {
t.Errorf("%s Array.Errs()\ngot: %s\nwant: %s", tc.name, got, want)
}
})
t.Run("Ctx", func(t *testing.T) {
wants := `{"e":` + want + `,"message":"msg"}` + "\n"
out := &bytes.Buffer{}
logger := New(out).With().Errs("e", errs).Logger()
logger.Log().Msg("msg")
if got := decodeIfBinaryToString(out.Bytes()); got != wants {
t.Errorf("%s Ctx.Errs()\ngot: %v\nwant: %v", tc.name, got, wants)
}
})
t.Run("Event", func(t *testing.T) {
wants := `{"e":` + want + `,"message":"msg"}` + "\n"
out := &bytes.Buffer{}
logger := New(out)
logger.Log().Errs("e", errs).Msg("msg")
if got := decodeIfBinaryToString(out.Bytes()); got != wants {
t.Errorf("%s Ctx.Errs()\ngot: %v\nwant: %v", tc.name, got, wants)
}
})
t.Run("Fields", func(t *testing.T) {
wants := `{"e":` + want + `,"message":"msg"}` + "\n"
out := &bytes.Buffer{}
logger := New(out)
logger.Log().Fields(map[string]interface{}{"e": errs}).Msg("msg")
if got := decodeIfBinaryToString(out.Bytes()); got != wants {
t.Errorf("%s Ctx.Errs()\ngot: %v\nwant: %v", tc.name, got, wants)
}
})
})
})
}
}
================================================
FILE: event.go
================================================
package zerolog
import (
"context"
"fmt"
"net"
"os"
"runtime"
"sync"
"time"
)
var eventPool = &sync.Pool{
New: func() interface{} {
return &Event{
buf: make([]byte, 0, 500),
}
},
}
// Event represents a log event. It is instanced by one of the level method of
// Logger and finalized by the Msg or Msgf method.
type Event struct {
buf []byte
w LevelWriter
level Level
done func(msg string)
stack bool // enable error stack trace
ch []Hook // hooks from context
skipFrame int // The number of additional frames to skip when printing the caller.
ctx context.Context // Optional Go context for event
}
func putEvent(e *Event) {
// prevent any subsequent use of the Event contextual state and truncate the buffer
e.w = nil
e.done = nil
e.stack = false
e.ch = nil
e.skipFrame = 0
e.ctx = nil
e.buf = e.buf[:0]
// Proper usage of a sync.Pool requires each entry to have approximately
// the same memory cost. To obtain this property when the stored type
// contains a variably-sized buffer, we add a hard limit on the maximum buffer
// to place back in the pool.
//
// See https://golang.org/issue/23199
const maxSize = 1 << 16 // 64KiB
if cap(e.buf) <= maxSize {
eventPool.Put(e)
}
}
// LogObjectMarshaler provides a strongly-typed and encoding-agnostic interface
// to be implemented by types used with Event/Context's Object methods.
type LogObjectMarshaler interface {
MarshalZerologObject(e *Event)
}
// LogArrayMarshaler provides a strongly-typed and encoding-agnostic interface
// to be implemented by types used with Event/Context's Array methods.
type LogArrayMarshaler interface {
MarshalZerologArray(a *Array)
}
func newEvent(w LevelWriter, level Level, stack bool, ctx context.Context, hooks []Hook) *Event {
e := eventPool.Get().(*Event)
e.buf = e.buf[:0]
e.stack = stack
e.ctx = ctx
e.ch = hooks
e.buf = enc.AppendBeginMarker(e.buf)
e.w = w
e.level = level
e.skipFrame = 0
return e
}
func (e *Event) write() (err error) {
if e == nil {
return nil
}
if e.level != Disabled {
e.buf = enc.AppendEndMarker(e.buf)
e.buf = enc.AppendLineBreak(e.buf)
if e.w != nil {
_, err = e.w.WriteLevel(e.level, e.buf)
}
}
putEvent(e)
return
}
// Enabled return false if the *Event is going to be filtered out by
// log level or sampling.
func (e *Event) Enabled() bool {
return e != nil && e.level != Disabled
}
// Discard disables the event so Msg(f) won't print it.
func (e *Event) Discard() *Event {
if e == nil {
return e
}
e.level = Disabled
return nil
}
// Msg sends the *Event with msg added as the message field if not empty.
//
// NOTICE: once this method is called, the *Event should be disposed.
// Calling Msg twice can have unexpected result.
func (e *Event) Msg(msg string) {
if e == nil {
return
}
e.msg(msg)
}
// Send is equivalent to calling Msg("").
//
// NOTICE: once this method is called, the *Event should be disposed.
func (e *Event) Send() {
if e == nil {
return
}
e.msg("")
}
// Msgf sends the event with formatted msg added as the message field if not empty.
//
// NOTICE: once this method is called, the *Event should be disposed.
// Calling Msgf twice can have unexpected result.
func (e *Event) Msgf(format string, v ...interface{}) {
if e == nil {
return
}
e.msg(fmt.Sprintf(format, v...))
}
func (e *Event) MsgFunc(createMsg func() string) {
if e == nil {
return
}
e.msg(createMsg())
}
func (e *Event) msg(msg string) {
for _, hook := range e.ch {
hook.Run(e, e.level, msg)
}
if msg != "" {
e.buf = enc.AppendString(enc.AppendKey(e.buf, MessageFieldName), msg)
}
if e.done != nil {
defer e.done(msg)
}
if err := e.write(); err != nil {
if ErrorHandler != nil {
ErrorHandler(err)
} else {
fmt.Fprintf(os.Stderr, "zerolog: could not write event: %v\n", err)
}
}
}
// Fields is a helper function to use a map or slice to set fields using type assertion.
// Only map[string]interface{} and []interface{} are accepted. []interface{} must
// alternate string keys and arbitrary values, and extraneous ones are ignored.
func (e *Event) Fields(fields interface{}) *Event {
if e == nil {
return e
}
e.buf = appendFields(e.buf, fields, e.stack, e.ctx, e.ch)
return e
}
// Dict adds the field key with a dict to the event context.
// Use e.CreateDict() to create the dictionary.
func (e *Event) Dict(key string, dict *Event) *Event {
if e != nil {
dict.buf = enc.AppendEndMarker(dict.buf)
e.buf = append(enc.AppendKey(e.buf, key), dict.buf...)
}
putEvent(dict)
return e
}
// CreateDict creates an Event to be used with the *Event.Dict method.
// It preserves the stack, hooks, and context from the parent event.
// Call usual field methods like Str, Int etc to add fields to this
// event and give it as argument the *Event.Dict method.
func (e *Event) CreateDict() *Event {
if e == nil {
return newEvent(nil, DebugLevel, false, nil, nil)
}
return newEvent(nil, DebugLevel, e.stack, e.ctx, e.ch)
}
// Dict creates an Event to be used with the *Event.Dict method.
// Call usual field methods like Str, Int etc to add fields to this
// event and give it as argument the *Event.Dict method.
// NOTE: This function is deprecated because it does not preserve
// the stack, hooks, and context from the parent event.
// Deprecated: Use Event.CreateDict instead.
func Dict() *Event {
return newEvent(nil, DebugLevel, false, nil, nil)
}
// CreateArray creates an Array to be used with the *Event.Array method.
// It preserves the stack, hooks, and context from the parent event.
// Call usual field methods like Str, Int etc to add elements to this
// array and give it as argument the *Event.Array method.
func (e *Event) CreateArray() *Array {
a := Arr()
if e != nil {
a.stack = e.stack
a.ctx = e.ctx
a.ch = e.ch
}
return a
}
// Array adds the field key with an array to the event context.
// Use e.CreateArray() to create the array or pass a type that
// implement the LogArrayMarshaler interface.
func (e *Event) Array(key string, arr LogArrayMarshaler) *Event {
if e == nil {
return e
}
e.buf = enc.AppendKey(e.buf, key)
var a *Array
if aa, ok := arr.(*Array); ok {
a = aa
} else {
a = e.CreateArray()
arr.MarshalZerologArray(a)
}
e.buf = a.write(e.buf)
return e
}
func (e *Event) appendObject(obj LogObjectMarshaler) {
e.buf = enc.AppendBeginMarker(e.buf)
obj.MarshalZerologObject(e)
e.buf = enc.AppendEndMarker(e.buf)
}
// Object marshals an object that implement the LogObjectMarshaler interface.
func (e *Event) Object(key string, obj LogObjectMarshaler) *Event {
if e == nil {
return e
}
e.buf = enc.AppendKey(e.buf, key)
if obj == nil {
e.buf = enc.AppendNil(e.buf)
return e
}
e.appendObject(obj)
return e
}
// Objects adds the field key with obj as an array of objects that implement the LogObjectMarshaler interface.
func (e *Event) Objects(key string, objs []LogObjectMarshaler) *Event {
if e == nil {
return e
}
e.buf = enc.AppendArrayStart(enc.AppendKey(e.buf, key))
for i, obj := range objs {
e.buf = appendObject(e.buf, obj, e.stack, e.ctx, e.ch)
if i < (len(objs) - 1) {
e.buf = enc.AppendArrayDelim(e.buf)
}
}
e.buf = enc.AppendArrayEnd(e.buf)
return e
}
// Func allows an anonymous func to run only if the event is enabled.
func (e *Event) Func(f func(e *Event)) *Event {
if e != nil && e.Enabled() {
f(e)
}
return e
}
// EmbedObject marshals an object that implement the LogObjectMarshaler interface.
func (e *Event) EmbedObject(obj LogObjectMarshaler) *Event {
if e == nil {
return e
}
if obj == nil {
return e
}
obj.MarshalZerologObject(e)
return e
}
// Str adds the field key with val as a string to the *Event context.
func (e *Event) Str(key, val string) *Event {
if e == nil {
return e
}
e.buf = enc.AppendString(enc.AppendKey(e.buf, key), val)
return e
}
// Strs adds the field key with vals as a []string to the *Event context.
func (e *Event) Strs(key string, vals []string) *Event {
if e == nil {
return e
}
e.buf = enc.AppendStrings(enc.AppendKey(e.buf, key), vals)
return e
}
// Stringer adds the field key with val.String() (or null if val is nil)
// to the *Event context.
func (e *Event) Stringer(key string, val fmt.Stringer) *Event {
if e == nil {
return e
}
e.buf = enc.AppendStringer(enc.AppendKey(e.buf, key), val)
return e
}
// Stringers adds the field key with vals where each individual val
// is used as val.String() (or null if val is empty) to the *Event
// context.
func (e *Event) Stringers(key string, vals []fmt.Stringer) *Event {
if e == nil {
return e
}
e.buf = enc.AppendStringers(enc.AppendKey(e.buf, key), vals)
return e
}
// Bytes adds the field key with val as a string to the *Event context.
//
// Runes outside of normal ASCII ranges will be hex-encoded in the resulting
// JSON.
func (e *Event) Bytes(key string, val []byte) *Event {
if e == nil {
return e
}
e.buf = enc.AppendBytes(enc.AppendKey(e.buf, key), val)
return e
}
// Hex adds the field key with val as a hex string to the *Event context.
func (e *Event) Hex(key string, val []byte) *Event {
if e == nil {
return e
}
e.buf = enc.AppendHex(enc.AppendKey(e.buf, key), val)
return e
}
// RawJSON adds already encoded JSON to the log line under key.
//
// No sanity check is performed on b; it must not contain carriage returns and
// be valid JSON.
func (e *Event) RawJSON(key string, b []byte) *Event {
if e == nil {
return e
}
e.buf = appendJSON(enc.AppendKey(e.buf, key), b)
return e
}
// RawCBOR adds already encoded CBOR to the log line under key.
//
// No sanity check is performed on b
// Note: The full featureset of CBOR is supported as data will not be mapped to json but stored as data-url
func (e *Event) RawCBOR(key string, b []byte) *Event {
if e == nil {
return e
}
e.buf = appendCBOR(enc.AppendKey(e.buf, key), b)
return e
}
// AnErr adds the field key with serialized err to the *Event context.
// If err is nil, no field is added.
func (e *Event) AnErr(key string, err error) *Event {
if e == nil {
return e
}
switch m := ErrorMarshalFunc(err).(type) {
case nil:
return e
case LogObjectMarshaler:
return e.Object(key, m)
case error:
if isNilValue(m) {
return e
}
return e.Str(key, m.Error())
case string:
return e.Str(key, m)
default:
return e.Interface(key, m)
}
}
// Errs adds the field key with errs as an array of serialized errors to the
// *Event context.
func (e *Event) Errs(key string, errs []error) *Event {
if e == nil {
return e
}
arr := e.CreateArray().Errs(errs)
return e.Array(key, arr)
}
// Err adds the field "error" with serialized err to the *Event context.
// If err is nil, no field is added.
//
// To customize the key name, change zerolog.ErrorFieldName.
//
// If Stack() has been called before and zerolog.ErrorStackMarshaler is defined,
// the err is passed to ErrorStackMarshaler and the result is appended to the
// zerolog.ErrorStackFieldName.
func (e *Event) Err(err error) *Event {
if e == nil {
return e
}
if e.stack && ErrorStackMarshaler != nil {
switch m := ErrorStackMarshaler(err).(type) {
case nil:
return e
case LogObjectMarshaler:
e = e.Object(ErrorStackFieldName, m)
case error:
e = e.Str(ErrorStackFieldName, m.Error())
case string:
e = e.Str(ErrorStackFieldName, m)
default:
e = e.Interface(ErrorStackFieldName, m)
}
}
return e.AnErr(ErrorFieldName, err)
}
// Stack enables stack trace printing for the error passed to Err().
//
// ErrorStackMarshaler must be set for this method to do something.
func (e *Event) Stack() *Event {
if e != nil {
e.stack = true
}
return e
}
// Ctx adds the Go Context to the *Event context. The context is not rendered
// in the output message, but is available to hooks and to Func() calls via the
// GetCtx() accessor. A typical use case is to extract tracing information from
// the Go Ctx.
func (e *Event) Ctx(ctx context.Context) *Event {
if e != nil {
e.ctx = ctx
}
return e
}
// GetCtx retrieves the Go context.Context which is optionally stored in the
// Event. This allows Hooks and functions passed to Func() to retrieve values
// which are stored in the context.Context. This can be useful in tracing,
// where span information is commonly propagated in the context.Context.
func (e *Event) GetCtx() context.Context {
if e == nil || e.ctx == nil {
return context.Background()
}
return e.ctx
}
// Bool adds the field key with val as a bool to the *Event context.
func (e *Event) Bool(key string, b bool) *Event {
if e == nil {
return e
}
e.buf = enc.AppendBool(enc.AppendKey(e.buf, key), b)
return e
}
// Bools adds the field key with val as a []bool to the *Event context.
func (e *Event) Bools(key string, b []bool) *Event {
if e == nil {
return e
}
e.buf = enc.AppendBools(enc.AppendKey(e.buf, key), b)
return e
}
// Int adds the field key with i as a int to the *Event context.
func (e *Event) Int(key string, i int) *Event {
if e == nil {
return e
}
e.buf = enc.AppendInt(enc.AppendKey(e.buf, key), i)
return e
}
// Ints adds the field key with i as a []int to the *Event context.
func (e *Event) Ints(key string, i []int) *Event {
if e == nil {
return e
}
e.buf = enc.AppendInts(enc.AppendKey(e.buf, key), i)
return e
}
// Int8 adds the field key with i as a int8 to the *Event context.
func (e *Event) Int8(key string, i int8) *Event {
if e == nil {
return e
}
e.buf = enc.AppendInt8(enc.AppendKey(e.buf, key), i)
return e
}
// Ints8 adds the field key with i as a []int8 to the *Event context.
func (e *Event) Ints8(key string, i []int8) *Event {
if e == nil {
return e
}
e.buf = enc.AppendInts8(enc.AppendKey(e.buf, key), i)
return e
}
// Int16 adds the field key with i as a int16 to the *Event context.
func (e *Event) Int16(key string, i int16) *Event {
if e == nil {
return e
}
e.buf = enc.AppendInt16(enc.AppendKey(e.buf, key), i)
return e
}
// Ints16 adds the field key with i as a []int16 to the *Event context.
func (e *Event) Ints16(key string, i []int16) *Event {
if e == nil {
return e
}
e.buf = enc.AppendInts16(enc.AppendKey(e.buf, key), i)
return e
}
// Int32 adds the field key with i as a int32 to the *Event context.
func (e *Event) Int32(key string, i int32) *Event {
if e == nil {
return e
}
e.buf = enc.AppendInt32(enc.AppendKey(e.buf, key), i)
return e
}
// Ints32 adds the field key with i as a []int32 to the *Event context.
func (e *Event) Ints32(key string, i []int32) *Event {
if e == nil {
return e
}
e.buf = enc.AppendInts32(enc.AppendKey(e.buf, key), i)
return e
}
// Int64 adds the field key with i as a int64 to the *Event context.
func (e *Event) Int64(key string, i int64) *Event {
if e == nil {
return e
}
e.buf = enc.AppendInt64(enc.AppendKey(e.buf, key), i)
return e
}
// Ints64 adds the field key with i as a []int64 to the *Event context.
func (e *Event) Ints64(key string, i []int64) *Event {
if e == nil {
return e
}
e.buf = enc.AppendInts64(enc.AppendKey(e.buf, key), i)
return e
}
// Uint adds the field key with i as a uint to the *Event context.
func (e *Event) Uint(key string, i uint) *Event {
if e == nil {
return e
}
e.buf = enc.AppendUint(enc.AppendKey(e.buf, key), i)
return e
}
// Uints adds the field key with i as a []int to the *Event context.
func (e *Event) Uints(key string, i []uint) *Event {
if e == nil {
return e
}
e.buf = enc.AppendUints(enc.AppendKey(e.buf, key), i)
return e
}
// Uint8 adds the field key with i as a uint8 to the *Event context.
func (e *Event) Uint8(key string, i uint8) *Event {
if e == nil {
return e
}
e.buf = enc.AppendUint8(enc.AppendKey(e.buf, key), i)
return e
}
// Uints8 adds the field key with i as a []int8 to the *Event context.
func (e *Event) Uints8(key string, i []uint8) *Event {
if e == nil {
return e
}
e.buf = enc.AppendUints8(enc.AppendKey(e.buf, key), i)
return e
}
// Uint16 adds the field key with i as a uint16 to the *Event context.
func (e *Event) Uint16(key string, i uint16) *Event {
if e == nil {
return e
}
e.buf = enc.AppendUint16(enc.AppendKey(e.buf, key), i)
return e
}
// Uints16 adds the field key with i as a []int16 to the *Event context.
func (e *Event) Uints16(key string, i []uint16) *Event {
if e == nil {
return e
}
e.buf = enc.AppendUints16(enc.AppendKey(e.buf, key), i)
return e
}
// Uint32 adds the field key with i as a uint32 to the *Event context.
func (e *Event) Uint32(key string, i uint32) *Event {
if e == nil {
return e
}
e.buf = enc.AppendUint32(enc.AppendKey(e.buf, key), i)
return e
}
// Uints32 adds the field key with i as a []int32 to the *Event context.
func (e *Event) Uints32(key string, i []uint32) *Event {
if e == nil {
return e
}
e.buf = enc.AppendUints32(enc.AppendKey(e.buf, key), i)
return e
}
// Uint64 adds the field key with i as a uint64 to the *Event context.
func (e *Event) Uint64(key string, i uint64) *Event {
if e == nil {
return e
}
e.buf = enc.AppendUint64(enc.AppendKey(e.buf, key), i)
return e
}
// Uints64 adds the field key with i as a []int64 to the *Event context.
func (e *Event) Uints64(key string, i []uint64) *Event {
if e == nil {
return e
}
e.buf = enc.AppendUints64(enc.AppendKey(e.buf, key), i)
return e
}
// Float32 adds the field key with f as a float32 to the *Event context.
func (e *Event) Float32(key string, f float32) *Event {
if e == nil {
return e
}
e.buf = enc.AppendFloat32(enc.AppendKey(e.buf, key), f, FloatingPointPrecision)
return e
}
// Floats32 adds the field key with f as a []float32 to the *Event context.
func (e *Event) Floats32(key string, f []float32) *Event {
if e == nil {
return e
}
e.buf = enc.AppendFloats32(enc.AppendKey(e.buf, key), f, FloatingPointPrecision)
return e
}
// Float64 adds the field key with f as a float64 to the *Event context.
func (e *Event) Float64(key string, f float64) *Event {
if e == nil {
return e
}
e.buf = enc.AppendFloat64(enc.AppendKey(e.buf, key), f, FloatingPointPrecision)
return e
}
// Floats64 adds the field key with f as a []float64 to the *Event context.
func (e *Event) Floats64(key string, f []float64) *Event {
if e == nil {
return e
}
e.buf = enc.AppendFloats64(enc.AppendKey(e.buf, key), f, FloatingPointPrecision)
return e
}
// Timestamp adds the current local time as UNIX timestamp to the *Event context with the "time" key.
// To customize the key name, change zerolog.TimestampFieldName.
//
// NOTE: It won't dedupe the "time" key if the *Event (or *Context) has one
// already.
func (e *Event) Timestamp() *Event {
if e == nil {
return e
}
e.buf = enc.AppendTime(enc.AppendKey(e.buf, TimestampFieldName), TimestampFunc(), TimeFieldFormat)
return e
}
// Time adds the field key with t formatted as string using zerolog.TimeFieldFormat.
func (e *Event) Time(key string, t time.Time) *Event {
if e == nil {
return e
}
e.buf = enc.AppendTime(enc.AppendKey(e.buf, key), t, TimeFieldFormat)
return e
}
// Times adds the field key with t formatted as string using zerolog.TimeFieldFormat.
func (e *Event) Times(key string, t []time.Time) *Event {
if e == nil {
return e
}
e.buf = enc.AppendTimes(enc.AppendKey(e.buf, key), t, TimeFieldFormat)
return e
}
// Dur adds the field key with duration d stored as zerolog.DurationFieldUnit.
// If zerolog.DurationFieldInteger is true, durations are rendered as integer
// instead of float.
func (e *Event) Dur(key string, d time.Duration) *Event {
if e == nil {
return e
}
e.buf = enc.AppendDuration(enc.AppendKey(e.buf, key), d, DurationFieldUnit, DurationFieldFormat, DurationFieldInteger, FloatingPointPrecision)
return e
}
// Durs adds the field key with duration d stored as zerolog.DurationFieldUnit.
// If zerolog.DurationFieldInteger is true, durations are rendered as integer
// instead of float.
func (e *Event) Durs(key string, d []time.Duration) *Event {
if e == nil {
return e
}
e.buf = enc.AppendDurations(enc.AppendKey(e.buf, key), d, DurationFieldUnit, DurationFieldFormat, DurationFieldInteger, FloatingPointPrecision)
return e
}
// TimeDiff adds the field key with positive duration between time t and start.
// If time t is not greater than start, duration will be 0.
// Duration format follows the same principle as Dur().
func (e *Event) TimeDiff(key string, t time.Time, start time.Time) *Event {
if e == nil {
return e
}
var d time.Duration
if t.After(start) {
d = t.Sub(start)
}
e.buf = enc.AppendDuration(enc.AppendKey(e.buf, key), d, DurationFieldUnit, DurationFieldFormat, DurationFieldInteger, FloatingPointPrecision)
return e
}
// Any is a wrapper around Event.Interface.
func (e *Event) Any(key string, i interface{}) *Event {
return e.Interface(key, i)
}
// Interface adds the field key with i marshaled using reflection.
func (e *Event) Interface(key string, i interface{}) *Event {
if e == nil {
return e
}
if obj, ok := i.(LogObjectMarshaler); ok {
return e.Object(key, obj)
}
e.buf = enc.AppendInterface(enc.AppendKey(e.buf, key), i)
return e
}
// Type adds the field key with val's type using reflection.
func (e *Event) Type(key string, val interface{}) *Event {
if e == nil {
return e
}
e.buf = enc.AppendType(enc.AppendKey(e.buf, key), val)
return e
}
// CallerSkipFrame instructs any future Caller calls to skip the specified number of frames.
// This includes those added via hooks from the context.
func (e *Event) CallerSkipFrame(skip int) *Event {
if e == nil {
return e
}
e.skipFrame += skip
return e
}
// Caller adds the file:line of the caller with the zerolog.CallerFieldName key.
// The argument skip is the number of stack frames to ascend
// Skip If not passed, use the global variable CallerSkipFrameCount
func (e *Event) Caller(skip ...int) *Event {
sk := CallerSkipFrameCount
if len(skip) > 0 {
sk = skip[0] + CallerSkipFrameCount
}
return e.caller(sk)
}
func (e *Event) caller(skip int) *Event {
if e == nil {
return e
}
if pc, file, line, ok := runtime.Caller(skip + e.skipFrame); ok {
e.buf = enc.AppendString(enc.AppendKey(e.buf, CallerFieldName), CallerMarshalFunc(pc, file, line))
}
return e
}
// IPAddr adds the field key with ip as a net.IP IPv4 or IPv6 Address to the event
func (e *Event) IPAddr(key string, ip net.IP) *Event {
if e == nil {
return e
}
e.buf = enc.AppendIPAddr(enc.AppendKey(e.buf, key), ip)
return e
}
// IPAddrs adds the field key with ip as a net.IP array of IPv4 or IPv6 Address to the event
func (e *Event) IPAddrs(key string, ip []net.IP) *Event {
if e == nil {
return e
}
e.buf = enc.AppendIPAddrs(enc.AppendKey(e.buf, key), ip)
return e
}
// IPPrefix adds the field key with pfx as a net.IPNet IPv4 or IPv6 Prefix (address and mask) to the event
func (e *Event) IPPrefix(key string, pfx net.IPNet) *Event {
if e == nil {
return e
}
e.buf = enc.AppendIPPrefix(enc.AppendKey(e.buf, key), pfx)
return e
}
// IPPrefixes the field key with pfx as a net.IPNet array of IPv4 or IPv6 Prefixes (address and mask) to the event
func (e *Event) IPPrefixes(key string, pfx []net.IPNet) *Event {
if e == nil {
return e
}
e.buf = enc.AppendIPPrefixes(enc.AppendKey(e.buf, key), pfx)
return e
}
// MACAddr the field key with ha as a net.HardwareAddr MAC address to the event
func (e *Event) MACAddr(key string, ha net.HardwareAddr) *Event {
if e == nil {
return e
}
e.buf = enc.AppendMACAddr(enc.AppendKey(e.buf, key), ha)
return e
}
================================================
FILE: event_test.go
================================================
//go:build !binary_log
// +build !binary_log
package zerolog
import (
"bytes"
"context"
"errors"
"io"
"os"
"strings"
"testing"
)
type nilError struct{}
func (nilError) Error() string {
return "nope"
}
func TestEvent_AnErr(t *testing.T) {
tests := []struct {
name string
err error
want string
}{
{"nil", nil, `{}`},
{"error", errors.New("test"), `{"err":"test"}`},
{"nil interface", func() *nilError { return nil }(), `{}`},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
var buf bytes.Buffer
e := newEvent(LevelWriterAdapter{&buf}, DebugLevel, false, nil, nil)
e = e.AnErr("err", tt.err)
err := e.write()
if err != nil {
t.Errorf("Event.AnErr() error: %v", err)
}
if got, want := strings.TrimSpace(buf.String()), tt.want; got != want {
t.Errorf("Event.AnErr() = %v, want %v", got, want)
}
})
}
}
func TestEvent_writeWithNil(t *testing.T) {
var e *Event = nil
got := e.write()
var want *Event = nil
if got != nil {
t.Errorf("Event.write() = %v, want %v", got, want)
}
}
type loggableObject struct {
member string
}
func (o loggableObject) MarshalZerologObject(e *Event) {
e.Str("member", o.member)
}
func TestEvent_Object(t *testing.T) {
t.Run("ObjectWithNil", func(t *testing.T) {
var buf bytes.Buffer
e := newEvent(LevelWriterAdapter{&buf}, DebugLevel, false, nil, nil)
e = e.Object("obj", nil)
err := e.write()
if err != nil {
t.Errorf("Event.Object() error: %v", err)
}
want := `{"obj":null}`
got := strings.TrimSpace(buf.String())
if got != want {
t.Errorf("Event.Object()\ngot: %s\nwant: %s", got, want)
}
})
t.Run("EmbedObjectWithNil", func(t *testing.T) {
var buf bytes.Buffer
e := newEvent(LevelWriterAdapter{&buf}, DebugLevel, false, nil, nil)
e = e.EmbedObject(nil)
err := e.write()
if err != nil {
t.Errorf("Event.EmbedObject() error: %v", err)
}
want := "{}"
got := strings.TrimSpace(buf.String())
if got != want {
t.Errorf("Event.EmbedObject()\ngot: %s\nwant: %s", got, want)
}
})
type contextKeyType struct{}
var contextKey = contextKeyType{}
called := false
ctxHook := HookFunc(func(e *Event, level Level, message string) {
called = true
ctx := e.GetCtx()
if ctx == nil {
t.Errorf("expected context to be set in Event")
}
val := ctx.Value(contextKey)
if val == nil {
t.Errorf("expected context value, got %v", val)
}
e.Str("ctxValue", val.(string))
e.Bool("stackValue", e.stack)
})
t.Run("ObjectWithFullContext", func(t *testing.T) {
called = false
ctx := context.WithValue(context.Background(), contextKey, "ctx-object")
var buf bytes.Buffer
e := newEvent(LevelWriterAdapter{&buf}, DebugLevel, true, ctx, []Hook{ctxHook})
e = e.Object("obj", loggableObject{member: "object-value"})
e.Msg("hello")
if !called {
t.Errorf("hook was not called")
}
want := `{"obj":{"member":"object-value"},"ctxValue":"ctx-object","stackValue":true,"message":"hello"}`
got := strings.TrimSpace(buf.String())
if got != want {
t.Errorf("Event.EmbedObject()\ngot: %s\nwant: %s", got, want)
}
})
t.Run("EmbedObjectWithFullContext", func(t *testing.T) {
called = false
ctx := context.WithValue(context.Background(), contextKey, "ctx-embed")
var buf bytes.Buffer
e := newEvent(LevelWriterAdapter{&buf}, DebugLevel, false, ctx, []Hook{ctxHook})
e = e.EmbedObject(loggableObject{member: "embedded-value"})
e.Msg("hello")
if !called {
t.Errorf("hook was not called")
}
want := `{"member":"embedded-value","ctxValue":"ctx-embed","stackValue":false,"message":"hello"}`
got := strings.TrimSpace(buf.String())
if got != want {
t.Errorf("Event.EmbedObject()\ngot: %s\nwant: %s", got, want)
}
})
}
func TestEvent_WithNilEvent(t *testing.T) {
// coverage for nil Event receiver for all types
var e *Event = nil
fixtures := makeFieldFixtures()
types := map[string]func() *Event{
"Array": func() *Event {
arr := e.CreateArray()
return e.Array("k", arr)
},
"Bool": func() *Event {
return e.Bool("k", fixtures.Bools[0])
},
"Bools": func() *Event {
return e.Bools("k", fixtures.Bools)
},
"Fields": func() *Event {
return e.Fields(fixtures)
},
"Int": func() *Event {
return e.Int("k", fixtures.Ints[0])
},
"Ints": func() *Event {
return e.Ints("k", fixtures.Ints)
},
"Int8": func() *Event {
return e.Int8("k", fixtures.Ints8[0])
},
"Ints8": func() *Event {
return e.Ints8("k", fixtures.Ints8)
},
"Int16": func() *Event {
return e.Int16("k", fixtures.Ints16[0])
},
"Ints16": func() *Event {
return e.Ints16("k", fixtures.Ints16)
},
"Int32": func() *Event {
return e.Int32("k", fixtures.Ints32[0])
},
"Ints32": func() *Event {
return e.Ints32("k", fixtures.Ints32)
},
"Int64": func() *Event {
return e.Int64("k", fixtures.Ints64[0])
},
"Ints64": func() *Event {
return e.Ints64("k", fixtures.Ints64)
},
"Uint": func() *Event {
return e.Uint("k", fixtures.Uints[0])
},
"Uints": func() *Event {
return e.Uints("k", fixtures.Uints)
},
"Uint8": func() *Event {
return e.Uint8("k", fixtures.Uints8[0])
},
"Uints8": func() *Event {
return e.Uints8("k", fixtures.Uints8)
},
"Uint16": func() *Event {
return e.Uint16("k", fixtures.Uints16[0])
},
"Uints16": func() *Event {
return e.Uints16("k", fixtures.Uints16)
},
"Uint32": func() *Event {
return e.Uint32("k", fixtures.Uints32[0])
},
"Uints32": func() *Event {
return e.Uints32("k", fixtures.Uints32)
},
"Uint64": func() *Event {
return e.Uint64("k", fixtures.Uints64[0])
},
"Uints64": func() *Event {
return e.Uints64("k", fixtures.Uints64)
},
"Float64": func() *Event {
return e.Float64("k", fixtures.Floats64[0])
},
"Floats64": func() *Event {
return e.Floats64("k", fixtures.Floats64)
},
"Float32": func() *Event {
return e.Float32("k", fixtures.Floats32[0])
},
"Floats32": func() *Event {
return e.Floats32("k", fixtures.Floats32)
},
"RawCBOR": func() *Event {
return e.RawCBOR("k", fixtures.RawCBOR)
},
"RawJSON": func() *Event {
return e.RawJSON("k", fixtures.RawJSONs[0])
},
"Str": func() *Event {
return e.Str("k", fixtures.Strings[0])
},
"Strs": func() *Event {
return e.Strs("k", fixtures.Strings)
},
"Stringers": func() *Event {
return e.Stringers("k", fixtures.Stringers)
},
"Err": func() *Event {
return e.Err(fixtures.Errs[0])
},
"Errs": func() *Event {
return e.Errs("k", fixtures.Errs)
},
"Ctx": func() *Event {
return e.Ctx(fixtures.Ctx)
},
"Time": func() *Event {
return e.Time("k", fixtures.Times[0])
},
"Times": func() *Event {
return e.Times("k", fixtures.Times)
},
"Dict": func() *Event {
d := e.CreateDict()
d.Str("greeting", "hello")
return e.Dict("k", d)
},
"Dur": func() *Event {
return e.Dur("k", fixtures.Durations[0])
},
"Durs": func() *Event {
return e.Durs("k", fixtures.Durations)
},
"Interface": func() *Event {
return e.Interface("k", fixtures.Interfaces[0])
},
"Interfaces": func() *Event {
return e.Interface("k", fixtures.Interfaces)
},
"Interface(Object)": func() *Event {
return e.Interface("k", fixtures.Objects[0])
},
"Interface(Objects)": func() *Event {
return e.Interface("k", fixtures.Objects)
},
"Object": func() *Event {
return e.Object("k", fixtures.Objects[0])
},
"Objects": fun
gitextract_uhbtc_lf/ ├── .github/ │ ├── dependabot.yml │ └── workflows/ │ └── test.yml ├── .gitignore ├── CONTRIBUTING.md ├── LICENSE ├── README.md ├── array.go ├── array_test.go ├── benchmark_test.go ├── binary_test.go ├── cmd/ │ ├── lint/ │ │ ├── README.md │ │ ├── go.mod │ │ ├── go.sum │ │ └── lint.go │ └── prettylog/ │ ├── README.md │ └── prettylog.go ├── console.go ├── console_test.go ├── context.go ├── context_test.go ├── ctx.go ├── ctx_test.go ├── diode/ │ ├── diode.go │ ├── diode_example_test.go │ ├── diode_test.go │ └── internal/ │ └── diodes/ │ ├── README │ ├── many_to_one.go │ ├── one_to_one.go │ ├── poller.go │ └── waiter.go ├── encoder.go ├── encoder_cbor.go ├── encoder_json.go ├── error_marshal_test.go ├── event.go ├── event_test.go ├── example.jsonl ├── fields.go ├── fixtures_test.go ├── globals.go ├── go.mod ├── go.sum ├── go112.go ├── hlog/ │ ├── hlog.go │ ├── hlog_example_test.go │ ├── hlog_test.go │ └── internal/ │ └── mutil/ │ ├── LICENSE │ ├── mutil.go │ └── writer_proxy.go ├── hook.go ├── hook_test.go ├── internal/ │ ├── cbor/ │ │ ├── README.md │ │ ├── base.go │ │ ├── base_test.go │ │ ├── cbor.go │ │ ├── decode_stream.go │ │ ├── decoder_test.go │ │ ├── examples/ │ │ │ ├── genLog.go │ │ │ └── makefile │ │ ├── string.go │ │ ├── string_test.go │ │ ├── time.go │ │ ├── time_test.go │ │ ├── types.go │ │ ├── types_64_test.go │ │ └── types_test.go │ ├── json/ │ │ ├── base.go │ │ ├── base_test.go │ │ ├── bytes.go │ │ ├── bytes_test.go │ │ ├── float_test.go │ │ ├── int_test.go │ │ ├── string.go │ │ ├── string_test.go │ │ ├── time.go │ │ ├── time_test.go │ │ ├── types.go │ │ └── types_test.go │ └── testcases.go ├── journald/ │ ├── journald.go │ └── journald_test.go ├── log/ │ ├── log.go │ └── log_example_test.go ├── log.go ├── log_example_test.go ├── log_test.go ├── not_go112.go ├── pkgerrors/ │ ├── stacktrace.go │ └── stacktrace_test.go ├── sampler.go ├── sampler_test.go ├── slog.go ├── slog_test.go ├── syslog.go ├── syslog_test.go ├── writer.go └── writer_test.go
SYMBOL INDEX (1211 symbols across 79 files)
FILE: array.go
type Array (line 20) | type Array struct
method MarshalZerologArray (line 61) | func (*Array) MarshalZerologArray(*Array) {
method write (line 65) | func (a *Array) write(dst []byte) []byte {
method Object (line 77) | func (a *Array) Object(obj LogObjectMarshaler) *Array {
method Str (line 83) | func (a *Array) Str(val string) *Array {
method Bytes (line 89) | func (a *Array) Bytes(val []byte) *Array {
method Hex (line 95) | func (a *Array) Hex(val []byte) *Array {
method RawJSON (line 101) | func (a *Array) RawJSON(val []byte) *Array {
method Err (line 107) | func (a *Array) Err(err error) *Array {
method Errs (line 127) | func (a *Array) Errs(errs []error) *Array {
method Bool (line 148) | func (a *Array) Bool(b bool) *Array {
method Int (line 154) | func (a *Array) Int(i int) *Array {
method Int8 (line 160) | func (a *Array) Int8(i int8) *Array {
method Int16 (line 166) | func (a *Array) Int16(i int16) *Array {
method Int32 (line 172) | func (a *Array) Int32(i int32) *Array {
method Int64 (line 178) | func (a *Array) Int64(i int64) *Array {
method Uint (line 184) | func (a *Array) Uint(i uint) *Array {
method Uint8 (line 190) | func (a *Array) Uint8(i uint8) *Array {
method Uint16 (line 196) | func (a *Array) Uint16(i uint16) *Array {
method Uint32 (line 202) | func (a *Array) Uint32(i uint32) *Array {
method Uint64 (line 208) | func (a *Array) Uint64(i uint64) *Array {
method Float32 (line 214) | func (a *Array) Float32(f float32) *Array {
method Float64 (line 220) | func (a *Array) Float64(f float64) *Array {
method Time (line 226) | func (a *Array) Time(t time.Time) *Array {
method Dur (line 232) | func (a *Array) Dur(d time.Duration) *Array {
method Interface (line 238) | func (a *Array) Interface(i interface{}) *Array {
method IPAddr (line 247) | func (a *Array) IPAddr(ip net.IP) *Array {
method IPPrefix (line 253) | func (a *Array) IPPrefix(pfx net.IPNet) *Array {
method MACAddr (line 259) | func (a *Array) MACAddr(ha net.HardwareAddr) *Array {
method Dict (line 265) | func (a *Array) Dict(dict *Event) *Array {
method Type (line 273) | func (a *Array) Type(val interface{}) *Array {
function putArray (line 27) | func putArray(a *Array) {
function Arr (line 50) | func Arr() *Array {
FILE: array_test.go
function TestArray (line 10) | func TestArray(t *testing.T) {
function TestArray_MarshalZerologArray (line 63) | func TestArray_MarshalZerologArray(t *testing.T) {
FILE: benchmark_test.go
function BenchmarkLogEmpty (line 15) | func BenchmarkLogEmpty(b *testing.B) {
function BenchmarkDisabled (line 25) | func BenchmarkDisabled(b *testing.B) {
function BenchmarkInfo (line 35) | func BenchmarkInfo(b *testing.B) {
function BenchmarkContextFields (line 45) | func BenchmarkContextFields(b *testing.B) {
function BenchmarkContextAppend (line 60) | func BenchmarkContextAppend(b *testing.B) {
function BenchmarkLogFields (line 72) | func BenchmarkLogFields(b *testing.B) {
function BenchmarkLogArrayObject (line 87) | func BenchmarkLogArrayObject(b *testing.B) {
function BenchmarkLogFieldType (line 103) | func BenchmarkLogFieldType(b *testing.B) {
function BenchmarkContextFieldType (line 227) | func BenchmarkContextFieldType(b *testing.B) {
FILE: binary_test.go
function ExampleLogger_With (line 16) | func ExampleLogger_With() {
function ExampleLogger_Level (line 29) | func ExampleLogger_Level() {
function ExampleLogger_Sample (line 40) | func ExampleLogger_Sample() {
type LevelNameHook1 (line 54) | type LevelNameHook1 struct
method Run (line 56) | func (h LevelNameHook1) Run(e *Event, l Level, msg string) {
type MessageHook (line 64) | type MessageHook
method Run (line 66) | func (h MessageHook) Run(e *Event, l Level, msg string) {
function ExampleLogger_Hook (line 70) | func ExampleLogger_Hook() {
function ExampleLogger_Print (line 83) | func ExampleLogger_Print() {
function ExampleLogger_Printf (line 93) | func ExampleLogger_Printf() {
function ExampleLogger_Trace (line 103) | func ExampleLogger_Trace() {
function ExampleLogger_Debug (line 116) | func ExampleLogger_Debug() {
function ExampleLogger_Info (line 129) | func ExampleLogger_Info() {
function ExampleLogger_Warn (line 142) | func ExampleLogger_Warn() {
function ExampleLogger_Error (line 154) | func ExampleLogger_Error() {
function ExampleLogger_WithLevel (line 166) | func ExampleLogger_WithLevel() {
function ExampleLogger_Write (line 177) | func ExampleLogger_Write() {
function ExampleLogger_Log (line 192) | func ExampleLogger_Log() {
function ExampleEvent_Dict (line 205) | func ExampleEvent_Dict() {
type User (line 222) | type User struct
method MarshalZerologObject (line 228) | func (u User) MarshalZerologObject(e *Event) {
type Users (line 234) | type Users
method MarshalZerologArray (line 237) | func (uu Users) MarshalZerologArray(a *Array) {
function ExampleEvent_Array (line 243) | func ExampleEvent_Array() {
function ExampleEvent_Array_object (line 260) | func ExampleEvent_Array_object() {
function ExampleEvent_Object (line 279) | func ExampleEvent_Object() {
function ExampleContext_Objects (line 295) | func ExampleContext_Objects() {
function ExampleEvent_EmbedObject (line 314) | func ExampleEvent_EmbedObject() {
function ExampleEvent_Interface (line 329) | func ExampleEvent_Interface() {
function ExampleEvent_Dur (line 348) | func ExampleEvent_Dur() {
function ExampleEvent_Durs (line 363) | func ExampleEvent_Durs() {
function ExampleEvent_Fields_map (line 381) | func ExampleEvent_Fields_map() {
function ExampleEvent_Fields_slice (line 399) | func ExampleEvent_Fields_slice() {
function ExampleContext_Dict (line 417) | func ExampleContext_Dict() {
function ExampleContext_Array (line 433) | func ExampleContext_Array() {
function ExampleContext_Array_object (line 449) | func ExampleContext_Array_object() {
type Price (line 468) | type Price struct
method MarshalZerologObject (line 474) | func (p Price) MarshalZerologObject(e *Event) {
function ExampleContext_EmbedObject (line 484) | func ExampleContext_EmbedObject() {
function ExampleContext_Object (line 498) | func ExampleContext_Object() {
function ExampleContext_Interface (line 514) | func ExampleContext_Interface() {
function ExampleContext_Dur (line 533) | func ExampleContext_Dur() {
function ExampleContext_Durs (line 548) | func ExampleContext_Durs() {
function ExampleContext_Fields_map (line 566) | func ExampleContext_Fields_map() {
function ExampleContext_Fields_slice (line 584) | func ExampleContext_Fields_slice() {
function ExampleContext_IPAddr (line 602) | func ExampleContext_IPAddr() {
function ExampleContext_IPPrefix (line 618) | func ExampleContext_IPPrefix() {
function ExampleContext_MACAddr (line 634) | func ExampleContext_MACAddr() {
FILE: cmd/lint/lint.go
function init (line 25) | func init() {
function main (line 42) | func main() {
function getEvent (line 81) | func getEvent(p *loader.Program) types.Type {
function getSelectionsWithReceiverType (line 95) | func getSelectionsWithReceiverType(p *loader.Program, targetType types.T...
function hasBadFinisher (line 124) | func hasBadFinisher(p *loader.Program, s selection) bool {
type arrayFlag (line 160) | type arrayFlag
method String (line 162) | func (i *arrayFlag) String() string {
method Set (line 166) | func (i *arrayFlag) Set(value string) error {
type selection (line 171) | type selection struct
FILE: cmd/prettylog/prettylog.go
function isInputFromPipe (line 15) | func isInputFromPipe() bool {
function processInput (line 20) | func processInput(reader io.Reader, writer io.Writer) error {
function main (line 37) | func main() {
FILE: console.go
constant colorBlack (line 20) | colorBlack = iota + 30
constant colorRed (line 21) | colorRed
constant colorGreen (line 22) | colorGreen
constant colorYellow (line 23) | colorYellow
constant colorBlue (line 24) | colorBlue
constant colorMagenta (line 25) | colorMagenta
constant colorCyan (line 26) | colorCyan
constant colorWhite (line 27) | colorWhite
constant colorBold (line 29) | colorBold = 1
constant colorDarkGray (line 30) | colorDarkGray = 90
constant unknownLevel (line 32) | unknownLevel = "???"
constant consoleDefaultTimeFormat (line 44) | consoleDefaultTimeFormat = time.Kitchen
type Formatter (line 48) | type Formatter
type FormatterByFieldName (line 52) | type FormatterByFieldName
type ConsoleWriter (line 56) | type ConsoleWriter struct
method Write (line 122) | func (w ConsoleWriter) Write(p []byte) (n int, err error) {
method Close (line 178) | func (w ConsoleWriter) Close() error {
method writeFields (line 186) | func (w ConsoleWriter) writeFields(evt map[string]interface{}, buf *by...
method writePart (line 290) | func (w ConsoleWriter) writePart(buf *bytes.Buffer, evt map[string]int...
method orderFields (line 355) | func (w ConsoleWriter) orderFields(fields []string) {
function NewConsoleWriter (line 102) | func NewConsoleWriter(options ...func(w *ConsoleWriter)) ConsoleWriter {
function needsQuote (line 379) | func needsQuote(s string) bool {
function colorize (line 389) | func colorize(s interface{}, c int, disabled bool) string {
function consoleDefaultPartsOrder (line 403) | func consoleDefaultPartsOrder() []string {
function consoleDefaultFormatTimestamp (line 412) | func consoleDefaultFormatTimestamp(timeFormat string, location *time.Loc...
function stripLevel (line 456) | func stripLevel(ll string) string {
function consoleDefaultFormatLevel (line 466) | func consoleDefaultFormatLevel(noColor bool) Formatter {
function consoleDefaultFormatCaller (line 483) | func consoleDefaultFormatCaller(noColor bool) Formatter {
function consoleDefaultFormatMessage (line 501) | func consoleDefaultFormatMessage(noColor bool, level interface{}) Format...
function consoleDefaultFormatFieldName (line 515) | func consoleDefaultFormatFieldName(noColor bool) Formatter {
function consoleDefaultFormatFieldValue (line 521) | func consoleDefaultFormatFieldValue(i interface{}) string {
function consoleDefaultFormatErrFieldName (line 525) | func consoleDefaultFormatErrFieldName(noColor bool) Formatter {
function consoleDefaultFormatErrFieldValue (line 531) | func consoleDefaultFormatErrFieldValue(noColor bool) Formatter {
FILE: console_test.go
function ExampleConsoleWriter (line 17) | func ExampleConsoleWriter() {
function ExampleConsoleWriter_customFormatters (line 24) | func ExampleConsoleWriter_customFormatters() {
function ExampleConsoleWriter_partValueFormatter (line 35) | func ExampleConsoleWriter_partValueFormatter() {
function ExampleNewConsoleWriter (line 63) | func ExampleNewConsoleWriter() {
function ExampleNewConsoleWriter_customFormatters (line 72) | func ExampleNewConsoleWriter_customFormatters() {
function TestConsoleLogger (line 89) | func TestConsoleLogger(t *testing.T) {
function TestConsoleWriter (line 104) | func TestConsoleWriter(t *testing.T) {
function TestConsoleWriterConfiguration (line 451) | func TestConsoleWriterConfiguration(t *testing.T) {
function BenchmarkConsoleWriter (line 643) | func BenchmarkConsoleWriter(b *testing.B) {
FILE: context.go
type Context (line 12) | type Context struct
method Logger (line 17) | func (c Context) Logger() Logger {
method Fields (line 24) | func (c Context) Fields(fields interface{}) Context {
method Dict (line 30) | func (c Context) Dict(key string, dict *Event) Context {
method CreateDict (line 41) | func (c Context) CreateDict() *Event {
method CreateArray (line 49) | func (c Context) CreateArray() *Array {
method Array (line 60) | func (c Context) Array(key string, arr LogArrayMarshaler) Context {
method Object (line 73) | func (c Context) Object(key string, obj LogObjectMarshaler) Context {
method Objects (line 82) | func (c Context) Objects(key string, objs []LogObjectMarshaler) Context {
method EmbedObject (line 91) | func (c Context) EmbedObject(obj LogObjectMarshaler) Context {
method Str (line 100) | func (c Context) Str(key, val string) Context {
method Strs (line 106) | func (c Context) Strs(key string, vals []string) Context {
method Stringer (line 112) | func (c Context) Stringer(key string, val fmt.Stringer) Context {
method Stringers (line 124) | func (c Context) Stringers(key string, vals []fmt.Stringer) Context {
method Bytes (line 135) | func (c Context) Bytes(key string, val []byte) Context {
method Hex (line 141) | func (c Context) Hex(key string, val []byte) Context {
method RawJSON (line 150) | func (c Context) RawJSON(key string, b []byte) Context {
method AnErr (line 157) | func (c Context) AnErr(key string, err error) Context {
method Errs (line 177) | func (c Context) Errs(key string, errs []error) Context {
method Err (line 183) | func (c Context) Err(err error) Context {
method Ctx (line 206) | func (c Context) Ctx(ctx context.Context) Context {
method Bool (line 212) | func (c Context) Bool(key string, b bool) Context {
method Bools (line 218) | func (c Context) Bools(key string, b []bool) Context {
method Int (line 224) | func (c Context) Int(key string, i int) Context {
method Ints (line 230) | func (c Context) Ints(key string, i []int) Context {
method Int8 (line 236) | func (c Context) Int8(key string, i int8) Context {
method Ints8 (line 242) | func (c Context) Ints8(key string, i []int8) Context {
method Int16 (line 248) | func (c Context) Int16(key string, i int16) Context {
method Ints16 (line 254) | func (c Context) Ints16(key string, i []int16) Context {
method Int32 (line 260) | func (c Context) Int32(key string, i int32) Context {
method Ints32 (line 266) | func (c Context) Ints32(key string, i []int32) Context {
method Int64 (line 272) | func (c Context) Int64(key string, i int64) Context {
method Ints64 (line 278) | func (c Context) Ints64(key string, i []int64) Context {
method Uint (line 284) | func (c Context) Uint(key string, i uint) Context {
method Uints (line 290) | func (c Context) Uints(key string, i []uint) Context {
method Uint8 (line 296) | func (c Context) Uint8(key string, i uint8) Context {
method Uints8 (line 302) | func (c Context) Uints8(key string, i []uint8) Context {
method Uint16 (line 308) | func (c Context) Uint16(key string, i uint16) Context {
method Uints16 (line 314) | func (c Context) Uints16(key string, i []uint16) Context {
method Uint32 (line 320) | func (c Context) Uint32(key string, i uint32) Context {
method Uints32 (line 326) | func (c Context) Uints32(key string, i []uint32) Context {
method Uint64 (line 332) | func (c Context) Uint64(key string, i uint64) Context {
method Uints64 (line 338) | func (c Context) Uints64(key string, i []uint64) Context {
method Float32 (line 344) | func (c Context) Float32(key string, f float32) Context {
method Floats32 (line 350) | func (c Context) Floats32(key string, f []float32) Context {
method Float64 (line 356) | func (c Context) Float64(key string, f float64) Context {
method Floats64 (line 362) | func (c Context) Floats64(key string, f []float64) Context {
method Timestamp (line 380) | func (c Context) Timestamp() Context {
method Time (line 386) | func (c Context) Time(key string, t time.Time) Context {
method Times (line 392) | func (c Context) Times(key string, t []time.Time) Context {
method Dur (line 398) | func (c Context) Dur(key string, d time.Duration) Context {
method Durs (line 404) | func (c Context) Durs(key string, d []time.Duration) Context {
method Interface (line 410) | func (c Context) Interface(key string, i interface{}) Context {
method Type (line 419) | func (c Context) Type(key string, val interface{}) Context {
method Any (line 425) | func (c Context) Any(key string, i interface{}) Context {
method Reset (line 430) | func (c Context) Reset() Context {
method Caller (line 462) | func (c Context) Caller() Context {
method CallerWithSkipFrameCount (line 470) | func (c Context) CallerWithSkipFrameCount(skipFrameCount int) Context {
method Stack (line 476) | func (c Context) Stack() Context {
method IPAddr (line 482) | func (c Context) IPAddr(key string, ip net.IP) Context {
method IPAddrs (line 488) | func (c Context) IPAddrs(key string, ip []net.IP) Context {
method IPPrefix (line 494) | func (c Context) IPPrefix(key string, pfx net.IPNet) Context {
method IPPrefixes (line 500) | func (c Context) IPPrefixes(key string, pfx []net.IPNet) Context {
method MACAddr (line 506) | func (c Context) MACAddr(key string, ha net.HardwareAddr) Context {
type timestampHook (line 367) | type timestampHook struct
method Run (line 369) | func (ts timestampHook) Run(e *Event, level Level, msg string) {
type callerHook (line 435) | type callerHook struct
method Run (line 443) | func (ch callerHook) Run(e *Event, level Level, msg string) {
function newCallerHook (line 439) | func newCallerHook(skipFrameCount int) callerHook {
constant useGlobalSkipFrameCount (line 456) | useGlobalSkipFrameCount = math.MinInt32
FILE: context_test.go
type myError (line 9) | type myError struct
method Error (line 11) | func (e *myError) Error() string { return "test" }
function TestContext_ErrWithStackMarshaler (line 13) | func TestContext_ErrWithStackMarshaler(t *testing.T) {
function TestContext_AnErrWithNilErrorMarshal (line 35) | func TestContext_AnErrWithNilErrorMarshal(t *testing.T) {
function TestContext_ErrWithNilStackMarshaler (line 57) | func TestContext_ErrWithNilStackMarshaler(t *testing.T) {
function TestContext_ErrWithStackMarshalerObject (line 79) | func TestContext_ErrWithStackMarshalerObject(t *testing.T) {
function TestContext_ErrWithStackMarshalerError (line 101) | func TestContext_ErrWithStackMarshalerError(t *testing.T) {
function TestContext_ErrWithStackMarshalerInterface (line 123) | func TestContext_ErrWithStackMarshalerInterface(t *testing.T) {
FILE: ctx.go
function init (line 9) | func init() {
type ctxKey (line 15) | type ctxKey struct
method WithContext (line 33) | func (l Logger) WithContext(ctx context.Context) context.Context {
function Ctx (line 44) | func Ctx(ctx context.Context) *Logger {
FILE: ctx_test.go
function TestCtx (line 14) | func TestCtx(t *testing.T) {
function TestCtxDisabled (line 43) | func TestCtxDisabled(t *testing.T) {
type logObjectMarshalerImpl (line 76) | type logObjectMarshalerImpl struct
method MarshalZerologObject (line 81) | func (t logObjectMarshalerImpl) MarshalZerologObject(e *Event) {
function Test_InterfaceLogObjectMarshaler (line 85) | func Test_InterfaceLogObjectMarshaler(t *testing.T) {
FILE: diode/diode.go
type Alerter (line 20) | type Alerter
type diodeFetcher (line 22) | type diodeFetcher interface
type Writer (line 29) | type Writer struct
method Write (line 74) | func (dw Writer) Write(p []byte) (n int, err error) {
method Close (line 84) | func (dw Writer) Close() error {
method poll (line 93) | func (dw Writer) poll() {
function NewWriter (line 51) | func NewWriter(w io.Writer, size int, pollInterval time.Duration, f Aler...
FILE: diode/diode_example_test.go
function ExampleNewWriter (line 13) | func ExampleNewWriter() {
FILE: diode/diode_test.go
function TestNewWriter (line 19) | func TestNewWriter(t *testing.T) {
function TestClose (line 35) | func TestClose(t *testing.T) {
function TestFatal (line 43) | func TestFatal(t *testing.T) {
type SlowWriter (line 90) | type SlowWriter struct
method Write (line 92) | func (rw *SlowWriter) Write(p []byte) (n int, err error) {
function TestFatalWithFilteredLevelWriter (line 98) | func TestFatalWithFilteredLevelWriter(t *testing.T) {
function Benchmark (line 150) | func Benchmark(b *testing.B) {
FILE: diode/internal/diodes/many_to_one.go
type ManyToOne (line 11) | type ManyToOne struct
method Set (line 41) | func (d *ManyToOne) Set(data GenericDataType) {
method TryNext (line 70) | func (d *ManyToOne) TryNext() (data GenericDataType, ok bool) {
function NewManyToOne (line 23) | func NewManyToOne(size int, alerter Alerter) *ManyToOne {
FILE: diode/internal/diodes/one_to_one.go
type GenericDataType (line 9) | type GenericDataType
type Alerter (line 13) | type Alerter interface
type AlertFunc (line 19) | type AlertFunc
method Alert (line 22) | func (f AlertFunc) Alert(missed int) {
type bucket (line 26) | type bucket struct
type OneToOne (line 33) | type OneToOne struct
method Set (line 56) | func (d *OneToOne) Set(data GenericDataType) {
method TryNext (line 70) | func (d *OneToOne) TryNext() (data GenericDataType, ok bool) {
function NewOneToOne (line 44) | func NewOneToOne(size int, alerter Alerter) *OneToOne {
FILE: diode/internal/diodes/poller.go
type Diode (line 9) | type Diode interface
type Poller (line 15) | type Poller struct
method Next (line 58) | func (p *Poller) Next() GenericDataType {
method isDone (line 73) | func (p *Poller) isDone() bool {
type PollerConfigOption (line 22) | type PollerConfigOption
function WithPollingInterval (line 26) | func WithPollingInterval(interval time.Duration) PollerConfigOption {
function WithPollingContext (line 35) | func WithPollingContext(ctx context.Context) PollerConfigOption {
function NewPoller (line 42) | func NewPoller(d Diode, opts ...PollerConfigOption) *Poller {
FILE: diode/internal/diodes/waiter.go
type Waiter (line 10) | type Waiter struct
method Set (line 55) | func (w *Waiter) Set(data GenericDataType) {
method Next (line 63) | func (w *Waiter) Next() GenericDataType {
method isDone (line 81) | func (w *Waiter) isDone() bool {
type WaiterConfigOption (line 18) | type WaiterConfigOption
function WithWaiterContext (line 23) | func WithWaiterContext(ctx context.Context) WaiterConfigOption {
function NewWaiter (line 30) | func NewWaiter(d Diode, opts ...WaiterConfigOption) *Waiter {
FILE: encoder.go
type encoder (line 8) | type encoder interface
FILE: encoder_cbor.go
function init (line 17) | func init() {
function appendJSON (line 24) | func appendJSON(dst []byte, j []byte) []byte {
function appendCBOR (line 27) | func appendCBOR(dst []byte, c []byte) []byte {
function decodeIfBinaryToString (line 33) | func decodeIfBinaryToString(in []byte) string {
function decodeObjectToStr (line 37) | func decodeObjectToStr(in []byte) string {
function decodeIfBinaryToBytes (line 43) | func decodeIfBinaryToBytes(in []byte) []byte {
FILE: encoder_json.go
function init (line 19) | func init() {
function appendJSON (line 26) | func appendJSON(dst []byte, j []byte) []byte {
function appendCBOR (line 29) | func appendCBOR(dst []byte, cbor []byte) []byte {
function decodeIfBinaryToString (line 41) | func decodeIfBinaryToString(in []byte) string {
function decodeObjectToStr (line 45) | func decodeObjectToStr(in []byte) string {
function decodeIfBinaryToBytes (line 49) | func decodeIfBinaryToBytes(in []byte) []byte {
FILE: error_marshal_test.go
type loggableError (line 10) | type loggableError struct
method MarshalZerologObject (line 14) | func (l loggableError) MarshalZerologObject(e *Event) {
type nonLoggableError (line 21) | type nonLoggableError struct
type wrappedError (line 26) | type wrappedError struct
method Error (line 31) | func (w wrappedError) Error() string {
type interfaceError (line 38) | type interfaceError struct
function TestArrayErrorMarshalFunc (line 42) | func TestArrayErrorMarshalFunc(t *testing.T) {
FILE: event.go
type Event (line 23) | type Event struct
method write (line 81) | func (e *Event) write() (err error) {
method Enabled (line 98) | func (e *Event) Enabled() bool {
method Discard (line 103) | func (e *Event) Discard() *Event {
method Msg (line 115) | func (e *Event) Msg(msg string) {
method Send (line 125) | func (e *Event) Send() {
method Msgf (line 136) | func (e *Event) Msgf(format string, v ...interface{}) {
method MsgFunc (line 143) | func (e *Event) MsgFunc(createMsg func() string) {
method msg (line 150) | func (e *Event) msg(msg string) {
method Fields (line 172) | func (e *Event) Fields(fields interface{}) *Event {
method Dict (line 182) | func (e *Event) Dict(key string, dict *Event) *Event {
method CreateDict (line 195) | func (e *Event) CreateDict() *Event {
method CreateArray (line 216) | func (e *Event) CreateArray() *Array {
method Array (line 229) | func (e *Event) Array(key string, arr LogArrayMarshaler) *Event {
method appendObject (line 245) | func (e *Event) appendObject(obj LogObjectMarshaler) {
method Object (line 252) | func (e *Event) Object(key string, obj LogObjectMarshaler) *Event {
method Objects (line 268) | func (e *Event) Objects(key string, objs []LogObjectMarshaler) *Event {
method Func (line 284) | func (e *Event) Func(f func(e *Event)) *Event {
method EmbedObject (line 292) | func (e *Event) EmbedObject(obj LogObjectMarshaler) *Event {
method Str (line 304) | func (e *Event) Str(key, val string) *Event {
method Strs (line 313) | func (e *Event) Strs(key string, vals []string) *Event {
method Stringer (line 323) | func (e *Event) Stringer(key string, val fmt.Stringer) *Event {
method Stringers (line 334) | func (e *Event) Stringers(key string, vals []fmt.Stringer) *Event {
method Bytes (line 346) | func (e *Event) Bytes(key string, val []byte) *Event {
method Hex (line 355) | func (e *Event) Hex(key string, val []byte) *Event {
method RawJSON (line 367) | func (e *Event) RawJSON(key string, b []byte) *Event {
method RawCBOR (line 379) | func (e *Event) RawCBOR(key string, b []byte) *Event {
method AnErr (line 389) | func (e *Event) AnErr(key string, err error) *Event {
method Errs (line 412) | func (e *Event) Errs(key string, errs []error) *Event {
method Err (line 428) | func (e *Event) Err(err error) *Event {
method Stack (line 454) | func (e *Event) Stack() *Event {
method Ctx (line 465) | func (e *Event) Ctx(ctx context.Context) *Event {
method GetCtx (line 476) | func (e *Event) GetCtx() context.Context {
method Bool (line 484) | func (e *Event) Bool(key string, b bool) *Event {
method Bools (line 493) | func (e *Event) Bools(key string, b []bool) *Event {
method Int (line 502) | func (e *Event) Int(key string, i int) *Event {
method Ints (line 511) | func (e *Event) Ints(key string, i []int) *Event {
method Int8 (line 520) | func (e *Event) Int8(key string, i int8) *Event {
method Ints8 (line 529) | func (e *Event) Ints8(key string, i []int8) *Event {
method Int16 (line 538) | func (e *Event) Int16(key string, i int16) *Event {
method Ints16 (line 547) | func (e *Event) Ints16(key string, i []int16) *Event {
method Int32 (line 556) | func (e *Event) Int32(key string, i int32) *Event {
method Ints32 (line 565) | func (e *Event) Ints32(key string, i []int32) *Event {
method Int64 (line 574) | func (e *Event) Int64(key string, i int64) *Event {
method Ints64 (line 583) | func (e *Event) Ints64(key string, i []int64) *Event {
method Uint (line 592) | func (e *Event) Uint(key string, i uint) *Event {
method Uints (line 601) | func (e *Event) Uints(key string, i []uint) *Event {
method Uint8 (line 610) | func (e *Event) Uint8(key string, i uint8) *Event {
method Uints8 (line 619) | func (e *Event) Uints8(key string, i []uint8) *Event {
method Uint16 (line 628) | func (e *Event) Uint16(key string, i uint16) *Event {
method Uints16 (line 637) | func (e *Event) Uints16(key string, i []uint16) *Event {
method Uint32 (line 646) | func (e *Event) Uint32(key string, i uint32) *Event {
method Uints32 (line 655) | func (e *Event) Uints32(key string, i []uint32) *Event {
method Uint64 (line 664) | func (e *Event) Uint64(key string, i uint64) *Event {
method Uints64 (line 673) | func (e *Event) Uints64(key string, i []uint64) *Event {
method Float32 (line 682) | func (e *Event) Float32(key string, f float32) *Event {
method Floats32 (line 691) | func (e *Event) Floats32(key string, f []float32) *Event {
method Float64 (line 700) | func (e *Event) Float64(key string, f float64) *Event {
method Floats64 (line 709) | func (e *Event) Floats64(key string, f []float64) *Event {
method Timestamp (line 722) | func (e *Event) Timestamp() *Event {
method Time (line 731) | func (e *Event) Time(key string, t time.Time) *Event {
method Times (line 740) | func (e *Event) Times(key string, t []time.Time) *Event {
method Dur (line 751) | func (e *Event) Dur(key string, d time.Duration) *Event {
method Durs (line 762) | func (e *Event) Durs(key string, d []time.Duration) *Event {
method TimeDiff (line 773) | func (e *Event) TimeDiff(key string, t time.Time, start time.Time) *Ev...
method Any (line 786) | func (e *Event) Any(key string, i interface{}) *Event {
method Interface (line 791) | func (e *Event) Interface(key string, i interface{}) *Event {
method Type (line 803) | func (e *Event) Type(key string, val interface{}) *Event {
method CallerSkipFrame (line 813) | func (e *Event) CallerSkipFrame(skip int) *Event {
method Caller (line 824) | func (e *Event) Caller(skip ...int) *Event {
method caller (line 832) | func (e *Event) caller(skip int) *Event {
method IPAddr (line 843) | func (e *Event) IPAddr(key string, ip net.IP) *Event {
method IPAddrs (line 852) | func (e *Event) IPAddrs(key string, ip []net.IP) *Event {
method IPPrefix (line 861) | func (e *Event) IPPrefix(key string, pfx net.IPNet) *Event {
method IPPrefixes (line 870) | func (e *Event) IPPrefixes(key string, pfx []net.IPNet) *Event {
method MACAddr (line 879) | func (e *Event) MACAddr(key string, ha net.HardwareAddr) *Event {
function putEvent (line 34) | func putEvent(e *Event) {
type LogObjectMarshaler (line 58) | type LogObjectMarshaler interface
type LogArrayMarshaler (line 64) | type LogArrayMarshaler interface
function newEvent (line 68) | func newEvent(w LevelWriter, level Level, stack bool, ctx context.Contex...
function Dict (line 208) | func Dict() *Event {
FILE: event_test.go
type nilError (line 16) | type nilError struct
method Error (line 18) | func (nilError) Error() string {
function TestEvent_AnErr (line 22) | func TestEvent_AnErr(t *testing.T) {
function TestEvent_writeWithNil (line 49) | func TestEvent_writeWithNil(t *testing.T) {
type loggableObject (line 59) | type loggableObject struct
method MarshalZerologObject (line 63) | func (o loggableObject) MarshalZerologObject(e *Event) {
function TestEvent_Object (line 67) | func TestEvent_Object(t *testing.T) {
function TestEvent_WithNilEvent (line 159) | func TestEvent_WithNilEvent(t *testing.T) {
function TestEvent_MsgFunc (line 370) | func TestEvent_MsgFunc(t *testing.T) {
function TestEvent_CallerRuntimeFail (line 390) | func TestEvent_CallerRuntimeFail(t *testing.T) {
function TestEvent_DoneHandler (line 407) | func TestEvent_DoneHandler(t *testing.T) {
type badLevelWriter (line 430) | type badLevelWriter struct
method WriteLevel (line 434) | func (w *badLevelWriter) WriteLevel(level Level, p []byte) (n int, err...
method Write (line 438) | func (w *badLevelWriter) Write(p []byte) (n int, err error) {
function TestEvent_Msg_ErrorHandlerNil (line 442) | func TestEvent_Msg_ErrorHandlerNil(t *testing.T) {
type mockLogObjectMarshaler (line 482) | type mockLogObjectMarshaler struct
method MarshalZerologObject (line 486) | func (m mockLogObjectMarshaler) MarshalZerologObject(e *Event) {
function TestEvent_ErrWithStackMarshaler (line 490) | func TestEvent_ErrWithStackMarshaler(t *testing.T) {
function TestEvent_FieldsWithErrorAndStackMarshaler (line 513) | func TestEvent_FieldsWithErrorAndStackMarshaler(t *testing.T) {
function TestEvent_FieldsWithErrorAndStackMarshalerObject (line 536) | func TestEvent_FieldsWithErrorAndStackMarshalerObject(t *testing.T) {
function TestEvent_FieldsWithErrorAndStackMarshalerError (line 559) | func TestEvent_FieldsWithErrorAndStackMarshalerError(t *testing.T) {
function TestEvent_FieldsWithErrorAndStackMarshalerInterface (line 582) | func TestEvent_FieldsWithErrorAndStackMarshalerInterface(t *testing.T) {
function TestEvent_FieldsWithErrorAndStackMarshalerNil (line 605) | func TestEvent_FieldsWithErrorAndStackMarshalerNil(t *testing.T) {
function TestEvent_ErrWithStackMarshalerObject (line 628) | func TestEvent_ErrWithStackMarshalerObject(t *testing.T) {
function TestEvent_ErrWithStackMarshalerError (line 651) | func TestEvent_ErrWithStackMarshalerError(t *testing.T) {
function TestEvent_ErrWithStackMarshalerInterface (line 674) | func TestEvent_ErrWithStackMarshalerInterface(t *testing.T) {
function TestEvent_ErrWithStackMarshalerNil (line 697) | func TestEvent_ErrWithStackMarshalerNil(t *testing.T) {
FILE: fields.go
function isNilValue (line 13) | func isNilValue(e error) bool {
function appendFields (line 22) | func appendFields(dst []byte, fields interface{}, stack bool, ctx contex...
function appendObject (line 44) | func appendObject(dst []byte, obj LogObjectMarshaler, stack bool, ctx co...
function appendFieldList (line 53) | func appendFieldList(dst []byte, kvList []interface{}, stack bool, ctx c...
FILE: fixtures_test.go
type fixtureObj (line 12) | type fixtureObj struct
method MarshalZerologObject (line 18) | func (o fixtureObj) MarshalZerologObject(e *Event) {
type fieldFixtures (line 24) | type fieldFixtures struct
function makeFieldFixtures (line 59) | func makeFieldFixtures() *fieldFixtures {
FILE: globals.go
constant TimeFormatUnix (line 14) | TimeFormatUnix = ""
constant TimeFormatUnixMs (line 18) | TimeFormatUnixMs = "UNIXMS"
constant TimeFormatUnixMicro (line 22) | TimeFormatUnixMicro = "UNIXMICRO"
constant TimeFormatUnixNano (line 26) | TimeFormatUnixNano = "UNIXNANO"
constant DurationFormatFloat (line 30) | DurationFormatFloat = "float"
constant DurationFormatInt (line 33) | DurationFormatInt = "int"
constant DurationFormatString (line 36) | DurationFormatString = "string"
function SetGlobalLevel (line 188) | func SetGlobalLevel(l Level) {
function GlobalLevel (line 193) | func GlobalLevel() Level {
function DisableSampling (line 198) | func DisableSampling(v bool) {
function samplingDisabled (line 206) | func samplingDisabled() bool {
FILE: go112.go
constant contextCallerSkipFrameCount (line 7) | contextCallerSkipFrameCount = 2
FILE: hlog/hlog.go
function FromRequest (line 19) | func FromRequest(r *http.Request) *zerolog.Logger {
function NewHandler (line 24) | func NewHandler(log zerolog.Logger) func(http.Handler) http.Handler {
function URLHandler (line 38) | func URLHandler(fieldKey string) func(next http.Handler) http.Handler {
function MethodHandler (line 52) | func MethodHandler(fieldKey string) func(next http.Handler) http.Handler {
function RequestHandler (line 66) | func RequestHandler(fieldKey string) func(next http.Handler) http.Handler {
function RemoteAddrHandler (line 80) | func RemoteAddrHandler(fieldKey string) func(next http.Handler) http.Han...
function getHost (line 94) | func getHost(hostPort string) string {
function RemoteIPHandler (line 108) | func RemoteIPHandler(fieldKey string) func(next http.Handler) http.Handl...
function UserAgentHandler (line 125) | func UserAgentHandler(fieldKey string) func(next http.Handler) http.Hand...
function RefererHandler (line 141) | func RefererHandler(fieldKey string) func(next http.Handler) http.Handler {
function ProtoHandler (line 157) | func ProtoHandler(fieldKey string) func(next http.Handler) http.Handler {
function HTTPVersionHandler (line 171) | func HTTPVersionHandler(fieldKey string) func(next http.Handler) http.Ha...
type idKey (line 184) | type idKey struct
function IDFromRequest (line 187) | func IDFromRequest(r *http.Request) (id xid.ID, ok bool) {
function IDFromCtx (line 195) | func IDFromCtx(ctx context.Context) (id xid.ID, ok bool) {
function CtxWithID (line 201) | func CtxWithID(ctx context.Context, id xid.ID) context.Context {
function RequestIDHandler (line 214) | func RequestIDHandler(fieldKey, headerName string) func(next http.Handle...
function CustomHeaderHandler (line 240) | func CustomHeaderHandler(fieldKey, header string) func(next http.Handler...
function EtagHandler (line 256) | func EtagHandler(fieldKey string) func(next http.Handler) http.Handler {
function ResponseHeaderHandler (line 274) | func ResponseHeaderHandler(fieldKey, headerName string) func(next http.H...
function AccessHandler (line 292) | func AccessHandler(f func(r *http.Request, status, size int, duration ti...
function HostHandler (line 308) | func HostHandler(fieldKey string, trimPort ...bool) func(next http.Handl...
FILE: hlog/hlog_example_test.go
type middleware (line 17) | type middleware
type alice (line 18) | type alice struct
method Append (line 22) | func (a alice) Append(m middleware) alice {
method Then (line 26) | func (a alice) Then(h http.Handler) http.Handler {
function init (line 33) | func init() {
function Example_handler (line 39) | func Example_handler() {
FILE: hlog/hlog_test.go
function decodeIfBinary (line 22) | func decodeIfBinary(out *bytes.Buffer) string {
function TestNewHandler (line 30) | func TestNewHandler(t *testing.T) {
function TestURLHandler (line 44) | func TestURLHandler(t *testing.T) {
function TestMethodHandler (line 60) | func TestMethodHandler(t *testing.T) {
function TestRequestHandler (line 76) | func TestRequestHandler(t *testing.T) {
function TestRemoteAddrHandler (line 93) | func TestRemoteAddrHandler(t *testing.T) {
function TestRemoteAddrHandlerIPv6 (line 109) | func TestRemoteAddrHandlerIPv6(t *testing.T) {
function TestRemoteIPHandler (line 125) | func TestRemoteIPHandler(t *testing.T) {
function TestRemoteIPHandlerIPv6 (line 141) | func TestRemoteIPHandlerIPv6(t *testing.T) {
function TestUserAgentHandler (line 157) | func TestUserAgentHandler(t *testing.T) {
function TestRefererHandler (line 175) | func TestRefererHandler(t *testing.T) {
function TestRequestIDHandler (line 193) | func TestRequestIDHandler(t *testing.T) {
function TestCustomHeaderHandler (line 218) | func TestCustomHeaderHandler(t *testing.T) {
function TestEtagHandler (line 236) | func TestEtagHandler(t *testing.T) {
function TestResponseHeaderHandler (line 256) | func TestResponseHeaderHandler(t *testing.T) {
function TestProtoHandler (line 276) | func TestProtoHandler(t *testing.T) {
function TestHTTPVersionHandler (line 292) | func TestHTTPVersionHandler(t *testing.T) {
function TestCombinedHandlers (line 308) | func TestCombinedHandlers(t *testing.T) {
function BenchmarkHandlers (line 325) | func BenchmarkHandlers(b *testing.B) {
function BenchmarkDataRace (line 351) | func BenchmarkDataRace(b *testing.B) {
function TestCtxWithID (line 371) | func TestCtxWithID(t *testing.T) {
function TestHostHandler (line 384) | func TestHostHandler(t *testing.T) {
function TestHostHandlerWithoutPort (line 398) | func TestHostHandlerWithoutPort(t *testing.T) {
function TestGetHost (line 412) | func TestGetHost(t *testing.T) {
FILE: hlog/internal/mutil/writer_proxy.go
type WriterProxy (line 12) | type WriterProxy interface
function WrapWriter (line 32) | func WrapWriter(w http.ResponseWriter) WriterProxy {
type basicWriter (line 50) | type basicWriter struct
method WriteHeader (line 58) | func (b *basicWriter) WriteHeader(code int) {
method Write (line 66) | func (b *basicWriter) Write(buf []byte) (int, error) {
method maybeWriteHeader (line 80) | func (b *basicWriter) maybeWriteHeader() {
method Status (line 86) | func (b *basicWriter) Status() int {
method BytesWritten (line 90) | func (b *basicWriter) BytesWritten() int {
method Tee (line 94) | func (b *basicWriter) Tee(w io.Writer) {
method Unwrap (line 98) | func (b *basicWriter) Unwrap() http.ResponseWriter {
type fancyWriter (line 106) | type fancyWriter struct
method CloseNotify (line 110) | func (f *fancyWriter) CloseNotify() <-chan bool {
method Flush (line 115) | func (f *fancyWriter) Flush() {
method Hijack (line 120) | func (f *fancyWriter) Hijack() (net.Conn, *bufio.ReadWriter, error) {
method ReadFrom (line 125) | func (f *fancyWriter) ReadFrom(r io.Reader) (int64, error) {
type flushWriter (line 139) | type flushWriter struct
method Flush (line 143) | func (f *flushWriter) Flush() {
FILE: hook.go
type Hook (line 4) | type Hook interface
type HookFunc (line 11) | type HookFunc
method Run (line 14) | func (h HookFunc) Run(e *Event, level Level, message string) {
type LevelHook (line 19) | type LevelHook struct
method Run (line 24) | func (h LevelHook) Run(e *Event, level Level, message string) {
function NewLevelHook (line 62) | func NewLevelHook() LevelHook {
FILE: hook_test.go
type contextKeyType (line 10) | type contextKeyType
function TestHook (line 47) | func TestHook(t *testing.T) {
function TestLevelHook (line 178) | func TestLevelHook(t *testing.T) {
function BenchmarkHooks (line 271) | func BenchmarkHooks(b *testing.B) {
FILE: internal/cbor/base.go
type Encoder (line 11) | type Encoder struct
method AppendKey (line 14) | func (e Encoder) AppendKey(dst []byte, key string) []byte {
FILE: internal/cbor/base_test.go
function TestAppendKey (line 9) | func TestAppendKey(t *testing.T) {
FILE: internal/cbor/cbor.go
constant majorOffset (line 8) | majorOffset = 5
constant additionalMax (line 9) | additionalMax = 23
constant additionalTypeBoolFalse (line 12) | additionalTypeBoolFalse byte = 20
constant additionalTypeBoolTrue (line 13) | additionalTypeBoolTrue byte = 21
constant additionalTypeNull (line 14) | additionalTypeNull byte = 22
constant additionalTypeIntUint8 (line 17) | additionalTypeIntUint8 byte = 24
constant additionalTypeIntUint16 (line 18) | additionalTypeIntUint16 byte = 25
constant additionalTypeIntUint32 (line 19) | additionalTypeIntUint32 byte = 26
constant additionalTypeIntUint64 (line 20) | additionalTypeIntUint64 byte = 27
constant additionalTypeFloat16 (line 23) | additionalTypeFloat16 byte = 25
constant additionalTypeFloat32 (line 24) | additionalTypeFloat32 byte = 26
constant additionalTypeFloat64 (line 25) | additionalTypeFloat64 byte = 27
constant additionalTypeBreak (line 26) | additionalTypeBreak byte = 31
constant additionalTypeTimestamp (line 29) | additionalTypeTimestamp byte = 01
constant additionalTypeEmbeddedCBOR (line 30) | additionalTypeEmbeddedCBOR byte = 63
constant additionalTypeTagNetworkAddr (line 33) | additionalTypeTagNetworkAddr uint16 = 260
constant additionalTypeTagNetworkPrefix (line 34) | additionalTypeTagNetworkPrefix uint16 = 261
constant additionalTypeEmbeddedJSON (line 35) | additionalTypeEmbeddedJSON uint16 = 262
constant additionalTypeTagHexString (line 36) | additionalTypeTagHexString uint16 = 263
constant additionalTypeInfiniteCount (line 39) | additionalTypeInfiniteCount byte = 31
constant majorTypeUnsignedInt (line 42) | majorTypeUnsignedInt byte = iota << majorOffset
constant majorTypeNegativeInt (line 43) | majorTypeNegativeInt
constant majorTypeByteString (line 44) | majorTypeByteString
constant majorTypeUtf8String (line 45) | majorTypeUtf8String
constant majorTypeArray (line 46) | majorTypeArray
constant majorTypeMap (line 47) | majorTypeMap
constant majorTypeTags (line 48) | majorTypeTags
constant majorTypeSimpleAndFloat (line 49) | majorTypeSimpleAndFloat
constant maskOutAdditionalType (line 53) | maskOutAdditionalType byte = (7 << majorOffset)
constant maskOutMajorType (line 54) | maskOutMajorType byte = 31
constant float32Nan (line 58) | float32Nan = "\x7f\xc0\x00\x00"
constant float32PosInfinity (line 59) | float32PosInfinity = "\x7f\x80\x00\x00"
constant float32NegInfinity (line 60) | float32NegInfinity = "\xff\x80\x00\x00"
constant float64Nan (line 61) | float64Nan = "\x7f\xf8\x00\x00\x00\x00\x00\x00"
constant float64PosInfinity (line 62) | float64PosInfinity = "\x7f\xf0\x00\x00\x00\x00\x00\x00"
constant float64NegInfinity (line 63) | float64NegInfinity = "\xff\xf0\x00\x00\x00\x00\x00\x00"
function appendCborTypePrefix (line 74) | func appendCborTypePrefix(dst []byte, major byte, number uint64) []byte {
FILE: internal/cbor/decode_stream.go
constant hexTable (line 22) | hexTable = "0123456789abcdef"
constant isFloat32 (line 24) | isFloat32 = 4
constant isFloat64 (line 25) | isFloat64 = 8
function readNBytes (line 27) | func readNBytes(src *bufio.Reader, n int) []byte {
function readByte (line 39) | func readByte(src *bufio.Reader) byte {
function decodeIntAdditionalType (line 47) | func decodeIntAdditionalType(src *bufio.Reader, minor byte) int64 {
function decodeInteger (line 74) | func decodeInteger(src *bufio.Reader) int64 {
function decodeFloat (line 88) | func decodeFloat(src *bufio.Reader) (float64, int) {
function decodeStringComplex (line 138) | func decodeStringComplex(dst []byte, s string, pos uint) []byte {
function decodeString (line 197) | func decodeString(src *bufio.Reader, noQuotes bool) []byte {
function decodeStringToDataUrl (line 217) | func decodeStringToDataUrl(src *bufio.Reader, mimeType string) []byte {
function decodeUTF8String (line 243) | func decodeUTF8String(src *bufio.Reader) []byte {
function array2Json (line 273) | func array2Json(src *bufio.Reader, dst io.Writer) {
function map2Json (line 318) | func map2Json(src *bufio.Reader, dst io.Writer) {
function decodeTagData (line 368) | func decodeTagData(src *bufio.Reader) []byte {
function decodeTimeStamp (line 459) | func decodeTimeStamp(src *bufio.Reader) []byte {
function decodeSimpleFloat (line 496) | func decodeSimpleFloat(src *bufio.Reader) []byte {
function cbor2JsonOneObject (line 539) | func cbor2JsonOneObject(src *bufio.Reader, dst io.Writer) {
function moreBytesToRead (line 577) | func moreBytesToRead(src *bufio.Reader) bool {
function Cbor2JsonManyObjects (line 594) | func Cbor2JsonManyObjects(src io.Reader, dst io.Writer) (err error) {
function binaryFmt (line 612) | func binaryFmt(p []byte) bool {
function getReader (line 619) | func getReader(str string) *bufio.Reader {
function DecodeIfBinaryToString (line 625) | func DecodeIfBinaryToString(in []byte) string {
function DecodeObjectToStr (line 636) | func DecodeObjectToStr(in []byte) string {
function DecodeIfBinaryToBytes (line 647) | func DecodeIfBinaryToBytes(in []byte) []byte {
FILE: internal/cbor/decoder_test.go
function TestDecodeInteger (line 13) | func TestDecodeInteger(t *testing.T) {
function TestDecodeString (line 23) | func TestDecodeString(t *testing.T) {
function TestDecodeArray (line 33) | func TestDecodeArray(t *testing.T) {
function TestDecodeMap (line 87) | func TestDecodeMap(t *testing.T) {
function TestDecodeBool (line 104) | func TestDecodeBool(t *testing.T) {
function TestDecodeFloat (line 113) | func TestDecodeFloat(t *testing.T) {
function TestDecodeTimestamp (line 161) | func TestDecodeTimestamp(t *testing.T) {
function TestDecodeNetworkAddr (line 203) | func TestDecodeNetworkAddr(t *testing.T) {
function TestDecodeMACAddr (line 212) | func TestDecodeMACAddr(t *testing.T) {
function TestDecodeIPPrefix (line 221) | func TestDecodeIPPrefix(t *testing.T) {
function TestDecodeCbor2Json (line 240) | func TestDecodeCbor2Json(t *testing.T) {
function TestDecodeNegativeCbor2Json (line 263) | func TestDecodeNegativeCbor2Json(t *testing.T) {
function TestBinaryFmt (line 273) | func TestBinaryFmt(t *testing.T) {
function TestDecodeIfBinaryToString (line 294) | func TestDecodeIfBinaryToString(t *testing.T) {
function TestDecodeObjectToStr (line 327) | func TestDecodeObjectToStr(t *testing.T) {
function TestDecodeIfBinaryToBytes (line 360) | func TestDecodeIfBinaryToBytes(t *testing.T) {
function TestDecodeEmbeddedCBOR (line 393) | func TestDecodeEmbeddedCBOR(t *testing.T) {
function TestDecodeEmbeddedJSON (line 409) | func TestDecodeEmbeddedJSON(t *testing.T) {
function TestDecodeHexString (line 440) | func TestDecodeHexString(t *testing.T) {
function TestDecodeSimpleFloat (line 456) | func TestDecodeSimpleFloat(t *testing.T) {
FILE: internal/cbor/examples/genLog.go
function writeLog (line 14) | func writeLog(fname string, count int, useCompress bool) {
function main (line 47) | func main() {
FILE: internal/cbor/string.go
method AppendStrings (line 6) | func (e Encoder) AppendStrings(dst []byte, vals []string) []byte {
method AppendString (line 22) | func (Encoder) AppendString(dst []byte, s string) []byte {
method AppendStringers (line 37) | func (e Encoder) AppendStringers(dst []byte, vals []fmt.Stringer) []byte {
method AppendStringer (line 53) | func (e Encoder) AppendStringer(dst []byte, val fmt.Stringer) []byte {
method AppendBytes (line 61) | func (Encoder) AppendBytes(dst, s []byte) []byte {
function AppendEmbeddedJSON (line 75) | func AppendEmbeddedJSON(dst, s []byte) []byte {
function AppendEmbeddedCBOR (line 98) | func AppendEmbeddedCBOR(dst, s []byte) []byte {
FILE: internal/cbor/string_test.go
function TestAppendString (line 74) | func TestAppendString(t *testing.T) {
function TestAppendStrings (line 94) | func TestAppendStrings(t *testing.T) {
function TestAppendStringer (line 142) | func TestAppendStringer(t *testing.T) {
function TestAppendStringers (line 164) | func TestAppendStringers(t *testing.T) {
function TestAppendBytes (line 179) | func TestAppendBytes(t *testing.T) {
function BenchmarkAppendString (line 199) | func BenchmarkAppendString(b *testing.B) {
function TestAppendEmbeddedJSON (line 219) | func TestAppendEmbeddedJSON(t *testing.T) {
function TestAppendEmbeddedCBOR (line 252) | func TestAppendEmbeddedCBOR(t *testing.T) {
FILE: internal/cbor/time.go
constant timeFormatUnix (line 9) | timeFormatUnix = ""
constant timeFormatUnixMs (line 10) | timeFormatUnixMs = "UNIXMS"
constant timeFormatUnixMicro (line 11) | timeFormatUnixMicro = "UNIXMICRO"
constant timeFormatUnixNano (line 12) | timeFormatUnixNano = "UNIXNANO"
constant durationFormatFloat (line 13) | durationFormatFloat = "float"
constant durationFormatInt (line 14) | durationFormatInt = "int"
constant durationFormatString (line 15) | durationFormatString = "string"
function appendIntegerTimestamp (line 18) | func appendIntegerTimestamp(dst []byte, t time.Time) []byte {
method appendFloatTimestamp (line 35) | func (e Encoder) appendFloatTimestamp(dst []byte, t time.Time) []byte {
method AppendTime (line 46) | func (e Encoder) AppendTime(dst []byte, t time.Time, unused string) []by...
method AppendTimes (line 55) | func (e Encoder) AppendTimes(dst []byte, vals []time.Time, unused string...
method AppendDuration (line 77) | func (e Encoder) AppendDuration(dst []byte, d time.Duration, unit time.D...
method AppendDurations (line 95) | func (e Encoder) AppendDurations(dst []byte, vals []time.Duration, unit ...
FILE: internal/cbor/time_test.go
function TestEncoder_AppendDuration (line 15) | func TestEncoder_AppendDuration(t *testing.T) {
function TestEncoder_AppendDurations (line 84) | func TestEncoder_AppendDurations(t *testing.T) {
function TestAppendTimeNow (line 153) | func TestAppendTimeNow(t *testing.T) {
function TestAppendTimePastPresentInteger (line 172) | func TestAppendTimePastPresentInteger(t *testing.T) {
function TestAppendTimePastPresentFloat (line 188) | func TestAppendTimePastPresentFloat(t *testing.T) {
function TestAppendTimes (line 204) | func TestAppendTimes(t *testing.T) {
function TestAppendDurationFloat (line 253) | func TestAppendDurationFloat(t *testing.T) {
function TestAppendDurationInteger (line 267) | func TestAppendDurationInteger(t *testing.T) {
function TestAppendDurations (line 281) | func TestAppendDurations(t *testing.T) {
function BenchmarkAppendTime (line 329) | func BenchmarkAppendTime(b *testing.B) {
FILE: internal/cbor/types.go
method AppendNil (line 11) | func (Encoder) AppendNil(dst []byte) []byte {
method AppendBeginMarker (line 16) | func (Encoder) AppendBeginMarker(dst []byte) []byte {
method AppendEndMarker (line 21) | func (Encoder) AppendEndMarker(dst []byte) []byte {
method AppendObjectData (line 26) | func (Encoder) AppendObjectData(dst []byte, o []byte) []byte {
method AppendArrayStart (line 33) | func (Encoder) AppendArrayStart(dst []byte) []byte {
method AppendArrayEnd (line 38) | func (Encoder) AppendArrayEnd(dst []byte) []byte {
method AppendArrayDelim (line 43) | func (Encoder) AppendArrayDelim(dst []byte) []byte {
method AppendLineBreak (line 49) | func (Encoder) AppendLineBreak(dst []byte) []byte {
method AppendBool (line 55) | func (Encoder) AppendBool(dst []byte, val bool) []byte {
method AppendBools (line 64) | func (e Encoder) AppendBools(dst []byte, vals []bool) []byte {
method AppendInt (line 83) | func (Encoder) AppendInt(dst []byte, val int) []byte {
method AppendInts (line 100) | func (e Encoder) AppendInts(dst []byte, vals []int) []byte {
method AppendInt8 (line 119) | func (e Encoder) AppendInt8(dst []byte, val int8) []byte {
method AppendInts8 (line 124) | func (e Encoder) AppendInts8(dst []byte, vals []int8) []byte {
method AppendInt16 (line 143) | func (e Encoder) AppendInt16(dst []byte, val int16) []byte {
method AppendInts16 (line 148) | func (e Encoder) AppendInts16(dst []byte, vals []int16) []byte {
method AppendInt32 (line 167) | func (e Encoder) AppendInt32(dst []byte, val int32) []byte {
method AppendInts32 (line 172) | func (e Encoder) AppendInts32(dst []byte, vals []int32) []byte {
method AppendInt64 (line 191) | func (Encoder) AppendInt64(dst []byte, val int64) []byte {
method AppendInts64 (line 208) | func (e Encoder) AppendInts64(dst []byte, vals []int64) []byte {
method AppendUint (line 227) | func (e Encoder) AppendUint(dst []byte, val uint) []byte {
method AppendUints (line 232) | func (e Encoder) AppendUints(dst []byte, vals []uint) []byte {
method AppendUint8 (line 251) | func (e Encoder) AppendUint8(dst []byte, val uint8) []byte {
method AppendUints8 (line 256) | func (e Encoder) AppendUints8(dst []byte, vals []uint8) []byte {
method AppendUint16 (line 275) | func (e Encoder) AppendUint16(dst []byte, val uint16) []byte {
method AppendUints16 (line 280) | func (e Encoder) AppendUints16(dst []byte, vals []uint16) []byte {
method AppendUint32 (line 299) | func (e Encoder) AppendUint32(dst []byte, val uint32) []byte {
method AppendUints32 (line 304) | func (e Encoder) AppendUints32(dst []byte, vals []uint32) []byte {
method AppendUint64 (line 323) | func (Encoder) AppendUint64(dst []byte, val uint64) []byte {
method AppendUints64 (line 336) | func (e Encoder) AppendUints64(dst []byte, vals []uint64) []byte {
method AppendFloat32 (line 355) | func (Encoder) AppendFloat32(dst []byte, val float32, unused int) []byte {
method AppendFloats32 (line 375) | func (e Encoder) AppendFloats32(dst []byte, vals []float32, unused int) ...
method AppendFloat64 (line 394) | func (Encoder) AppendFloat64(dst []byte, val float64, unused int) []byte {
method AppendFloats64 (line 415) | func (e Encoder) AppendFloats64(dst []byte, vals []float64, unused int) ...
method AppendInterface (line 434) | func (e Encoder) AppendInterface(dst []byte, i interface{}) []byte {
method AppendType (line 443) | func (e Encoder) AppendType(dst []byte, i interface{}) []byte {
method AppendIPAddr (line 451) | func (e Encoder) AppendIPAddr(dst []byte, ip net.IP) []byte {
method AppendIPAddrs (line 459) | func (e Encoder) AppendIPAddrs(dst []byte, ips []net.IP) []byte {
method AppendIPPrefix (line 478) | func (e Encoder) AppendIPPrefix(dst []byte, pfx net.IPNet) []byte {
method AppendIPPrefixes (line 492) | func (e Encoder) AppendIPPrefixes(dst []byte, pfxs []net.IPNet) []byte {
method AppendMACAddr (line 511) | func (e Encoder) AppendMACAddr(dst []byte, ha net.HardwareAddr) []byte {
method AppendHex (line 519) | func (e Encoder) AppendHex(dst []byte, val []byte) []byte {
FILE: internal/cbor/types_64_test.go
function TestAppendInt_64bit (line 24) | func TestAppendInt_64bit(t *testing.T) {
FILE: internal/cbor/types_test.go
function TestAppendNil (line 16) | func TestAppendNil(t *testing.T) {
function TestAppendBeginMarker (line 25) | func TestAppendBeginMarker(t *testing.T) {
function TestAppendEndMarker (line 34) | func TestAppendEndMarker(t *testing.T) {
function TestAppendObjectData (line 43) | func TestAppendObjectData(t *testing.T) {
function TestAppendArrayDelim (line 53) | func TestAppendArrayDelim(t *testing.T) {
function TestAppendLineBreak (line 62) | func TestAppendLineBreak(t *testing.T) {
function TestAppendInterface (line 72) | func TestAppendInterface(t *testing.T) {
function TestAppendType (line 109) | func TestAppendType(t *testing.T) {
function TestAppendBool (line 136) | func TestAppendBool(t *testing.T) {
function TestAppendBoolArray (line 148) | func TestAppendBoolArray(t *testing.T) {
function TestAppendInt8 (line 188) | func TestAppendInt8(t *testing.T) {
function TestAppendInts8 (line 203) | func TestAppendInts8(t *testing.T) {
function TestAppendInt16 (line 251) | func TestAppendInt16(t *testing.T) {
function TestAppendInts16 (line 266) | func TestAppendInts16(t *testing.T) {
function TestAppendInt32 (line 314) | func TestAppendInt32(t *testing.T) {
function TestAppendInts32 (line 329) | func TestAppendInts32(t *testing.T) {
function TestAppendInt64 (line 377) | func TestAppendInt64(t *testing.T) {
function TestAppendInts64 (line 389) | func TestAppendInts64(t *testing.T) {
function TestAppendInt (line 434) | func TestAppendInt(t *testing.T) {
function TestAppendInts (line 446) | func TestAppendInts(t *testing.T) {
function TestAppendUint8 (line 491) | func TestAppendUint8(t *testing.T) {
function TestAppendUints8 (line 506) | func TestAppendUints8(t *testing.T) {
function TestAppendUint16 (line 554) | func TestAppendUint16(t *testing.T) {
function TestAppendUints16 (line 570) | func TestAppendUints16(t *testing.T) {
function TestAppendUint32 (line 618) | func TestAppendUint32(t *testing.T) {
function TestAppendUints32 (line 634) | func TestAppendUints32(t *testing.T) {
function TestAppendUint64 (line 682) | func TestAppendUint64(t *testing.T) {
function TestAppendUints64 (line 695) | func TestAppendUints64(t *testing.T) {
function TestAppendUint (line 740) | func TestAppendUint(t *testing.T) {
function TestAppendUints (line 756) | func TestAppendUints(t *testing.T) {
function TestAppendIntArray (line 805) | func TestAppendIntArray(t *testing.T) {
function TestAppendFloat32 (line 817) | func TestAppendFloat32(t *testing.T) {
function TestAppendFloats32 (line 830) | func TestAppendFloats32(t *testing.T) {
function TestAppendFloat64 (line 871) | func TestAppendFloat64(t *testing.T) {
function TestAppendFloats64 (line 883) | func TestAppendFloats64(t *testing.T) {
function TestAppendNetworkAddr (line 924) | func TestAppendNetworkAddr(t *testing.T) {
function TestAppendIPAddrArray (line 936) | func TestAppendIPAddrArray(t *testing.T) {
function TestAppendMACAddr (line 964) | func TestAppendMACAddr(t *testing.T) {
function TestAppendIPPrefix (line 976) | func TestAppendIPPrefix(t *testing.T) {
function TestAppendIPPrefixArray (line 988) | func TestAppendIPPrefixArray(t *testing.T) {
function TestAppendHex (line 1016) | func TestAppendHex(t *testing.T) {
function BenchmarkAppendInt (line 1042) | func BenchmarkAppendInt(b *testing.B) {
function BenchmarkAppendFloat (line 1088) | func BenchmarkAppendFloat(b *testing.B) {
FILE: internal/json/base.go
type Encoder (line 11) | type Encoder struct
method AppendKey (line 14) | func (e Encoder) AppendKey(dst []byte, key string) []byte {
FILE: internal/json/base_test.go
function TestAppendKey (line 8) | func TestAppendKey(t *testing.T) {
FILE: internal/json/bytes.go
method AppendBytes (line 6) | func (Encoder) AppendBytes(dst, s []byte) []byte {
method AppendHex (line 23) | func (Encoder) AppendHex(dst, s []byte) []byte {
function appendBytesComplex (line 33) | func appendBytesComplex(dst, s []byte, i int) []byte {
FILE: internal/json/bytes_test.go
function TestAppendBytes (line 12) | func TestAppendBytes(t *testing.T) {
function TestAppendHex (line 21) | func TestAppendHex(t *testing.T) {
function TestStringBytes (line 30) | func TestStringBytes(t *testing.T) {
function BenchmarkAppendBytes (line 67) | func BenchmarkAppendBytes(b *testing.B) {
FILE: internal/json/float_test.go
function TestEncoder_AppendFloat64 (line 101) | func TestEncoder_AppendFloat64(t *testing.T) {
function FuzzEncoder_AppendFloat64 (line 113) | func FuzzEncoder_AppendFloat64(f *testing.F) {
function TestEncoder_AppendFloat32 (line 247) | func TestEncoder_AppendFloat32(t *testing.T) {
function FuzzEncoder_AppendFloat32 (line 259) | func FuzzEncoder_AppendFloat32(f *testing.F) {
function generateFloat32s (line 307) | func generateFloat32s(n int) []float32 {
function generateFloat64s (line 315) | func generateFloat64s(n int) []float64 {
function TestAppendFloats32 (line 323) | func TestAppendFloats32(t *testing.T) {
function TestAppendFloats64 (line 365) | func TestAppendFloats64(t *testing.T) {
function BenchmarkEncoder_AppendFloat32 (line 408) | func BenchmarkEncoder_AppendFloat32(b *testing.B) {
function BenchmarkEncoder_AppendFloat64 (line 422) | func BenchmarkEncoder_AppendFloat64(b *testing.B) {
FILE: internal/json/int_test.go
function TestAppendInts8 (line 12) | func TestAppendInts8(t *testing.T) {
function TestAppendUints8 (line 45) | func TestAppendUints8(t *testing.T) {
function TestAppendInts16 (line 78) | func TestAppendInts16(t *testing.T) {
function TestAppendUints16 (line 111) | func TestAppendUints16(t *testing.T) {
function TestAppendInts32 (line 144) | func TestAppendInts32(t *testing.T) {
function TestAppendUints32 (line 177) | func TestAppendUints32(t *testing.T) {
function TestAppendInt64 (line 211) | func TestAppendInt64(t *testing.T) {
function TestAppendUints64 (line 241) | func TestAppendUints64(t *testing.T) {
function TestAppendInt (line 272) | func TestAppendInt(t *testing.T) {
function TestAppendUint (line 284) | func TestAppendUint(t *testing.T) {
function TestAppendInts (line 297) | func TestAppendInts(t *testing.T) {
function TestAppendUints (line 327) | func TestAppendUints(t *testing.T) {
FILE: internal/json/string.go
constant hexCharacters (line 8) | hexCharacters = "0123456789abcdef"
function init (line 12) | func init() {
method AppendStrings (line 20) | func (e Encoder) AppendStrings(dst []byte, vals []string) []byte {
method AppendString (line 44) | func (Encoder) AppendString(dst []byte, s string) []byte {
method AppendStringers (line 68) | func (e Encoder) AppendStringers(dst []byte, vals []fmt.Stringer) []byte {
method AppendStringer (line 84) | func (e Encoder) AppendStringer(dst []byte, val fmt.Stringer) []byte {
function appendStringComplex (line 94) | func appendStringComplex(dst []byte, s string, i int) []byte {
FILE: internal/json/string_test.go
function TestAppendString (line 9) | func TestAppendString(t *testing.T) {
function TestAppendStrings (line 18) | func TestAppendStrings(t *testing.T) {
function TestAppendStringer (line 27) | func TestAppendStringer(t *testing.T) {
function TestAppendStringers (line 45) | func TestAppendStringers(t *testing.T) {
function BenchmarkAppendString (line 54) | func BenchmarkAppendString(b *testing.B) {
FILE: internal/json/time.go
constant timeFormatUnix (line 10) | timeFormatUnix = ""
constant timeFormatUnixMs (line 11) | timeFormatUnixMs = "UNIXMS"
constant timeFormatUnixMicro (line 12) | timeFormatUnixMicro = "UNIXMICRO"
constant timeFormatUnixNano (line 13) | timeFormatUnixNano = "UNIXNANO"
constant durationFormatFloat (line 14) | durationFormatFloat = "float"
constant durationFormatInt (line 15) | durationFormatInt = "int"
constant durationFormatString (line 16) | durationFormatString = "string"
method AppendTime (line 21) | func (e Encoder) AppendTime(dst []byte, t time.Time, format string) []by...
method AppendTimes (line 37) | func (Encoder) AppendTimes(dst []byte, vals []time.Time, format string) ...
function appendUnixTimes (line 62) | func appendUnixTimes(dst []byte, vals []time.Time) []byte {
function appendUnixNanoTimes (line 77) | func appendUnixNanoTimes(dst []byte, vals []time.Time, div int64) []byte {
method AppendDuration (line 94) | func (e Encoder) AppendDuration(dst []byte, d time.Duration, unit time.D...
method AppendDurations (line 111) | func (e Encoder) AppendDurations(dst []byte, vals []time.Duration, unit ...
FILE: internal/json/time_test.go
function TestEncoder_AppendDuration (line 13) | func TestEncoder_AppendDuration(t *testing.T) {
function TestEncoder_AppendDurations (line 82) | func TestEncoder_AppendDurations(t *testing.T) {
function TestAppendTimeNow (line 151) | func TestAppendTimeNow(t *testing.T) {
function TestAppendTimePastPresentInteger (line 164) | func TestAppendTimePastPresentInteger(t *testing.T) {
function TestAppendTimePastPresentFloat (line 207) | func TestAppendTimePastPresentFloat(t *testing.T) {
function TestAppendTimes (line 225) | func TestAppendTimes(t *testing.T) {
function TestAppendDurationFloat (line 278) | func TestAppendDurationFloat(t *testing.T) {
function TestAppendDurationInteger (line 303) | func TestAppendDurationInteger(t *testing.T) {
function TestAppendDurations (line 318) | func TestAppendDurations(t *testing.T) {
function BenchmarkAppendTime (line 354) | func BenchmarkAppendTime(b *testing.B) {
FILE: internal/json/types.go
method AppendNil (line 12) | func (Encoder) AppendNil(dst []byte) []byte {
method AppendBeginMarker (line 17) | func (Encoder) AppendBeginMarker(dst []byte) []byte {
method AppendEndMarker (line 22) | func (Encoder) AppendEndMarker(dst []byte) []byte {
method AppendLineBreak (line 27) | func (Encoder) AppendLineBreak(dst []byte) []byte {
method AppendArrayStart (line 32) | func (Encoder) AppendArrayStart(dst []byte) []byte {
method AppendArrayEnd (line 37) | func (Encoder) AppendArrayEnd(dst []byte) []byte {
method AppendArrayDelim (line 42) | func (Encoder) AppendArrayDelim(dst []byte) []byte {
method AppendBool (line 51) | func (Encoder) AppendBool(dst []byte, val bool) []byte {
method AppendBools (line 57) | func (Encoder) AppendBools(dst []byte, vals []bool) []byte {
method AppendInt (line 74) | func (Encoder) AppendInt(dst []byte, val int) []byte {
method AppendInts (line 80) | func (Encoder) AppendInts(dst []byte, vals []int) []byte {
method AppendInt8 (line 97) | func (Encoder) AppendInt8(dst []byte, val int8) []byte {
method AppendInts8 (line 103) | func (Encoder) AppendInts8(dst []byte, vals []int8) []byte {
method AppendInt16 (line 120) | func (Encoder) AppendInt16(dst []byte, val int16) []byte {
method AppendInts16 (line 126) | func (Encoder) AppendInts16(dst []byte, vals []int16) []byte {
method AppendInt32 (line 143) | func (Encoder) AppendInt32(dst []byte, val int32) []byte {
method AppendInts32 (line 149) | func (Encoder) AppendInts32(dst []byte, vals []int32) []byte {
method AppendInt64 (line 166) | func (Encoder) AppendInt64(dst []byte, val int64) []byte {
method AppendInts64 (line 172) | func (Encoder) AppendInts64(dst []byte, vals []int64) []byte {
method AppendUint (line 189) | func (Encoder) AppendUint(dst []byte, val uint) []byte {
method AppendUints (line 195) | func (Encoder) AppendUints(dst []byte, vals []uint) []byte {
method AppendUint8 (line 212) | func (Encoder) AppendUint8(dst []byte, val uint8) []byte {
method AppendUints8 (line 218) | func (Encoder) AppendUints8(dst []byte, vals []uint8) []byte {
method AppendUint16 (line 235) | func (Encoder) AppendUint16(dst []byte, val uint16) []byte {
method AppendUints16 (line 241) | func (Encoder) AppendUints16(dst []byte, vals []uint16) []byte {
method AppendUint32 (line 258) | func (Encoder) AppendUint32(dst []byte, val uint32) []byte {
method AppendUints32 (line 264) | func (Encoder) AppendUints32(dst []byte, vals []uint32) []byte {
method AppendUint64 (line 281) | func (Encoder) AppendUint64(dst []byte, val uint64) []byte {
method AppendUints64 (line 287) | func (Encoder) AppendUints64(dst []byte, vals []uint64) []byte {
function appendFloat (line 302) | func appendFloat(dst []byte, val float64, bitSize, precision int) []byte {
method AppendFloat32 (line 340) | func (Encoder) AppendFloat32(dst []byte, val float32, precision int) []b...
method AppendFloats32 (line 346) | func (Encoder) AppendFloats32(dst []byte, vals []float32, precision int)...
method AppendFloat64 (line 363) | func (Encoder) AppendFloat64(dst []byte, val float64, precision int) []b...
method AppendFloats64 (line 369) | func (Encoder) AppendFloats64(dst []byte, vals []float64, precision int)...
method AppendInterface (line 386) | func (e Encoder) AppendInterface(dst []byte, i interface{}) []byte {
method AppendType (line 395) | func (e Encoder) AppendType(dst []byte, i interface{}) []byte {
method AppendObjectData (line 404) | func (Encoder) AppendObjectData(dst []byte, o []byte) []byte {
method AppendIPAddr (line 422) | func (e Encoder) AppendIPAddr(dst []byte, ip net.IP) []byte {
method AppendIPAddrs (line 427) | func (e Encoder) AppendIPAddrs(dst []byte, ips []net.IP) []byte {
method AppendIPPrefix (line 443) | func (e Encoder) AppendIPPrefix(dst []byte, pfx net.IPNet) []byte {
method AppendIPPrefixes (line 448) | func (e Encoder) AppendIPPrefixes(dst []byte, pfxs []net.IPNet) []byte {
method AppendMACAddr (line 464) | func (e Encoder) AppendMACAddr(dst []byte, ha net.HardwareAddr) []byte {
FILE: internal/json/types_test.go
function TestAppendNil (line 16) | func TestAppendNil(t *testing.T) {
function TestAppendBeginMarker (line 25) | func TestAppendBeginMarker(t *testing.T) {
function TestAppendEndMarker (line 34) | func TestAppendEndMarker(t *testing.T) {
function TestAppendArrayStart (line 43) | func TestAppendArrayStart(t *testing.T) {
function TestAppendArrayEnd (line 52) | func TestAppendArrayEnd(t *testing.T) {
function TestAppendArrayDelim (line 61) | func TestAppendArrayDelim(t *testing.T) {
function TestAppendLineBreak (line 78) | func TestAppendLineBreak(t *testing.T) {
function interfaceMarshalFunc (line 89) | func interfaceMarshalFunc(v interface{}) ([]byte, error) {
function TestAppendInterface (line 105) | func TestAppendInterface(t *testing.T) {
function TestAppendType (line 139) | func TestAppendType(t *testing.T) {
function TestAppendMAC (line 200) | func TestAppendMAC(t *testing.T) {
function TestAppendBool (line 218) | func TestAppendBool(t *testing.T) {
function TestAppendBoolArray (line 231) | func TestAppendBoolArray(t *testing.T) {
function TestAppendIP (line 281) | func TestAppendIP(t *testing.T) {
function TestAppendIPAddrs (line 323) | func TestAppendIPAddrs(t *testing.T) {
function TestAppendIPPrefixes (line 342) | func TestAppendIPPrefixes(t *testing.T) {
function TestAppendIPPrefix (line 352) | func TestAppendIPPrefix(t *testing.T) {
function TestAppendMACAddr (line 386) | func TestAppendMACAddr(t *testing.T) {
function TestAppendType2 (line 404) | func TestAppendType2(t *testing.T) {
function TestAppendObjectData (line 426) | func TestAppendObjectData(t *testing.T) {
FILE: internal/testcases.go
type UnsignedIntTestCase (line 107) | type UnsignedIntTestCase struct
function unsignedIntegerTestCases (line 125) | func unsignedIntegerTestCases() []UnsignedIntTestCase {
function InterfaceMarshalFunc (line 363) | func InterfaceMarshalFunc(v interface{}) ([]byte, error) {
FILE: journald/journald.go
constant defaultJournalDPrio (line 32) | defaultJournalDPrio = journal.PriNotice
function NewJournalDWriter (line 38) | func NewJournalDWriter() io.Writer {
type journalWriter (line 42) | type journalWriter struct
method Write (line 72) | func (w journalWriter) Write(p []byte) (n int, err error) {
function levelToJPrio (line 48) | func levelToJPrio(zLevel string) journal.Priority {
FILE: journald/journald_test.go
function ExampleNewJournalDWriter (line 14) | func ExampleNewJournalDWriter() {
function TestWriteReturnsNoOfWrittenBytes (line 52) | func TestWriteReturnsNoOfWrittenBytes(t *testing.T) {
function TestMultiWrite (line 67) | func TestMultiWrite(t *testing.T) {
FILE: log.go
type Level (line 127) | type Level
method String (line 152) | func (l Level) String() string {
method UnmarshalText (line 210) | func (l *Level) UnmarshalText(text []byte) error {
method MarshalText (line 220) | func (l Level) MarshalText() ([]byte, error) {
constant DebugLevel (line 131) | DebugLevel Level = iota
constant InfoLevel (line 133) | InfoLevel
constant WarnLevel (line 135) | WarnLevel
constant ErrorLevel (line 137) | ErrorLevel
constant FatalLevel (line 139) | FatalLevel
constant PanicLevel (line 141) | PanicLevel
constant NoLevel (line 143) | NoLevel
constant Disabled (line 145) | Disabled
constant TraceLevel (line 148) | TraceLevel Level = -1
function ParseLevel (line 178) | func ParseLevel(levelStr string) (Level, error) {
type Logger (line 229) | type Logger struct
method Output (line 263) | func (l Logger) Output(w io.Writer) Logger {
method With (line 279) | func (l Logger) With() Context {
method UpdateContext (line 296) | func (l *Logger) UpdateContext(update func(c Context) Context) {
method Level (line 311) | func (l Logger) Level(lvl Level) Logger {
method GetLevel (line 317) | func (l Logger) GetLevel() Level {
method Sample (line 322) | func (l Logger) Sample(s Sampler) Logger {
method Hook (line 328) | func (l Logger) Hook(hooks ...Hook) Logger {
method Trace (line 341) | func (l *Logger) Trace() *Event {
method Debug (line 348) | func (l *Logger) Debug() *Event {
method Info (line 355) | func (l *Logger) Info() *Event {
method Warn (line 362) | func (l *Logger) Warn() *Event {
method Error (line 369) | func (l *Logger) Error() *Event {
method Err (line 377) | func (l *Logger) Err(err error) *Event {
method Fatal (line 390) | func (l *Logger) Fatal() *Event {
method Panic (line 410) | func (l *Logger) Panic() *Event {
method WithLevel (line 419) | func (l *Logger) WithLevel(level Level) *Event {
method Log (line 448) | func (l *Logger) Log() *Event {
method Print (line 454) | func (l *Logger) Print(v ...interface{}) {
method Printf (line 462) | func (l *Logger) Printf(format string, v ...interface{}) {
method Println (line 470) | func (l *Logger) Println(v ...interface{}) {
method Write (line 478) | func (l Logger) Write(p []byte) (n int, err error) {
method newEvent (line 488) | func (l *Logger) newEvent(level Level, done func(string)) *Event {
method scratchEvent (line 507) | func (l *Logger) scratchEvent() *Event {
method disabled (line 512) | func (l *Logger) disabled() bool {
method should (line 517) | func (l *Logger) should(lvl Level) bool {
function New (line 246) | func New(w io.Writer) Logger {
function Nop (line 258) | func Nop() Logger {
FILE: log/log.go
function Output (line 17) | func Output(w io.Writer) zerolog.Logger {
function With (line 22) | func With() zerolog.Context {
function Level (line 27) | func Level(level zerolog.Level) zerolog.Logger {
function Sample (line 32) | func Sample(s zerolog.Sampler) zerolog.Logger {
function Hook (line 37) | func Hook(h zerolog.Hook) zerolog.Logger {
function Err (line 45) | func Err(err error) *zerolog.Event {
function Trace (line 52) | func Trace() *zerolog.Event {
function Debug (line 59) | func Debug() *zerolog.Event {
function Info (line 66) | func Info() *zerolog.Event {
function Warn (line 73) | func Warn() *zerolog.Event {
function Error (line 80) | func Error() *zerolog.Event {
function Fatal (line 88) | func Fatal() *zerolog.Event {
function Panic (line 96) | func Panic() *zerolog.Event {
function WithLevel (line 103) | func WithLevel(level zerolog.Level) *zerolog.Event {
function Log (line 111) | func Log() *zerolog.Event {
function Print (line 117) | func Print(v ...interface{}) {
function Printf (line 123) | func Printf(format string, v ...interface{}) {
function Ctx (line 129) | func Ctx(ctx context.Context) *zerolog.Logger {
FILE: log/log_example_test.go
function setup (line 21) | func setup() {
function ExamplePrint (line 37) | func ExamplePrint() {
function ExamplePrintf (line 45) | func ExamplePrintf() {
function ExampleLog (line 53) | func ExampleLog() {
function ExampleErr (line 61) | func ExampleErr() {
function ExampleTrace (line 72) | func ExampleTrace() {
function ExampleDebug (line 80) | func ExampleDebug() {
function ExampleInfo (line 88) | func ExampleInfo() {
function ExampleWarn (line 96) | func ExampleWarn() {
function ExampleError (line 104) | func ExampleError() {
function ExampleFatal (line 112) | func ExampleFatal() {
function ExamplePanic (line 126) | func ExamplePanic() {
function Example (line 135) | func Example() {
function ExampleOutput (line 160) | func ExampleOutput() {
function ExampleWith (line 173) | func ExampleWith() {
function ExampleLevel (line 184) | func ExampleLevel() {
type valueKeyType (line 195) | type valueKeyType
function ExampleLogger_Hook (line 206) | func ExampleLogger_Hook() {
function ExampleWithLevel (line 215) | func ExampleWithLevel() {
function ExampleCtx (line 226) | func ExampleCtx() {
function ExampleSample (line 237) | func ExampleSample() {
FILE: log_example_test.go
function ExampleNew (line 16) | func ExampleNew() {
function ExampleLogger_With (line 23) | func ExampleLogger_With() {
function ExampleLogger_Level (line 34) | func ExampleLogger_Level() {
function ExampleLogger_Sample (line 43) | func ExampleLogger_Sample() {
type LevelNameHook (line 55) | type LevelNameHook struct
method Run (line 57) | func (h LevelNameHook) Run(e *zerolog.Event, l zerolog.Level, msg stri...
type MessageHook (line 65) | type MessageHook
method Run (line 67) | func (h MessageHook) Run(e *zerolog.Event, l zerolog.Level, msg string) {
function ExampleLogger_Hook (line 71) | func ExampleLogger_Hook() {
function ExampleLogger_Print (line 82) | func ExampleLogger_Print() {
function ExampleLogger_Printf (line 90) | func ExampleLogger_Printf() {
function ExampleLogger_Println (line 98) | func ExampleLogger_Println() {
function ExampleLogger_Trace (line 106) | func ExampleLogger_Trace() {
function ExampleLogger_Debug (line 117) | func ExampleLogger_Debug() {
function ExampleLogger_Info (line 128) | func ExampleLogger_Info() {
function ExampleLogger_Warn (line 139) | func ExampleLogger_Warn() {
function ExampleLogger_Error (line 149) | func ExampleLogger_Error() {
function ExampleLogger_WithLevel (line 159) | func ExampleLogger_WithLevel() {
function ExampleLogger_Write (line 168) | func ExampleLogger_Write() {
function ExampleLogger_Log (line 181) | func ExampleLogger_Log() {
function ExampleEvent_Dict (line 192) | func ExampleEvent_Dict() {
type User (line 207) | type User struct
method MarshalZerologObject (line 213) | func (u User) MarshalZerologObject(e *zerolog.Event) {
type Price (line 219) | type Price struct
method MarshalZerologObject (line 225) | func (p Price) MarshalZerologObject(e *zerolog.Event) {
type Users (line 235) | type Users
method MarshalZerologArray (line 237) | func (uu Users) MarshalZerologArray(a *zerolog.Array) {
function ExampleEvent_Array (line 243) | func ExampleEvent_Array() {
function ExampleEvent_Array_object (line 262) | func ExampleEvent_Array_object() {
function ExampleEvent_Object (line 279) | func ExampleEvent_Object() {
function ExampleEvent_EmbedObject (line 293) | func ExampleEvent_EmbedObject() {
function ExampleEvent_Interface (line 306) | func ExampleEvent_Interface() {
function ExampleEvent_Dur (line 323) | func ExampleEvent_Dur() {
function ExampleEvent_Durs (line 336) | func ExampleEvent_Durs() {
function ExampleEvent_Fields_map (line 352) | func ExampleEvent_Fields_map() {
function ExampleEvent_Fields_slice (line 368) | func ExampleEvent_Fields_slice() {
function ExampleContext_Dict (line 384) | func ExampleContext_Dict() {
function ExampleContext_Array (line 398) | func ExampleContext_Array() {
function ExampleContext_Array_object (line 412) | func ExampleContext_Array_object() {
function ExampleContext_Object (line 429) | func ExampleContext_Object() {
function ExampleContext_Objects (line 442) | func ExampleContext_Objects() {
function ExampleContext_EmbedObject (line 457) | func ExampleContext_EmbedObject() {
function ExampleContext_Interface (line 471) | func ExampleContext_Interface() {
function ExampleContext_Dur (line 488) | func ExampleContext_Dur() {
function ExampleContext_Durs (line 501) | func ExampleContext_Durs() {
function ExampleContext_IPAddr (line 517) | func ExampleContext_IPAddr() {
function ExampleContext_IPAddrs (line 528) | func ExampleContext_IPAddrs() {
function ExampleContext_IPPrefix (line 539) | func ExampleContext_IPPrefix() {
function ExampleContext_IPPrefixes (line 550) | func ExampleContext_IPPrefixes() {
function ExampleContext_MACAddr (line 561) | func ExampleContext_MACAddr() {
function ExampleContext_Fields_map (line 572) | func ExampleContext_Fields_map() {
function ExampleContext_Fields_slice (line 588) | func ExampleContext_Fields_slice() {
function ExampleContext_Times (line 604) | func ExampleContext_Times() {
FILE: log_test.go
function TestLog (line 19) | func TestLog(t *testing.T) {
function TestInfo (line 51) | func TestInfo(t *testing.T) {
function TestEmptyLevelFieldName (line 83) | func TestEmptyLevelFieldName(t *testing.T) {
function TestWith (line 101) | func TestWith(t *testing.T) {
function TestStackedWiths (line 159) | func TestStackedWiths(t *testing.T) {
function TestWithPlurals (line 173) | func TestWithPlurals(t *testing.T) {
function TestWithReset (line 204) | func TestWithReset(t *testing.T) {
function TestFieldsMap (line 224) | func TestFieldsMap(t *testing.T) {
function TestFieldsMap_Arrays (line 259) | func TestFieldsMap_Arrays(t *testing.T) {
function TestWithErr (line 291) | func TestWithErr(t *testing.T) {
function TestFieldsErr (line 309) | func TestFieldsErr(t *testing.T) {
function TestFieldsErrs (line 324) | func TestFieldsErrs(t *testing.T) {
function TestFieldsMapPnt (line 336) | func TestFieldsMapPnt(t *testing.T) {
function TestFieldsMapNilPnt (line 362) | func TestFieldsMapNilPnt(t *testing.T) {
function TestFieldsSlice (line 408) | func TestFieldsSlice(t *testing.T) {
function TestFieldsSliceExtraneous (line 439) | func TestFieldsSliceExtraneous(t *testing.T) {
function TestFieldsNotMapSlice (line 455) | func TestFieldsNotMapSlice(t *testing.T) {
function TestFields (line 468) | func TestFields(t *testing.T) {
function TestFieldsArrayEmpty (line 518) | func TestFieldsArrayEmpty(t *testing.T) {
function TestFieldsArraySingleElement (line 548) | func TestFieldsArraySingleElement(t *testing.T) {
function TestFieldsArrayMultipleElement (line 578) | func TestFieldsArrayMultipleElement(t *testing.T) {
function TestFieldsDisabled (line 608) | func TestFieldsDisabled(t *testing.T) {
function TestMsgf (line 649) | func TestMsgf(t *testing.T) {
function TestWithAndFieldsCombined (line 658) | func TestWithAndFieldsCombined(t *testing.T) {
function TestLevel (line 667) | func TestLevel(t *testing.T) {
function TestGetLevel (line 723) | func TestGetLevel(t *testing.T) {
function TestSampling (line 741) | func TestSampling(t *testing.T) {
function TestDisableSampling (line 753) | func TestDisableSampling(t *testing.T) {
function TestDiscard (line 775) | func TestDiscard(t *testing.T) {
type levelWriter (line 790) | type levelWriter struct
method Write (line 797) | func (lw *levelWriter) Write(p []byte) (int, error) {
method WriteLevel (line 801) | func (lw *levelWriter) WriteLevel(lvl Level, p []byte) (int, error) {
method Close (line 810) | func (lw *levelWriter) Close() error {
function TestLevelWriter (line 814) | func TestLevelWriter(t *testing.T) {
function TestDisabledLevel (line 875) | func TestDisabledLevel(t *testing.T) {
function TestPanicLevel (line 901) | func TestPanicLevel(t *testing.T) {
function TestFatalLevel (line 934) | func TestFatalLevel(t *testing.T) {
function TestFatalDisabled (line 972) | func TestFatalDisabled(t *testing.T) {
function TestPanicDisabled (line 995) | func TestPanicDisabled(t *testing.T) {
function TestLoggerShouldWithNilWriter (line 1014) | func TestLoggerShouldWithNilWriter(t *testing.T) {
function TestContextTimestamp (line 1024) | func TestContextTimestamp(t *testing.T) {
function TestEventTimestamp (line 1040) | func TestEventTimestamp(t *testing.T) {
function TestOutputWithoutTimestamp (line 1056) | func TestOutputWithoutTimestamp(t *testing.T) {
function TestOutputWithTimestamp (line 1067) | func TestOutputWithTimestamp(t *testing.T) {
function TestOutputWithContext (line 1084) | func TestOutputWithContext(t *testing.T) {
function TestCallerMarshalFunc (line 1095) | func TestCallerMarshalFunc(t *testing.T) {
function TestLevelFieldMarshalFunc (line 1128) | func TestLevelFieldMarshalFunc(t *testing.T) {
type errWriter (line 1164) | type errWriter struct
method Write (line 1168) | func (w errWriter) Write(p []byte) (n int, err error) {
function TestErrorHandler (line 1172) | func TestErrorHandler(t *testing.T) {
function TestUpdateEmptyContext (line 1185) | func TestUpdateEmptyContext(t *testing.T) {
function TestUpdateContextOnDisabledLogger (line 1201) | func TestUpdateContextOnDisabledLogger(t *testing.T) {
function TestUpdateContextOnNopLogger (line 1217) | func TestUpdateContextOnNopLogger(t *testing.T) {
function TestUpdateContextOnZeroValueLogger (line 1234) | func TestUpdateContextOnZeroValueLogger(t *testing.T) {
function TestLevel_String (line 1250) | func TestLevel_String(t *testing.T) {
function TestLevel_MarshalText (line 1275) | func TestLevel_MarshalText(t *testing.T) {
function TestParseLevel (line 1302) | func TestParseLevel(t *testing.T) {
function TestUnmarshalTextLevel (line 1339) | func TestUnmarshalTextLevel(t *testing.T) {
function TestUnmarshalTextLevelNil (line 1377) | func TestUnmarshalTextLevelNil(t *testing.T) {
function TestHTMLNoEscaping (line 1385) | func TestHTMLNoEscaping(t *testing.T) {
FILE: not_go112.go
constant contextCallerSkipFrameCount (line 5) | contextCallerSkipFrameCount = 3
FILE: pkgerrors/stacktrace.go
type state (line 13) | type state struct
method Write (line 18) | func (s *state) Write(b []byte) (n int, err error) {
method Width (line 24) | func (s *state) Width() (wid int, ok bool) {
method Precision (line 29) | func (s *state) Precision() (prec int, ok bool) {
method Flag (line 34) | func (s *state) Flag(c int) bool {
function frameField (line 38) | func frameField(f errors.Frame, s *state, c rune) string {
function MarshalStack (line 46) | func MarshalStack(err error) interface{} {
FILE: pkgerrors/stacktrace_test.go
function TestLogStack (line 15) | func TestLogStack(t *testing.T) {
function TestLogStackFields (line 31) | func TestLogStackFields(t *testing.T) {
function TestLogStackFromContext (line 47) | func TestLogStackFromContext(t *testing.T) {
function TestLogStackFromContextWith (line 63) | func TestLogStackFromContextWith(t *testing.T) {
function BenchmarkLogStack (line 79) | func BenchmarkLogStack(b *testing.B) {
FILE: sampler.go
type Sampler (line 19) | type Sampler interface
type RandomSampler (line 27) | type RandomSampler
method Sample (line 30) | func (s RandomSampler) Sample(lvl Level) bool {
type BasicSampler (line 42) | type BasicSampler struct
method Sample (line 48) | func (s *BasicSampler) Sample(lvl Level) bool {
type BurstSampler (line 62) | type BurstSampler struct
method Sample (line 77) | func (s *BurstSampler) Sample(lvl Level) bool {
method inc (line 89) | func (s *BurstSampler) inc() uint32 {
type LevelSampler (line 109) | type LevelSampler struct
method Sample (line 113) | func (s LevelSampler) Sample(lvl Level) bool {
FILE: sampler_test.go
function TestSamplers (line 76) | func TestSamplers(t *testing.T) {
function BenchmarkSamplers (line 94) | func BenchmarkSamplers(b *testing.B) {
function TestBurst (line 108) | func TestBurst(t *testing.T) {
function TestLevelSampler (line 139) | func TestLevelSampler(t *testing.T) {
FILE: slog.go
type SlogHandler (line 12) | type SlogHandler struct
method Enabled (line 27) | func (h *SlogHandler) Enabled(_ context.Context, level slog.Level) bool {
method Handle (line 40) | func (h *SlogHandler) Handle(ctx context.Context, record slog.Record) ...
method hasTimestampHook (line 77) | func (h *SlogHandler) hasTimestampHook() bool {
method WithAttrs (line 88) | func (h *SlogHandler) WithAttrs(attrs []slog.Attr) slog.Handler {
method WithGroup (line 99) | func (h *SlogHandler) WithGroup(name string) slog.Handler {
method clone (line 112) | func (h *SlogHandler) clone() *SlogHandler {
function NewSlogHandler (line 21) | func NewSlogHandler(logger Logger) *SlogHandler {
function slogToZerologLevel (line 128) | func slogToZerologLevel(level slog.Level) Level {
function zerologToSlogLevel (line 144) | func zerologToSlogLevel(level Level) slog.Level {
function joinPrefix (line 167) | func joinPrefix(prefix, key string) string {
function appendSlogAttr (line 179) | func appendSlogAttr(event *Event, attr slog.Attr, prefix string) *Event {
FILE: slog_test.go
function newSlogLogger (line 16) | func newSlogLogger(buf *bytes.Buffer) *slog.Logger {
function decodeOutput (line 23) | func decodeOutput(buf *bytes.Buffer) string {
function decodeJSON (line 31) | func decodeJSON(t *testing.T, buf *bytes.Buffer) map[string]interface{} {
function TestSlogHandler_BasicInfo (line 41) | func TestSlogHandler_BasicInfo(t *testing.T) {
function TestSlogHandler_Debug (line 56) | func TestSlogHandler_Debug(t *testing.T) {
function TestSlogHandler_Warn (line 72) | func TestSlogHandler_Warn(t *testing.T) {
function TestSlogHandler_Error (line 84) | func TestSlogHandler_Error(t *testing.T) {
function TestSlogHandler_WithStringAttr (line 96) | func TestSlogHandler_WithStringAttr(t *testing.T) {
function TestSlogHandler_WithIntAttr (line 108) | func TestSlogHandler_WithIntAttr(t *testing.T) {
function TestSlogHandler_WithBoolAttr (line 120) | func TestSlogHandler_WithBoolAttr(t *testing.T) {
function TestSlogHandler_WithFloat64Attr (line 132) | func TestSlogHandler_WithFloat64Attr(t *testing.T) {
function TestSlogHandler_WithTimeAttr (line 144) | func TestSlogHandler_WithTimeAttr(t *testing.T) {
function TestSlogHandler_WithDurationAttr (line 157) | func TestSlogHandler_WithDurationAttr(t *testing.T) {
function TestSlogHandler_WithErrorAttr (line 169) | func TestSlogHandler_WithErrorAttr(t *testing.T) {
function TestSlogHandler_WithAttrs (line 181) | func TestSlogHandler_WithAttrs(t *testing.T) {
function TestSlogHandler_WithAttrsEmpty (line 206) | func TestSlogHandler_WithAttrsEmpty(t *testing.T) {
function TestSlogHandler_WithGroup (line 218) | func TestSlogHandler_WithGroup(t *testing.T) {
function TestSlogHandler_WithGroupEmpty (line 237) | func TestSlogHandler_WithGroupEmpty(t *testing.T) {
function TestSlogHandler_WithNestedGroups (line 249) | func TestSlogHandler_WithNestedGroups(t *testing.T) {
function TestSlogHandler_WithGroupAndAttrs (line 265) | func TestSlogHandler_WithGroupAndAttrs(t *testing.T) {
function TestSlogHandler_GroupAttrInRecord (line 286) | func TestSlogHandler_GroupAttrInRecord(t *testing.T) {
function TestSlogHandler_LevelFiltering (line 304) | func TestSlogHandler_LevelFiltering(t *testing.T) {
function TestSlogHandler_FilteredMessageNotWritten (line 327) | func TestSlogHandler_FilteredMessageNotWritten(t *testing.T) {
function TestSlogHandler_MultipleAttrs (line 339) | func TestSlogHandler_MultipleAttrs(t *testing.T) {
function TestSlogHandler_LogValuer (line 365) | func TestSlogHandler_LogValuer(t *testing.T) {
type testLogValuer (line 381) | type testLogValuer struct
method LogValue (line 386) | func (v testLogValuer) LogValue() slog.Value {
function TestSlogHandler_WithAttrsImmutability (line 393) | func TestSlogHandler_WithAttrsImmutability(t *testing.T) {
function TestSlogHandler_LevelMapping (line 410) | func TestSlogHandler_LevelMapping(t *testing.T) {
function TestSlogHandler_EmptyMessage (line 438) | func TestSlogHandler_EmptyMessage(t *testing.T) {
function TestSlogHandler_WithContext (line 450) | func TestSlogHandler_WithContext(t *testing.T) {
function TestSlogHandler_EnabledRespectsGlobalLevel (line 466) | func TestSlogHandler_EnabledRespectsGlobalLevel(t *testing.T) {
function TestSlogHandler_EnabledNilWriter (line 490) | func TestSlogHandler_EnabledNilWriter(t *testing.T) {
function TestSlogHandler_HandlePropagatesContext (line 499) | func TestSlogHandler_HandlePropagatesContext(t *testing.T) {
function TestSlogHandler_NoDuplicateTimestamp (line 523) | func TestSlogHandler_NoDuplicateTimestamp(t *testing.T) {
function TestSlogHandler_TimestampWithoutHook (line 545) | func TestSlogHandler_TimestampWithoutHook(t *testing.T) {
FILE: syslog.go
constant ceePrefix (line 12) | ceePrefix = "@cee:"
type SyslogWriter (line 15) | type SyslogWriter interface
type syslogWriter (line 25) | type syslogWriter struct
method Write (line 44) | func (sw syslogWriter) Write(p []byte) (n int, err error) {
method WriteLevel (line 57) | func (sw syslogWriter) WriteLevel(level Level, p []byte) (n int, err e...
method Close (line 84) | func (sw syslogWriter) Close() error {
function SyslogLevelWriter (line 32) | func SyslogLevelWriter(w SyslogWriter) LevelWriter {
function SyslogCEEWriter (line 40) | func SyslogCEEWriter(w SyslogWriter) LevelWriter {
FILE: syslog_test.go
type syslogEvent (line 14) | type syslogEvent struct
type syslogTestWriter (line 18) | type syslogTestWriter struct
method Write (line 22) | func (w *syslogTestWriter) Write(p []byte) (int, error) {
method Trace (line 25) | func (w *syslogTestWriter) Trace(m string) error {
method Debug (line 29) | func (w *syslogTestWriter) Debug(m string) error {
method Info (line 33) | func (w *syslogTestWriter) Info(m string) error {
method Warning (line 37) | func (w *syslogTestWriter) Warning(m string) error {
method Err (line 41) | func (w *syslogTestWriter) Err(m string) error {
method Emerg (line 45) | func (w *syslogTestWriter) Emerg(m string) error {
method Crit (line 49) | func (w *syslogTestWriter) Crit(m string) error {
function TestSyslogWriter (line 54) | func TestSyslogWriter(t *testing.T) {
type testCEEwriter (line 75) | type testCEEwriter struct
method Debug (line 80) | func (c testCEEwriter) Debug(m string) error { return nil }
method Info (line 82) | func (c testCEEwriter) Info(m string) error {
method Warning (line 87) | func (c testCEEwriter) Warning(m string) error { return nil }
method Err (line 89) | func (c testCEEwriter) Err(m string) error { return nil }
method Emerg (line 91) | func (c testCEEwriter) Emerg(m string) error { return nil }
method Crit (line 93) | func (c testCEEwriter) Crit(m string) error { return nil }
method Write (line 95) | func (c testCEEwriter) Write(b []byte) (int, error) {
function TestSyslogWriter_WithCEE (line 99) | func TestSyslogWriter_WithCEE(t *testing.T) {
type errorSyslogWriter (line 111) | type errorSyslogWriter struct
method Write (line 116) | func (w *errorSyslogWriter) Write(p []byte) (int, error) {
function TestSyslogWriter_Write (line 123) | func TestSyslogWriter_Write(t *testing.T) {
function TestSyslogWriter_WriteLevel_AllLevels (line 161) | func TestSyslogWriter_WriteLevel_AllLevels(t *testing.T) {
type closableSyslogWriter (line 189) | type closableSyslogWriter struct
method Close (line 194) | func (w *closableSyslogWriter) Close() error {
function TestSyslogWriter_Close (line 199) | func TestSyslogWriter_Close(t *testing.T) {
function TestSyslogWriter_WriteLevel_InvalidLevel (line 222) | func TestSyslogWriter_WriteLevel_InvalidLevel(t *testing.T) {
FILE: writer.go
type LevelWriter (line 15) | type LevelWriter interface
type LevelWriterAdapter (line 21) | type LevelWriterAdapter struct
method WriteLevel (line 26) | func (lw LevelWriterAdapter) WriteLevel(l Level, p []byte) (n int, err...
method Close (line 32) | func (lw LevelWriterAdapter) Close() error {
type syncWriter (line 39) | type syncWriter struct
method Write (line 56) | func (s *syncWriter) Write(p []byte) (n int, err error) {
method WriteLevel (line 63) | func (s *syncWriter) WriteLevel(l Level, p []byte) (n int, err error) {
method Close (line 69) | func (s *syncWriter) Close() error {
function SyncWriter (line 48) | func SyncWriter(w io.Writer) io.Writer {
type multiLevelWriter (line 78) | type multiLevelWriter struct
method Write (line 82) | func (t multiLevelWriter) Write(p []byte) (n int, err error) {
method WriteLevel (line 96) | func (t multiLevelWriter) WriteLevel(l Level, p []byte) (n int, err er...
method Close (line 113) | func (t multiLevelWriter) Close() error {
function MultiLevelWriter (line 127) | func MultiLevelWriter(writers ...io.Writer) LevelWriter {
type TestingLog (line 140) | type TestingLog interface
type TestWriter (line 147) | type TestWriter struct
method Write (line 160) | func (t TestWriter) Write(p []byte) (n int, err error) {
function NewTestWriter (line 155) | func NewTestWriter(t TestingLog) TestWriter {
function ConsoleTestWriter (line 184) | func ConsoleTestWriter(t TestingLog) func(w *ConsoleWriter) {
type FilteredLevelWriter (line 197) | type FilteredLevelWriter struct
method Write (line 203) | func (w *FilteredLevelWriter) Write(p []byte) (int, error) {
method WriteLevel (line 209) | func (w *FilteredLevelWriter) WriteLevel(level Level, p []byte) (int, ...
method Close (line 218) | func (w *FilteredLevelWriter) Close() error {
type TriggerLevelWriter (line 237) | type TriggerLevelWriter struct
method WriteLevel (line 255) | func (w *TriggerLevelWriter) WriteLevel(l Level, p []byte) (n int, err...
method trigger (line 291) | func (w *TriggerLevelWriter) trigger() error {
method Trigger (line 329) | func (w *TriggerLevelWriter) Trigger() error {
method Close (line 337) | func (w *TriggerLevelWriter) Close() error {
FILE: writer_test.go
type closableBuffer (line 15) | type closableBuffer struct
method Close (line 21) | func (cb *closableBuffer) Close() error {
type errorWriter (line 26) | type errorWriter struct
method Write (line 31) | func (ew *errorWriter) Write(p []byte) (int, error) {
method WriteLevel (line 41) | func (ew *errorWriter) WriteLevel(level Level, p []byte) (int, error) {
function TestMultiSyslogWriter (line 45) | func TestMultiSyslogWriter(t *testing.T) {
type mockedWriter (line 67) | type mockedWriter struct
method Write (line 71) | func (c mockedWriter) Write(p []byte) (int, error) {
function TestResilientMultiWriter (line 82) | func TestResilientMultiWriter(t *testing.T) {
type testingLog (line 147) | type testingLog struct
method Log (line 152) | func (t *testingLog) Log(args ...interface{}) {
method Logf (line 158) | func (t *testingLog) Logf(format string, args ...interface{}) {
function TestTestWriter (line 164) | func TestTestWriter(t *testing.T) {
function TestFilteredLevelWriter (line 209) | func TestFilteredLevelWriter(t *testing.T) {
type testWrite (line 229) | type testWrite struct
function TestTriggerLevelWriter (line 234) | func TestTriggerLevelWriter(t *testing.T) {
function TestLevelWriterAdapter_Close (line 284) | func TestLevelWriterAdapter_Close(t *testing.T) {
function TestSyncWriter (line 308) | func TestSyncWriter(t *testing.T) {
function TestMultiLevelWriter_Write (line 373) | func TestMultiLevelWriter_Write(t *testing.T) {
function TestMultiLevelWriter_WriteLevel (line 419) | func TestMultiLevelWriter_WriteLevel(t *testing.T) {
function TestMultiLevelWriter_Close (line 454) | func TestMultiLevelWriter_Close(t *testing.T) {
function TestNewTestWriter (line 488) | func TestNewTestWriter(t *testing.T) {
function TestFilteredLevelWriter_Write (line 499) | func TestFilteredLevelWriter_Write(t *testing.T) {
function TestFilteredLevelWriter_Close (line 520) | func TestFilteredLevelWriter_Close(t *testing.T) {
Condensed preview — 97 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (682K chars).
[
{
"path": ".github/dependabot.yml",
"chars": 195,
"preview": "version: 2\nupdates:\n - package-ecosystem: github-actions\n directory: /\n schedule:\n interval: weekly\n - pack"
},
{
"path": ".github/workflows/test.yml",
"chars": 923,
"preview": "on: [push, pull_request]\nname: Test\njobs:\n test:\n strategy:\n matrix:\n go-version: [1.21.x, 1.24.x]\n "
},
{
"path": ".gitignore",
"chars": 286,
"preview": "# Compiled Object files, Static and Dynamic libs (Shared Objects)\n*.o\n*.a\n*.so\n\n# Folders\n_obj\n_test\ntmp\n\n# Architecture"
},
{
"path": "CONTRIBUTING.md",
"chars": 2053,
"preview": "# Contributing to Zerolog\n\nThank you for your interest in contributing to **Zerolog**!\n\nZerolog is a **feature-complete*"
},
{
"path": "LICENSE",
"chars": 1072,
"preview": "MIT License\n\nCopyright (c) 2017 Olivier Poitrey\n\nPermission is hereby granted, free of charge, to any person obtaining a"
},
{
"path": "README.md",
"chars": 29628,
"preview": "# Zero Allocation JSON Logger\n\n[](https://godoc"
},
{
"path": "array.go",
"chars": 7283,
"preview": "package zerolog\n\nimport (\n\t\"context\"\n\t\"net\"\n\t\"sync\"\n\t\"time\"\n)\n\nvar arrayPool = &sync.Pool{\n\tNew: func() interface{} {\n\t\t"
},
{
"path": "array_test.go",
"chars": 1626,
"preview": "package zerolog\n\nimport (\n\t\"fmt\"\n\t\"net\"\n\t\"testing\"\n\t\"time\"\n)\n\nfunc TestArray(t *testing.T) {\n\ta := Arr().\n\t\tBool(true).\n"
},
{
"path": "benchmark_test.go",
"chars": 8735,
"preview": "package zerolog\n\nimport (\n\t\"errors\"\n\t\"io\"\n\t\"testing\"\n\t\"time\"\n)\n\nvar (\n\terrExample = errors.New(\"fail\")\n\tfakeMessage = \""
},
{
"path": "binary_test.go",
"chars": 14487,
"preview": "//go:build binary_log\n// +build binary_log\n\npackage zerolog\n\nimport (\n\t\"bytes\"\n\t\"errors\"\n\t\"fmt\"\n\t\"net\"\n\n\tstdlog \"log\"\n\t\""
},
{
"path": "cmd/lint/README.md",
"chars": 2304,
"preview": "# Zerolog Lint\n\n**DEPRECATED: In favor of https://github.com/ykadowak/zerologlint which is integrated with `go vet` and "
},
{
"path": "cmd/lint/go.mod",
"chars": 82,
"preview": "module github.com/rs/zerolog/cmd/lint\n\ngo 1.15\n\nrequire golang.org/x/tools v0.1.8\n"
},
{
"path": "cmd/lint/go.sum",
"chars": 2788,
"preview": "github.com/yuin/goldmark v1.4.1/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=\ngolang.org/x/crypto v0.0.0-201903"
},
{
"path": "cmd/lint/lint.go",
"chars": 4274,
"preview": "package main\n\nimport (\n\t\"flag\"\n\t\"fmt\"\n\t\"go/ast\"\n\t\"go/token\"\n\t\"go/types\"\n\t\"os\"\n\t\"path/filepath\"\n\t\"strings\"\n\n\t\"golang.org/"
},
{
"path": "cmd/prettylog/README.md",
"chars": 906,
"preview": "# Zerolog PrettyLog\n\nThis is a basic CLI utility that will colorize and pretty print your structured JSON logs.\n\n## Usag"
},
{
"path": "cmd/prettylog/prettylog.go",
"chars": 1555,
"preview": "package main\n\nimport (\n\t\"bufio\"\n\t\"errors\"\n\t\"flag\"\n\t\"fmt\"\n\t\"io\"\n\t\"os\"\n\t\"time\"\n\n\t\"github.com/rs/zerolog\"\n)\n\nfunc isInputFr"
},
{
"path": "console.go",
"chars": 12111,
"preview": "package zerolog\n\nimport (\n\t\"bytes\"\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"io\"\n\t\"os\"\n\t\"path/filepath\"\n\t\"sort\"\n\t\"strconv\"\n\t\"strings\"\n\t\""
},
{
"path": "console_test.go",
"chars": 20320,
"preview": "package zerolog_test\n\nimport (\n\t\"bytes\"\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"io\"\n\t\"os\"\n\t\"path/filepath\"\n\t\"strings\"\n\t\"testing\"\n\t\"tim"
},
{
"path": "context.go",
"chars": 17065,
"preview": "package zerolog\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"math\"\n\t\"net\"\n\t\"time\"\n)\n\n// Context configures a new sub-logger with contex"
},
{
"path": "context_test.go",
"chars": 4188,
"preview": "package zerolog\n\nimport (\n\t\"bytes\"\n\t\"errors\"\n\t\"testing\"\n)\n\ntype myError struct{}\n\nfunc (e *myError) Error() string { ret"
},
{
"path": "ctx.go",
"chars": 1481,
"preview": "package zerolog\n\nimport (\n\t\"context\"\n)\n\nvar disabledLogger *Logger\n\nfunc init() {\n\tSetGlobalLevel(TraceLevel)\n\tl := Nop("
},
{
"path": "ctx_test.go",
"chars": 2373,
"preview": "package zerolog\n\nimport (\n\t\"bytes\"\n\t\"context\"\n\t\"io\"\n\t\"reflect\"\n\t\"strings\"\n\t\"testing\"\n\n\t\"github.com/rs/zerolog/internal/c"
},
{
"path": "diode/diode.go",
"chars": 2677,
"preview": "// Package diode provides a thread-safe, lock-free, non-blocking io.Writer\n// wrapper.\npackage diode\n\nimport (\n\t\"context"
},
{
"path": "diode/diode_example_test.go",
"chars": 366,
"preview": "// +build !binary_log\n\npackage diode_test\n\nimport (\n\t\"fmt\"\n\t\"os\"\n\n\t\"github.com/rs/zerolog\"\n\t\"github.com/rs/zerolog/diode"
},
{
"path": "diode/diode_test.go",
"chars": 3797,
"preview": "package diode_test\n\nimport (\n\t\"bytes\"\n\t\"fmt\"\n\t\"io\"\n\t\"log\"\n\t\"os\"\n\t\"os/exec\"\n\t\"sync\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/rs/z"
},
{
"path": "diode/internal/diodes/README",
"chars": 82,
"preview": "Copied from https://github.com/cloudfoundry/go-diodes to avoid test dependencies.\n"
},
{
"path": "diode/internal/diodes/many_to_one.go",
"chars": 4217,
"preview": "package diodes\n\nimport (\n\t\"log\"\n\t\"sync/atomic\"\n\t\"unsafe\"\n)\n\n// ManyToOne diode is optimal for many writers (go-routines "
},
{
"path": "diode/internal/diodes/one_to_one.go",
"chars": 4087,
"preview": "package diodes\n\nimport (\n\t\"sync/atomic\"\n\t\"unsafe\"\n)\n\n// GenericDataType is the data type the diodes operate on.\ntype Gen"
},
{
"path": "diode/internal/diodes/poller.go",
"chars": 1631,
"preview": "package diodes\n\nimport (\n\t\"context\"\n\t\"time\"\n)\n\n// Diode is any implementation of a diode.\ntype Diode interface {\n\tSet(Ge"
},
{
"path": "diode/internal/diodes/waiter.go",
"chars": 1796,
"preview": "package diodes\n\nimport (\n\t\"context\"\n\t\"sync\"\n)\n\n// Waiter will use a conditional mutex to alert the reader to when data i"
},
{
"path": "encoder.go",
"chars": 2367,
"preview": "package zerolog\n\nimport (\n\t\"net\"\n\t\"time\"\n)\n\ntype encoder interface {\n\tAppendArrayDelim(dst []byte) []byte\n\tAppendArrayEn"
},
{
"path": "encoder_cbor.go",
"chars": 1030,
"preview": "// +build binary_log\n\npackage zerolog\n\n// This file contains bindings to do binary encoding.\n\nimport (\n\t\"github.com/rs/z"
},
{
"path": "encoder_json.go",
"chars": 996,
"preview": "// +build !binary_log\n\npackage zerolog\n\n// encoder_json.go file contains bindings to generate\n// JSON encoded byte strea"
},
{
"path": "error_marshal_test.go",
"chars": 5784,
"preview": "package zerolog\n\nimport (\n\t\"bytes\"\n\t\"fmt\"\n\t\"strings\"\n\t\"testing\"\n)\n\ntype loggableError struct {\n\terror\n}\n\nfunc (l loggabl"
},
{
"path": "event.go",
"chars": 23512,
"preview": "package zerolog\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"net\"\n\t\"os\"\n\t\"runtime\"\n\t\"sync\"\n\t\"time\"\n)\n\nvar eventPool = &sync.Pool{\n\tNew:"
},
{
"path": "event_test.go",
"chars": 18052,
"preview": "//go:build !binary_log\n// +build !binary_log\n\npackage zerolog\n\nimport (\n\t\"bytes\"\n\t\"context\"\n\t\"errors\"\n\t\"io\"\n\t\"os\"\n\t\"stri"
},
{
"path": "example.jsonl",
"chars": 787,
"preview": "{\"time\":\"5:41PM\",\"level\":\"info\",\"message\":\"Starting listener\",\"listen\":\":8080\",\"pid\":37556}\n{\"time\":\"5:41PM\",\"level\":\"de"
},
{
"path": "fields.go",
"chars": 7940,
"preview": "package zerolog\n\nimport (\n\t\"context\"\n\t\"encoding/json\"\n\t\"io\"\n\t\"net\"\n\t\"reflect\"\n\t\"sort\"\n\t\"time\"\n)\n\nfunc isNilValue(e error"
},
{
"path": "fixtures_test.go",
"chars": 4301,
"preview": "package zerolog\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"fmt\"\n\t\"net\"\n\t\"reflect\"\n\t\"time\"\n)\n\ntype fixtureObj struct {\n\tPub string"
},
{
"path": "globals.go",
"chars": 6588,
"preview": "package zerolog\n\nimport (\n\t\"bytes\"\n\t\"encoding/json\"\n\t\"strconv\"\n\t\"sync/atomic\"\n\t\"time\"\n)\n\nconst (\n\t// TimeFormatUnix defi"
},
{
"path": "go.mod",
"chars": 287,
"preview": "module github.com/rs/zerolog\n\ngo 1.23\n\nrequire (\n\tgithub.com/coreos/go-systemd/v22 v22.6.0\n\tgithub.com/mattn/go-colorabl"
},
{
"path": "go.sum",
"chars": 1083,
"preview": "github.com/coreos/go-systemd/v22 v22.6.0 h1:aGVa/v8B7hpb0TKl0MWoAavPDmHvobFe5R5zn0bCJWo=\ngithub.com/coreos/go-systemd/v2"
},
{
"path": "go112.go",
"chars": 161,
"preview": "// +build go1.12\n\npackage zerolog\n\n// Since go 1.12, some auto generated init functions are hidden from\n// runtime.Calle"
},
{
"path": "hlog/hlog.go",
"chars": 10340,
"preview": "// Package hlog provides a set of http.Handler helpers for zerolog.\npackage hlog\n\nimport (\n\t\"context\"\n\t\"net\"\n\t\"net/http\""
},
{
"path": "hlog/hlog_example_test.go",
"chars": 1889,
"preview": "// +build !binary_log\n\npackage hlog_test\n\nimport (\n\t\"net/http\"\n\t\"os\"\n\t\"time\"\n\n\t\"net/http/httptest\"\n\n\t\"github.com/rs/zero"
},
{
"path": "hlog/hlog_test.go",
"chars": 12436,
"preview": "//go:build go1.7\n// +build go1.7\n\npackage hlog\n\nimport (\n\t\"bytes\"\n\t\"context\"\n\t\"fmt\"\n\t\"io\"\n\t\"net/http\"\n\t\"net/http/httptes"
},
{
"path": "hlog/internal/mutil/LICENSE",
"chars": 1098,
"preview": "Copyright (c) 2014, 2015, 2016 Carl Jackson (carl@avtok.com)\n\nMIT License\n\nPermission is hereby granted, free of charge,"
},
{
"path": "hlog/internal/mutil/mutil.go",
"chars": 229,
"preview": "// Package mutil contains various functions that are helpful when writing http\n// middleware.\n//\n// It has been vendored"
},
{
"path": "hlog/internal/mutil/writer_proxy.go",
"chars": 3784,
"preview": "package mutil\n\nimport (\n\t\"bufio\"\n\t\"io\"\n\t\"net\"\n\t\"net/http\"\n)\n\n// WriterProxy is a proxy around an http.ResponseWriter tha"
},
{
"path": "hook.go",
"chars": 1510,
"preview": "package zerolog\n\n// Hook defines an interface to a log hook.\ntype Hook interface {\n\t// Run runs the hook with the event."
},
{
"path": "hook_test.go",
"chars": 9533,
"preview": "package zerolog\n\nimport (\n\t\"bytes\"\n\t\"context\"\n\t\"io\"\n\t\"testing\"\n)\n\ntype contextKeyType int\n\nvar contextKey contextKeyType"
},
{
"path": "internal/cbor/README.md",
"chars": 3486,
"preview": "## Reference:\n CBOR Encoding is described in [RFC7049](https://tools.ietf.org/html/rfc7049)\n\n## Comparison of JSON vs "
},
{
"path": "internal/cbor/base.go",
"chars": 672,
"preview": "package cbor\n\n// JSONMarshalFunc is used to marshal interface to JSON encoded byte slice.\n// Making it package level ins"
},
{
"path": "internal/cbor/base_test.go",
"chars": 437,
"preview": "package cbor\n\nimport (\n\t\"bytes\"\n\t\"encoding/hex\"\n\t\"testing\"\n)\n\nfunc TestAppendKey(t *testing.T) {\n\twant := make([]byte, 0"
},
{
"path": "internal/cbor/cbor.go",
"chars": 2919,
"preview": "// Package cbor provides primitives for storing different data\n// in the CBOR (binary) format. CBOR is defined in RFC704"
},
{
"path": "internal/cbor/decode_stream.go",
"chars": 16382,
"preview": "package cbor\n\n// This file contains code to decode a stream of CBOR Data into JSON.\n\nimport (\n\t\"bufio\"\n\t\"bytes\"\n\t\"encodi"
},
{
"path": "internal/cbor/decoder_test.go",
"chars": 15476,
"preview": "package cbor\n\nimport (\n\t\"bytes\"\n\t\"encoding/hex\"\n\t\"math\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/rs/zerolog/internal\"\n)\n\nfunc Te"
},
{
"path": "internal/cbor/examples/genLog.go",
"chars": 1095,
"preview": "package main\n\nimport (\n\t\"compress/zlib\"\n\t\"flag\"\n\t\"io\"\n\t\"log\"\n\t\"os\"\n\t\"time\"\n\n\t\"github.com/rs/zerolog\"\n)\n\nfunc writeLog(fn"
},
{
"path": "internal/cbor/examples/makefile",
"chars": 197,
"preview": "all: genLogJSON genLogCBOR\n\ngenLogJSON: genLog.go\n\tgo build -o genLogJSON genLog.go \n\ngenLogCBOR: genLog.go\n\tgo build -t"
},
{
"path": "internal/cbor/string.go",
"chars": 2940,
"preview": "package cbor\n\nimport \"fmt\"\n\n// AppendStrings encodes and adds an array of strings to the dst byte array.\nfunc (e Encoder"
},
{
"path": "internal/cbor/string_test.go",
"chars": 9067,
"preview": "package cbor\n\nimport (\n\t\"bytes\"\n\t\"encoding/hex\"\n\t\"testing\"\n\n\t\"github.com/rs/zerolog/internal\"\n)\n\nvar encodeStringTests ="
},
{
"path": "internal/cbor/time.go",
"chars": 3114,
"preview": "package cbor\n\nimport (\n\t\"time\"\n)\n\nconst (\n\t// Import from zerolog/global.go\n\ttimeFormatUnix = \"\"\n\ttimeFormatUnixMs"
},
{
"path": "internal/cbor/time_test.go",
"chars": 9053,
"preview": "package cbor\n\nimport (\n\t\"bytes\"\n\t\"encoding/hex\"\n\t\"fmt\"\n\t\"math\"\n\t\"reflect\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/rs/zerolog/in"
},
{
"path": "internal/cbor/types.go",
"chars": 15099,
"preview": "package cbor\n\nimport (\n\t\"fmt\"\n\t\"math\"\n\t\"net\"\n\t\"reflect\"\n)\n\n// AppendNil inserts a 'Nil' object into the dst byte array.\n"
},
{
"path": "internal/cbor/types_64_test.go",
"chars": 750,
"preview": "// +build !386\n\npackage cbor\n\nimport (\n\t\"encoding/hex\"\n\t\"testing\"\n)\n\nvar enc2 = Encoder{}\n\nvar integerTestCases_64bit = "
},
{
"path": "internal/cbor/types_test.go",
"chars": 30941,
"preview": "package cbor\n\nimport (\n\t\"bytes\"\n\t\"encoding/hex\"\n\t\"errors\"\n\t\"math\"\n\t\"net\"\n\t\"testing\"\n\n\t\"github.com/rs/zerolog/internal\"\n)"
},
{
"path": "internal/json/base.go",
"chars": 671,
"preview": "package json\n\n// JSONMarshalFunc is used to marshal interface to JSON encoded byte slice.\n// Making it package level ins"
},
{
"path": "internal/json/base_test.go",
"chars": 613,
"preview": "package json\n\nimport (\n\t\"bytes\"\n\t\"testing\"\n)\n\nfunc TestAppendKey(t *testing.T) {\n\twant := make([]byte, 0)\n\twant = append"
},
{
"path": "internal/json/bytes.go",
"chars": 2010,
"preview": "package json\n\nimport \"unicode/utf8\"\n\n// AppendBytes is a mirror of appendString with []byte arg\nfunc (Encoder) AppendByt"
},
{
"path": "internal/json/bytes_test.go",
"chars": 2371,
"preview": "package json\n\nimport (\n\t\"testing\"\n\t\"unicode\"\n\n\t\"github.com/rs/zerolog/internal\"\n)\n\nvar enc = Encoder{}\n\nfunc TestAppendB"
},
{
"path": "internal/json/float_test.go",
"chars": 8553,
"preview": "package json\n\nimport (\n\t\"bytes\"\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"math\"\n\t\"math/rand\"\n\t\"testing\"\n\n\t\"github.com/rs/zerolog/interna"
},
{
"path": "internal/json/int_test.go",
"chars": 8120,
"preview": "package json\n\nimport (\n\t\"bytes\"\n\t\"fmt\"\n\t\"math\"\n\t\"testing\"\n\n\t\"github.com/rs/zerolog/internal\"\n)\n\nfunc TestAppendInts8(t *"
},
{
"path": "internal/json/string.go",
"chars": 4163,
"preview": "package json\n\nimport (\n\t\"fmt\"\n\t\"unicode/utf8\"\n)\n\nconst hexCharacters = \"0123456789abcdef\"\n\nvar noEscapeTable = [256]bool"
},
{
"path": "internal/json/string_test.go",
"chars": 2111,
"preview": "package json\n\nimport (\n\t\"testing\"\n\n\t\"github.com/rs/zerolog/internal\"\n)\n\nfunc TestAppendString(t *testing.T) {\n\tfor _, tt"
},
{
"path": "internal/json/time.go",
"chars": 3662,
"preview": "package json\n\nimport (\n\t\"strconv\"\n\t\"time\"\n)\n\nconst (\n\t// Import from zerolog/global.go\n\ttimeFormatUnix = \"\"\n\ttimeF"
},
{
"path": "internal/json/time_test.go",
"chars": 9203,
"preview": "package json\n\nimport (\n\t\"bytes\"\n\t\"fmt\"\n\t\"reflect\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/rs/zerolog/internal\"\n)\n\nfunc TestEnco"
},
{
"path": "internal/json/types.go",
"chars": 13964,
"preview": "package json\n\nimport (\n\t\"fmt\"\n\t\"math\"\n\t\"net\"\n\t\"reflect\"\n\t\"strconv\"\n)\n\n// AppendNil inserts a 'Nil' object into the dst b"
},
{
"path": "internal/json/types_test.go",
"chars": 14349,
"preview": "package json\n\nimport (\n\t\"bytes\"\n\t\"encoding/hex\"\n\t\"encoding/json\"\n\t\"errors\"\n\t\"math\"\n\t\"net\"\n\t\"reflect\"\n\t\"testing\"\n\n\t\"githu"
},
{
"path": "internal/testcases.go",
"chars": 10731,
"preview": "package internal\n\nimport (\n\t\"bytes\"\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"math\"\n\t\"net\"\n\t\"time\"\n)\n\nvar BooleanTestCases = []struct {\n"
},
{
"path": "journald/journald.go",
"chars": 2845,
"preview": "//go:build !windows\n// +build !windows\n\n// Package journald provides a io.Writer to send the logs\n// to journalD compone"
},
{
"path": "journald/journald_test.go",
"chars": 2115,
"preview": "// +build linux\n\npackage journald_test\n\nimport (\n\t\"bytes\"\n\t\"io\"\n\t\"testing\"\n\n\t\"github.com/rs/zerolog\"\n\t\"github.com/rs/zer"
},
{
"path": "log/log.go",
"chars": 3577,
"preview": "// Package log provides a global logger for zerolog.\npackage log\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"io\"\n\t\"os\"\n\n\t\"github.com/r"
},
{
"path": "log/log_example_test.go",
"chars": 7432,
"preview": "//go:build !binary_log\n// +build !binary_log\n\npackage log_test\n\nimport (\n\t\"bytes\"\n\t\"context\"\n\t\"errors\"\n\t\"flag\"\n\t\"os\"\n\t\"t"
},
{
"path": "log.go",
"chars": 15035,
"preview": "// Package zerolog provides a lightweight logging library dedicated to JSON logging.\n//\n// A global Logger can be use fo"
},
{
"path": "log_example_test.go",
"chars": 12653,
"preview": "// +build !binary_log\n\npackage zerolog_test\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\tstdlog \"log\"\n\t\"net\"\n\t\"os\"\n\t\"time\"\n\n\t\"github.com/"
},
{
"path": "log_test.go",
"chars": 46099,
"preview": "package zerolog\n\nimport (\n\t\"bytes\"\n\t\"context\"\n\t\"encoding/json\"\n\t\"errors\"\n\t\"fmt\"\n\t\"math\"\n\t\"net\"\n\t\"reflect\"\n\t\"runtime\"\n\t\"s"
},
{
"path": "not_go112.go",
"chars": 74,
"preview": "// +build !go1.12\n\npackage zerolog\n\nconst contextCallerSkipFrameCount = 3\n"
},
{
"path": "pkgerrors/stacktrace.go",
"chars": 1561,
"preview": "package pkgerrors\n\nimport (\n\t\"github.com/pkg/errors\"\n)\n\nvar (\n\tStackSourceFileName = \"source\"\n\tStackSourceLineName "
},
{
"path": "pkgerrors/stacktrace_test.go",
"chars": 2757,
"preview": "// +build !binary_log\n\npackage pkgerrors\n\nimport (\n\t\"bytes\"\n\t\"fmt\"\n\t\"regexp\"\n\t\"testing\"\n\n\t\"github.com/pkg/errors\"\n\t\"gith"
},
{
"path": "sampler.go",
"chars": 3176,
"preview": "package zerolog\n\nimport (\n\t\"math/rand\"\n\t\"sync/atomic\"\n\t\"time\"\n)\n\nvar (\n\t// Often samples log every ~ 10 events.\n\tOften ="
},
{
"path": "sampler_test.go",
"chars": 3752,
"preview": "//go:build !binary_log\n// +build !binary_log\n\npackage zerolog\n\nimport (\n\t\"testing\"\n\t\"time\"\n)\n\nvar samplers = []struct {\n"
},
{
"path": "slog.go",
"chars": 6485,
"preview": "package zerolog\n\nimport (\n\t\"context\"\n\t\"log/slog\"\n\t\"time\"\n)\n\n// SlogHandler implements the slog.Handler interface using a"
},
{
"path": "slog_test.go",
"chars": 14125,
"preview": "package zerolog_test\n\nimport (\n\t\"context\"\n\t\"bytes\"\n\t\"encoding/json\"\n\t\"errors\"\n\t\"log/slog\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.c"
},
{
"path": "syslog.go",
"chars": 2194,
"preview": "// +build !windows\n// +build !binary_log\n\npackage zerolog\n\nimport (\n\t\"io\"\n)\n\n// See http://cee.mitre.org/language/1.0-be"
},
{
"path": "syslog_test.go",
"chars": 6584,
"preview": "// +build !binary_log\n// +build !windows\n\npackage zerolog\n\nimport (\n\t\"bytes\"\n\t\"io\"\n\t\"reflect\"\n\t\"strings\"\n\t\"testing\"\n)\n\nt"
},
{
"path": "writer.go",
"chars": 9523,
"preview": "package zerolog\n\nimport (\n\t\"bytes\"\n\t\"io\"\n\t\"path\"\n\t\"runtime\"\n\t\"strconv\"\n\t\"strings\"\n\t\"sync\"\n)\n\n// LevelWriter defines as i"
},
{
"path": "writer_test.go",
"chars": 13194,
"preview": "//go:build !binary_log && !windows\n// +build !binary_log,!windows\n\npackage zerolog\n\nimport (\n\t\"bytes\"\n\t\"errors\"\n\t\"fmt\"\n\t"
}
]
About this extraction
This page contains the full source code of the rs/zerolog GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 97 files (599.0 KB), approximately 189.9k tokens, and a symbol index with 1211 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.
Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.