golflog

package module
Version: v1.5.1 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jun 1, 2022 License: Apache-2.0 Imports: 11 Imported by: 0

README

golflog GoDoc Build Status

golflog is a logging utility package built around go-logr. It's main use is a higher level api for building context based logging iteratively and stored in context.Context.

Installation

go get -u github.com/floatme-corp/golflog

Use

As close to your application entry point or initial context creation, create a Configurator and logr.Logger, then set that logger in the context.Context:

import (
    "context"
    "fmt"

    "github.com/floatme-corp/golflog"
)

func main() {
    configurator := golflog.NewZapProductionConfigurator()
    verbosity := 0

    logger, err := golflog.NewLogger(configurator, "RootLoggerName", verbosity)
    if err != nil {
        panic(fmt.Sprintf("runtime error: failed to setup logging: %s", err))
    }

    ctx := golflog.NewContext(context.Background(), logger)

    ...
}

Later if your application has another section, such as a Queue handler, you can set that in the logger name:

func HandleQueue(ctx context.Context) {
    ctx = golflog.ContextWithName(ctx, "Queue")
}

All messages logged from that point forward will have the name added to the existing name: RootLoggerName.Queue.

Additional values can be setup as well for future logging:

func HandleUser(ctx context.Context, userID string) {
    ctx = golflog.ContextWithValues(ctx, "user_id", userID)
}

The name and values can be setup together in one shot:

func HandleUser(ctx context.Context, userID string) {
    ctx = golflog.ContextWithNameAndValues(ctx, "Queue", "user_id", userID)
}

Functions are guaranteed to be able to get a logger from any context:

func randoFunc(ctx context.Context) {
    log := golflog.AlwaysFromContext(ctx)
    log.Info("my log message")
}

If the context does not have a logger associated with it golflog will create a fallback logger with the default configuration. If that fails it will fallback to logging via fmt.Fprintln to os.Stdout

golflog provides helpers to create a log and a context with a name, values, or both:

func randoFunc(ctx context.Context) {
    // for tracing logs from this function
    ctx, log := golflog.WithName(ctx, "randoFunc")
    log.Info("my log message") // logs `randoFunc "msg"="my log message"`
}

// assume you have the important value `foo`
func randoFunc(ctx context.Context, importantValue string) {
    // for always seeing important value in future logs with this context
    ctx, log := golflog.WithValues(ctx, "important-value", importantValue)
    log.Info("my log message")
    // logs `"msg"="my log message" "important-value"="foo"`
}

func randoFunc(ctx context.Context, importantValue string) {
    ctx, log := golflog.WithNameAndValues(
        ctx,
        "randoFunc",
        "important-value", importantValue,
    )
    log.Info("my log message")
    // logs `randoFunc "msg"="my log message" "important-value"="foo"`
}
Logging Convenience Helpers

Info and Error convenience helpers are provided to log or report an error to the logger in the context. A severity key is added to each to invocation automatically to assist log aggregation services.

func randoFunc(ctx context.Context) {
    // Same as:
    // log := golflog.AlwaysFromContext(ctx)
    // log.Info("message", "severity", "info", "key", "value")
    golflog.Info(ctx, "message", "key", "value")

    ...

    // Same as:
    // log := golflog.AlwaysFromContext(ctx)
    // log.Error(err, "message", "severity", "error", "key", "value")
    golflog.Error(ctx, err, "message", "key", "value")
}

A Wrap helper will log the message at the info level and return a new error wrapping the err with message. A WarnWrap helper is also provided to log the message with severity=warning prepended to the list of key/value pairs before returning the wrapped error.

func randoFunc(ctx context.Context) {
    ...

    if err != nil {
        // Same as:
        // golflog.Error(ctx, err, "message", "key", "value")
        // return fmt.Errorf("%s: %w", "message", "err")
        return golflog.Wrap(ctx, err, "message", "key", "value")
    }
    ...

    thingID := "1234"
    if err := findThing(thingID); err != nil {
        // Suppose you expect this error
        if err.As(ErrThingNotFound) {
            // Same as:
            // golflog.Warn(ctx, "message", "thing_id", thingID)
            // return fmt.Errorf("%s: %w", "message", "err")
            return golflog.WarnWrap(ctx, err, "Could not find thing!", "thing_id", thingID)
        }
    }
}

A V helper will return a logger from the context at the level requested.

func randoFunc(ctx context.Context) {
    ...

    // Will be logged at level 1
    golflog.V(ctx, 1).Info("message", "key", "value")
}

A Warn helper will automatically prepend severity=warning to the list of key/value pairs and logs out the message. This helper should be used sparingly, and instead logging levels should be used. It is included to make it easier for log aggregation services to key off.

func randoFunc(ctx context.Context) {
    ...

    // The same as
    // golflog.Info(ctx, "message", "severity", "warning", "key", "value")
    golflog.Warn(ctx, "message", "key", "value")
}

Warning is an alias of Warn.

func randoFunc(ctx context.Context) {
    ...

    // The same as
    // golflog.Info(ctx, "message", "severity", "warning", "key", "value")
    golflog.Warning(ctx, "message", "key", "value")
}

A Debug helper will automatically prepend severity=debug to the list of key/value pairs and logs out the message at a level 1 higher than the level of the logger in the context.Context. This helper should be used sparingly, and instead logging levels should be used. It is included to make it easier for log aggregation services to key off.

func randoFunc(ctx context.Context) {
    ...

    // The same as
    // golflog.V(ctx, 1).Info("message", "severity", "warning", "key", "value")
    golflog.Debug(ctx, "message", "key", "value")
}
Env setup

An alternative to calling golflog.NewLogger with the parameters, is to call NewLoggerFromEnv and give it only the root name:

import (
    "context"
    "fmt"

    "github.com/floatme-corp/golflog
)

func main() {
    logger, err := golflog.NewLoggerFromEnv("RootLoggerName")
    if err != nil {
        panic(fmt.Sprintf("runtime error: failed to setup logging: %s", err))
    }

    ctx := golflog.NewContext(context.Background(), logger)

    ...
}

NewLoggerFromEnv uses the environment variables LOG_PRODUCTION, LOG_IMPLEMENTATION, and LOG_VERBOSITY to configure the logger. If they do not exist, it will default to configuring a production logger, with a zap Configurator at 0 verbosity (normal / info level).


Released under the Apache 2.0 License.

Documentation

Index

Constants

View Source
const (
	LogProduction     = "LOG_PRODUCTION"
	LogImplementation = "LOG_IMPLEMENTATION"
	LogVerbosity      = "LOG_VERBOSITY"
)
View Source
const (
	// MaxLevel is the maximum logging level supported. All verbosity values higher will be
	// clamped to this value.
	MaxLevel = 127

	// MinLevel is the minimum logging level supported. All verbosity values lower will be
	// clamped to this value.
	MinLevel = 0
)

Variables

View Source
var DefaultFallbackOutput io.Writer = os.Stdout

DefaultFallbackOutput is the default io stream jfor fallback logging. nolint: gochecknoglobals // Allow for testing

View Source
var ErrUnknownImplementation = errors.New("unknown implementation")

Functions

func AlwaysFromContext

func AlwaysFromContext(ctx context.Context) logr.Logger

AlwaysFromContext retrieves the logger from the context, if it is not found a new production logger at `MaxLevel` will be returned. If that fails a `fmt.Println` based logger is returned. nolint:contextcheck // ALWAYS!

func ContextWithName

func ContextWithName(ctx context.Context, name string) context.Context

ContextWithName returns a context with the name set in its logger.

func ContextWithNameAndValues added in v1.3.0

func ContextWithNameAndValues(
	ctx context.Context,
	name string,
	keysAndValues ...interface{},
) context.Context

ContextWithNameAndValues returns a context with the name and values set in its logger.

func ContextWithValues

func ContextWithValues(ctx context.Context, keysAndValues ...interface{}) context.Context

ContextWithValues returns a context with the values set in its logger.

func Debug added in v1.3.0

func Debug(ctx context.Context, message string, keysAndValues ...interface{})

Debug get a logger from the given context at one level higher than the current level and log the message. Prepends `severity=debug` to the passed key/value.

func Discard added in v1.4.0

func Discard() logr.Logger

Discard returns a Logger that discards all messages logged to it. It can be used whenever the caller is not interested in the logs. Logger instances produced by this function always compare as equal. This is just a proxy to `logr.Discard`.

func Error added in v1.2.0

func Error(
	ctx context.Context,
	err error,
	message string,
	keysAndValues ...interface{},
)

Error gets a logger from the given context and logs the error and message and optional values with `severity=error` prepended into the passed key/value.

