Documentation
¶
Overview ¶
Package log provides zerolog-based structured logging for Go services, with OpenTelemetry trace_id/span_id correlation drawn from the active span context.
New and Ctx return a concrete zerolog.Logger for callers that already depend on zerolog. NewLogger and LoggerFromContext return the neutral Logger interface instead: no zerolog type appears in its method signatures, so a consumer can wrap or depend on it without importing zerolog directly. Both paths honor the same LOG_LEVEL/LOG_FORMAT environment controls and the same trace correlation; zerolog stays an internal implementation detail behind the neutral path.
NewLoggerWithOptions builds a neutral Logger tuned by options: WithOutput picks the io.Writer (a CLI uses os.Stderr), and WithDefaultLevel and WithDefaultFormat set the fallbacks used when LOG_LEVEL or LOG_FORMAT is unset or invalid. It returns a TraceLogger, which adds Trace; Nop returns a TraceLogger that writes nothing.
LOG_LEVEL sets the start level. SetLevel changes the level live for the whole process, reaching loggers that already exist, and WatchLevelFile (or WatchLevelFileFromEnv with LOG_LEVEL_FILE) follows a one-word level file such as a mounted Kubernetes ConfigMap key.
Index ¶
- Constants
- func Ctx(ctx context.Context) zerolog.Loggerdeprecated
- func New(service string) zerolog.Logger
- func SetLevel(l Level) error
- func Trace(l Logger, msg string, fields ...Field)
- func WatchLevelFile(ctx context.Context, path string)
- func WatchLevelFileFromEnv(ctx context.Context) bool
- type Field
- type Format
- type Level
- type Logger
- type Option
- type TraceLogger
Examples ¶
Constants ¶
const LevelFileEnv = "LOG_LEVEL_FILE"
LevelFileEnv names the environment variable WatchLevelFileFromEnv reads: the path of a file holding one level word.
Variables ¶
This section is empty.
Functions ¶
func Ctx
deprecated
Ctx returns a zerolog.Logger derived from the logger created by the most recent call to New, with the active span's trace_id and span_id attached when ctx carries a valid span. This lets every log line be correlated with its trace in the tracing backend. When no valid span is present, it returns the plain base logger. If New has not been called, it falls back to a logger with no service field.
Deprecated: with two or more loggers in one process this returns whichever was created last, which is rarely what the caller means. Use NewLogger and the Logger.Ctx method, which derives from the logger it is called on.
func New ¶
New returns a zerolog.Logger with a timestamp and the given service name attached to every line, filtered to the level from LOG_LEVEL (default info) and rendered per LOG_FORMAT (JSON by default, console/pretty for dev). Consumers no longer need to parse LOG_LEVEL or wire a writer themselves -- calling New is enough.
func SetLevel ¶ added in v1.4.0
SetLevel changes the minimum level of every logger in the process, live: no logger needs rebuilding. It accepts the LOG_LEVEL names (trace, debug, info, warn, error, fatal, panic, disabled), case-insensitively. An unknown name returns an error and leaves the level as it was.
LOG_LEVEL stays the start value; SetLevel replaces it until the process ends, and loggers built afterwards keep the level SetLevel chose.
func Trace ¶ added in v1.3.0
Trace logs msg at trace level through l when l is a TraceLogger, as every Logger from this package is. For a Logger without a Trace method the line is dropped, since trace is below every level such a Logger can write.
func WatchLevelFile ¶ added in v1.4.0
WatchLevelFile applies the level named in the file at path, then keeps applying it whenever the file changes, until ctx ends. The file holds one level word (trace, debug, info, warn or error; surrounding whitespace is ignored). It is read once before WatchLevelFile returns and then every two seconds in the background, following symlinks on each read, so a Kubernetes ConfigMap volume (which swaps a symlink when the ConfigMap changes) works as the source.
An unknown word keeps the current level and logs a warning. A missing, unreadable or empty file means the start level from LOG_LEVEL. The watcher's own lines (a level change, a bad word, a missing file) are written whatever the level is, since they describe the level itself; only disabled silences them. They go to the logger built most recently by this package.
func WatchLevelFileFromEnv ¶ added in v1.4.0
WatchLevelFileFromEnv calls WatchLevelFile with the path in LOG_LEVEL_FILE and reports whether the variable was set. With it unset, nothing is watched and LOG_LEVEL alone sets the level.
Types ¶
type Field ¶ added in v1.2.0
Field is a structured key/value pair attached to a Logger call. Build one with F, or construct it directly since both fields are exported.
type Format ¶ added in v1.3.0
type Format string
Format names an output format for WithDefaultFormat. The values match the LOG_FORMAT vocabulary. An empty or unrecognized Format means JSON.
const ( // FormatJSON writes structured JSON. It is the default. FormatJSON Format = "json" // FormatConsole writes human-readable, colorized text. FormatConsole Format = "console" // FormatBoth writes JSON to the output and a console rendering to stderr. FormatBoth Format = "both" )
The formats WithDefaultFormat accepts.
type Level ¶ added in v1.3.0
type Level string
Level names a minimum log level for WithDefaultLevel. The values match the LOG_LEVEL vocabulary, so a string from a flag or config file converts with Level(s). An empty or unrecognized Level means info.
const ( LevelTrace Level = "trace" LevelDebug Level = "debug" LevelInfo Level = "info" LevelWarn Level = "warn" LevelError Level = "error" LevelFatal Level = "fatal" LevelPanic Level = "panic" LevelDisabled Level = "disabled" )
The levels WithDefaultLevel accepts, from most to least verbose.
func CurrentLevel ¶ added in v1.4.0
func CurrentLevel() Level
CurrentLevel returns the live minimum level.
type Logger ¶ added in v1.2.0
type Logger interface {
// Debug logs msg at debug level with the given structured fields.
Debug(msg string, fields ...Field)
// Info logs msg at info level with the given structured fields.
Info(msg string, fields ...Field)
// Warn logs msg at warn level with the given structured fields.
Warn(msg string, fields ...Field)
// Error logs msg at error level, attaching err, with the given
// structured fields.
Error(err error, msg string, fields ...Field)
// Fatal logs msg at fatal level, attaching err, with the given
// structured fields, then terminates the process with a non-zero exit
// code.
Fatal(err error, msg string, fields ...Field)
// With returns a child Logger that carries fields on every subsequent
// line, in addition to whatever the receiver already carries.
With(fields ...Field) Logger
// Ctx returns a Logger correlated with the trace/span carried by ctx.
// It derives from the receiver, so the service name and any fields
// already attached via With are carried over. When ctx has no valid
// span it returns the receiver unchanged.
Ctx(ctx context.Context) Logger
}
Logger is the neutral logging surface: no zerolog type appears in any method signature here, so a consumer can depend on this interface alone and never import zerolog directly. zerolog remains an internal implementation detail behind it. New/Ctx (which do return a concrete zerolog.Logger) are unchanged and continue to work side by side with this interface.
Example ¶
ExampleLogger shows the neutral surface: a consumer only needs the Logger interface, F, NewLogger, and LoggerFromContext -- zerolog is never imported or referenced.
package main
import (
"context"
"errors"
log "github.com/Bugs5382/go-log"
)
func main() {
logger := log.NewLogger("billing")
logger.Info("service started", log.F("port", 8080))
child := logger.With(log.F("request_id", "r-123"))
child.Warn("slow downstream call", log.F("elapsed_ms", 420))
err := errors.New("payment gateway timeout")
child.Error(err, "request failed")
// Inside a request/span, correlate logs with the active trace without
// ever touching a zerolog type.
ctx := context.Background()
log.LoggerFromContext(ctx).Info("handling request")
}
Output:
func LoggerFromContext
deprecated
added in
v1.2.0
LoggerFromContext returns a neutral Logger correlated with the trace/span carried by ctx -- the neutral equivalent of Ctx.
Deprecated: like Ctx, this derives from the logger created by the most recent call to New rather than from a logger the caller holds. Build a Logger with NewLogger and use its Ctx method instead.
type Option ¶ added in v1.3.0
type Option func(*config)
Option configures a Logger built by NewLoggerWithOptions.
func WithDefaultFormat ¶ added in v1.3.0
WithDefaultFormat sets the format used when LOG_FORMAT is unset or unrecognized, in place of JSON. LOG_FORMAT still wins whenever it is valid. A CLI passes FormatConsole so people read plain text unless they ask for JSON with LOG_FORMAT=json.
func WithDefaultLevel ¶ added in v1.3.0
WithDefaultLevel sets the level used when LOG_LEVEL is unset or not a level name, in place of info. LOG_LEVEL still wins whenever it is valid, so a deployment can always override the code. A CLI maps its -v flag here.
func WithOutput ¶ added in v1.3.0
WithOutput sends log output to w instead of stdout, whatever the format. A CLI passes os.Stderr so its logs never mix with what it prints on stdout. With LOG_FORMAT=both the JSON half goes to w and the console half still goes to stderr. A nil w leaves the output on stdout.
type TraceLogger ¶ added in v1.3.0
type TraceLogger interface {
Logger
// Trace logs msg at trace level with the given structured fields.
Trace(msg string, fields ...Field)
}
TraceLogger is a Logger that can also log at trace level. It is a separate interface because adding a method to Logger would break every type outside this package that implements it.
Every Logger this package returns is a TraceLogger, including the children from With and Ctx. NewLoggerWithOptions and Nop return one directly; for a value typed as Logger, use the Trace function.
func NewLoggerWithOptions ¶ added in v1.3.0
func NewLoggerWithOptions(service string, opts ...Option) TraceLogger
NewLoggerWithOptions returns a neutral Logger for a service, like NewLogger, configured by opts. With no options it behaves exactly like NewLogger. The environment still has the last word: LOG_LEVEL and LOG_FORMAT override the defaults the options set whenever they hold a valid value.
The result is a TraceLogger, so Trace can be called on it directly. Like NewLogger, it also becomes the logger the package-level Ctx and LoggerFromContext derive from.
Example ¶
ExampleNewLoggerWithOptions shows a CLI setup: logs on stderr so they never mix with command output, console text unless LOG_FORMAT asks for JSON, and a -v flag that selects trace unless LOG_LEVEL says otherwise.
package main
import (
"os"
log "github.com/Bugs5382/go-log"
)
func main() {
verbose := true
level := log.LevelInfo
if verbose {
level = log.LevelTrace
}
logger := log.NewLoggerWithOptions("my-cli",
log.WithOutput(os.Stderr),
log.WithDefaultFormat(log.FormatConsole),
log.WithDefaultLevel(level),
)
logger.Trace("resolved config", log.F("path", "config.yaml"))
logger.Info("done", log.F("files", 12))
}
Output:
func Nop ¶ added in v1.3.0
func Nop() TraceLogger
Nop returns a TraceLogger that writes nothing, for tests and quiet modes. It ignores LOG_LEVEL and LOG_FORMAT. Fatal still ends the process with a non-zero exit code, since callers rely on it not returning.
Example ¶
ExampleNop shows the no-op Logger for tests and quiet modes.
package main
import (
log "github.com/Bugs5382/go-log"
)
func main() {
var logger log.Logger = log.Nop()
logger.Info("never written")
log.Trace(logger, "never written either")
}
Output: