logctx

package module
v0.3.2 Latest Latest
Warning

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

Go to latest
Published: Jul 12, 2023 License: MIT Imports: 4 Imported by: 0

README

Logctx

Intro

Logctx is an utility enhancing work with the zap logger. It provides utilities to add logging context to context.Context and use it when writing logs.

ctx = logctx.WithFields(ctx,
	zap.String("username", "random"),
)
// ...
logctx.From(ctx).Debug("starting operation")

In addition to that, the option to add the logging context to an error is provided.

func DoOperation(ctx context.Context) error {
    err := failingOp()
    if err != nil {
        // add both the logging context from `ctx` and the additional fields
        return logctx.EnhanceError(ctx, err,
			zap.String("details", "present"), 
        )
    }
}
err := DoOperation(ctx)
if err != nil {
    logctx.ForError(ctx, err).Error("operation failed")
}

Install:

go get github.com/vbogdanov/logctx@latest

Initialization:

logctx.DefaultLogger, _ = zap.NewProduction()

Sugar vs No-Sugar

logctx supports sugared zap logger, see the API

HTTP Middleware

Feel free to copy or take inspiration from:

func AddLoggingContext(next http.Handler) http.Handler {
	return http.HandlerFunc(func(writer http.ResponseWriter, request *http.Request) {
		ctx := logctx.WithFields(request.Context(),
			zap.Namespace("request"),
			zap.String("Path", request.URL.Path),
		)
		request = request.WithContext(ctx)

		logctx.From(ctx).Debug("processing started")
		next.ServeHTTP(writer, request)
		logctx.From(ctx).Debug("processing complete")
	})
}

golangci-lint config

If using wrapcheck linter with logctx package:

linters-settings:
  wrapcheck:
    ignorePackageGlobs:
      # ignore this package, as it wraps errors to add logging context
      - github.com/vbogdanov/logctx

Documentation

Overview

Package logctx, short for Logging Context, provides utils to keep additional logging context in context.Context and use it.

Index

Examples

Constants

This section is empty.

Variables

View Source
var (

	// DefaultLogger is the logger to use if the provided ctx does not contain one.
	DefaultLogger = zap.NewNop()
	// AddCtxFields defines whether the context to be added as a Field in the log to be returned.
	AddCtxFields = false
)

Functions

func CtxField added in v0.2.0

func CtxField(ctx context.Context) zapcore.Field

CtxField wraps context.Context as a Field. To be used by CtxAwareZapCore.

func Debug added in v0.2.0

func Debug(ctx context.Context, msg string, fields ...zap.Field)

Debug simplifies logging simple debug messages. NB: if ctx == nil, DefaultLogger is used instead of From(ctx).

func EnhanceError

func EnhanceError(ctx context.Context, err error, fields ...zap.Field) error

EnhanceError wraps the provided error in logging context enhanced error. Optionally, fields are added to the logging context.

func ForError

func ForError(ctx context.Context, err error) *zap.Logger

ForError provides a new *zap.Logger with the error already added as Field. See From method.

Example
package main

import (
	"context"
	"errors"
	"fmt"
	"time"

	"github.com/vbogdanov/logctx"
	"go.uber.org/zap"
)

func main() {
	logctx.DefaultLogger = zap.NewExample()
	ctx := context.TODO()

	err := DoOperation(ctx)
	if err != nil {
		logctx.ForError(ctx, err).Error("operation failed")
	}

}

func DoOperation(ctx context.Context) error {
	ctx = logctx.WithFields(ctx,
		zap.String("username", "random"),
	)
	logctx.From(ctx).Debug("starting operation")
	// ...
	err := DoInDepth(ctx)
	if err != nil {
		return fmt.Errorf("wrapped with errorf: %w", err)
	}
	return nil
}

func DoInDepth(ctx context.Context) error {
	ctx = logctx.WithFields(ctx,
		zap.Int("depth", 2),
	)
	logctx.From(ctx).Debug("starting in depth")
	// ...
	err := failingOp()
	if err != nil {
		// add the most possible context available in the error
		return logctx.EnhanceError(ctx, err, zap.Duration("of test", 1*time.Second))
	}
	return nil
}

func failingOp() error {
	return errors.New("something")
}
Output:

{"level":"debug","msg":"starting operation","username":"random"}
{"level":"debug","msg":"starting in depth","username":"random","depth":2}
{"level":"error","msg":"operation failed","username":"random","depth":2,"of test":"1s"}

func From

func From(ctx context.Context) *zap.Logger

From provides a *zap.Logger from the given context. New logger is created if one is not associated with the context.

func NewError

func NewError(ctx context.Context, msg string, fields ...zap.Field) error

NewError creates a new `error` using the provided message and wraps in logging context enhanced error.

func Sugar

func Sugar(ctx context.Context) *zap.SugaredLogger

Sugar provides a *zap.SugaredLogger from the given context. New logger is created if one is not associated with the context.

func With

func With(ctx context.Context, args ...interface{}) context.Context

With enhances the logging context with the given args. Similar to the *zap.SugaredLogger With method.

func WithFields

func WithFields(ctx context.Context, fields ...zap.Field) context.Context

WithFields enhances the logging context with the provided fields. See go.uber.org/zap.Logger#With method

Types

type CtxAwareZapCore added in v0.2.0

type CtxAwareZapCore struct {
	zapcore.Core

	OnLogWrite OnLogWrite
	// contains filtered or unexported fields
}

CtxAwareZapCore is a wrapping zapcore.Core implementation that checks for wrapped context.Context

func (*CtxAwareZapCore) Check added in v0.2.0

Check checks if the entry should be logged. The method checks with the wrapped core, but add itself as the writer

func (*CtxAwareZapCore) Level added in v0.2.0

func (s *CtxAwareZapCore) Level() zapcore.Level

func (*CtxAwareZapCore) With added in v0.2.0

func (s *CtxAwareZapCore) With(fields []zapcore.Field) zapcore.Core

With is removes context.Context if present in the fields and stores it in the logger core

func (*CtxAwareZapCore) Write added in v0.2.0

func (s *CtxAwareZapCore) Write(ent zapcore.Entry, fields []zapcore.Field) error

Write writes a given log message. This method calls OnLogWrite callback before delegating to the wrapped core.

type OnLogWrite added in v0.2.0

type OnLogWrite func(ctx context.Context, ent zapcore.Entry, fields []zapcore.Field) []zapcore.Field

OnLogWrite wraps a function defining behavior when a log is written if context.Context is added as field. The intention is to integrate tracing and logging. For example * opencensus span context can be added as fields * record of a log message can be added in the trace It is OK to mutate and return the passed fields slice. This function is invoked after Level check and only if the log entry is about to be written out.

func (OnLogWrite) WrapCore added in v0.2.0

func (fn OnLogWrite) WrapCore(core zapcore.Core) zapcore.Core

WrapCore allows an easy integration with zap.WrapCore(). It creates a new CtxAwareZapCore around the passed core (usually zapcore.ioCore) and sets the current OnLogWrite in it.

Jump to

Keyboard shortcuts

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