func Info added in v1.1.0

func Info(
	ctx context.Context,
	message string,
	keysAndValues ...interface{},
)

Info gets a logger from the given context and logs message and optional values with `severity=info` prepended into the passed key/value.

func NewContext

func NewContext(ctx context.Context, log logr.Logger) context.Context

NewContext returns a context with the specified logger set in it.

func NewLogger

func NewLogger(
	configurator Configurator,
	rootName string,
	verbosity int,
) (logr.Logger, error)

NewLogger sets the log verbosity, configures a new logger from `configurator`, and sets the initial name of the logger.

func NewLoggerFromEnv

func NewLoggerFromEnv(rootname string) (logr.Logger, error)

NewLoggerFromEnv uses the environment variables `LOG_PRODUCTION`, `LOG_IMPLEMENTATION`, and `LOG_VERBOSITY` to configure the logger. If they do not exist, it will default to configuring a production logger, with a `zap` `Configurator` at `0` verbosity (normal / info level).

func NewLoggerWithBuildInfo

func NewLoggerWithBuildInfo(
	configurator Configurator,
	buildInfo BuildInfo,
	rootName string,
	verbosity int,
) (logr.Logger, error)

NewLogger sets the log verbosity, configures a new logger from `configurator`, and sets the initial name of the logger. If `buildInfo` is not `nil`, non-empty values from the interface will be set as values on the resulting `logr.Logger`.

func V added in v1.3.0

func V(ctx context.Context, level int) logr.Logger

V gets a logger from the given context for the level specified.

func Warn added in v1.3.0

func Warn(ctx context.Context, message string, keysAndValues ...interface{})

Warn gets a logger from the given context and logs the message with `severity=warning` prepended into the passed key/value.

func WarnWrap added in v1.5.0

func WarnWrap(
	ctx context.Context,
	err error,
	message string,
	keysAndValues ...interface{},
) error

WarnWrap logs the error as a warning and returns it wrapped by message. Useful for handling expected errors that should not be logged at error level.

func Warning added in v1.3.0

func Warning(ctx context.Context, message string, keysAndValues ...interface{})

Warning is an alias of the `Warn` function.

func WithName added in v1.2.0

func WithName(ctx context.Context, name string) (context.Context, logr.Logger)

WithName returns a context and logger with the given `name` set in the context.

func WithNameAndValues added in v1.2.0

func WithNameAndValues(
	ctx context.Context,
	name string,
	keysAndValues ...interface{},
) (context.Context, logr.Logger)

WithNameAndValues returns a context and logger with the given `name` and `values` set in the context.

func WithValues added in v1.2.0

func WithValues(ctx context.Context, keysAndValues ...interface{}) (context.Context, logr.Logger)

WithValues returns a context and logger with the given `values` set in the context.

func Wrap added in v1.1.0

func Wrap(
	ctx context.Context,
	err error,
	message string,
	keysAndValues ...interface{},
) error

Wrap logs the error on the given logger and returns it wrapped by message.

Types

type BuildInfo

type BuildInfo interface {
	Version() string
	Commit() string
	Date() string
	Time() string
}

BuildInfo allows the application to add build info to the logger by default. Any non empty value returned will be set in the logger when calling `NewLoggerWithBuildInfo`.

type Configurator

type Configurator interface {
	// Build and return a `logr.Logger` instance.
	Build() (logr.Logger, error)

	// Verbosity sets the desired verbosity level. NOTE this will be called prior to `Build`.
	Verbosity(verbosity int) error
}

Configurator allows a pluggable logging implementation.

var DefaultConfigurator Configurator = NewZapProductionConfigurator()

DefaultConfigurator is the default configurator for fallback logging. nolint: gochecknoglobals // Allow for testing

type ZapConfigurator

type ZapConfigurator struct {
	Zap zap.Config
}

func NewZapDevelopmentConfigurator

func NewZapDevelopmentConfigurator() *ZapConfigurator

func NewZapProductionConfigurator

func NewZapProductionConfigurator() *ZapConfigurator

func (*ZapConfigurator) Build

func (config *ZapConfigurator) Build() (logr.Logger, error)

Build a new `zap` `logr.Logger`.

func (*ZapConfigurator) Verbosity

func (config *ZapConfigurator) Verbosity(verbosity int) error

Verbosity sets the desirect log verbosity in the `zap` config.

Directories

Path Synopsis

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL