ctxslog

package module
v1.0.0 Latest Latest
Warning

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

Go to latest
Published: Aug 5, 2023 License: BSD-3-Clause Imports: 12 Imported by: 7

README

PkgGoDev Go Report Card

ctxslog

Go library provides helpers around slog

Example

(See package example on pkg.go.dev for up-to-date example)

package main

import (
	"context"
	"log/slog"
	"net/http"
	"os"

	"go.yhsif.com/ctxslog"
)

func EndpointHandler(ctx context.Context, traceID string) {
	// Inside an endpoint handler, attach trace id for all logs in this context
	ctx = ctxslog.Attach(ctx, "trace", traceID)
	// Now slog's global log functions with ctx will also have trace info
	slog.ErrorContex(ctx, "Not implemented")

	thirdPartyLibCall := func(ctx context.Context) {
		// Some third party library that uses slog and spams logs a lot.
		slog.ErrorContext(ctx, "not really an error")
	}
	thirdPartyLibCall(
		ctxslog.AttachLogLevel(ctx, ctxslog.MaxLevel), // now even if it logs at error level it won't shown
	)
}

func HttpHandler(w http.ResponseWriter, r *http.Request) {
	ctx := ctxslog.Attach(
		r.Context(),
		// Add httpRequest group to every log within this context
		slog.Group("httpRequest", ctxslog.HTTPRequest(r, ctxslog.RemoteAddrIP)),
	)
	// Enable callstack even at debug level for this context
	ctx = ctxslog.AttachCallstackLevel(ctx, slog.LevelDebug)
	slog.DebugContext(ctx, "foo") // this log will contain httpRequest group and callstack.
}

func main() {
	// Sets the global slog logger
	ctxslog.New(
		ctxslog.WithWriter(os.Stderr),                              // This is the default and can be omitted
		ctxslog.WithJSON,                                           // This is the default, use ctxslog.WithText instead if you want non-json logs
		ctxslog.WithAddSource(true),                                // Add source info
		ctxslog.WithLevel(slog.LevelDebug),                         // Keep debug level logs
		ctxslog.WithCallstack(slog.LevelError),                     // For error and above levels, also add callstack info
		ctxslog.WithGlobalKVs("version", os.Getenv("VERSION_TAG")), // Add version info to every log
		ctxslog.WithReplaceAttr(ctxslog.ChainReplaceAttr(
			ctxslog.GCPKeys,        // Use Google Cloud Structured logging friendly log keys
			ctxslog.StringDuration, // Log time durations as strings
		)),
	)
	// Now you can just use slog's global log functions
	slog.Info("Hello, world!", "key", "value")
}

Documentation

Overview

Package ctxslog provides helpers around slog.

Example
package main

import (
	"context"
	"log/slog"
	"net/http"
	"os"

	"go.yhsif.com/ctxslog"
)

func EndpointHandler(ctx context.Context, traceID string) {
	// Inside an endpoint handler, attach trace id for all logs in this context
	ctx = ctxslog.Attach(ctx, "trace", traceID)
	// Now slog's global log functions with ctx will also have trace info
	slog.ErrorContext(ctx, "Not implemented")

	thirdPartyLibCall := func(ctx context.Context) {
		// Some third party library that uses slog and spams logs a lot.
		slog.ErrorContext(ctx, "not really an error")
	}
	thirdPartyLibCall(
		ctxslog.AttachLogLevel(ctx, ctxslog.MaxLevel), // now even if it logs at error level it won't shown
	)
}

func HttpHandler(w http.ResponseWriter, r *http.Request) {
	ctx := ctxslog.Attach(
		r.Context(),
		// Add httpRequest group to every log within this context
		"httpRequest", ctxslog.HTTPRequest(r, ctxslog.RemoteAddrIP),
	)
	// Enable callstack even at debug level for this context
	ctx = ctxslog.AttachCallstackLevel(ctx, slog.LevelDebug)
	slog.DebugContext(ctx, "foo") // this log will contain httpRequest group and callstack.
}

func main() {
	// Sets the global slog logger
	ctxslog.New(
		ctxslog.WithWriter(os.Stderr),                              // This is the default and can be omitted
		ctxslog.WithJSON,                                           // This is the default, use ctxslog.WithText instead if you want non-json logs
		ctxslog.WithAddSource(true),                                // Add source info
		ctxslog.WithLevel(slog.LevelDebug),                         // Keep debug level logs
		ctxslog.WithCallstack(slog.LevelError),                     // For error and above levels, also add callstack info
		ctxslog.WithGlobalKVs("version", os.Getenv("VERSION_TAG")), // Add version info to every log
		ctxslog.WithReplaceAttr(ctxslog.ChainReplaceAttr(
			ctxslog.GCPKeys,        // Use Google Cloud Structured logging friendly log keys
			ctxslog.StringDuration, // Log time durations as strings
		)),
	)
	// Now you can just use slog's global log functions
	slog.Info("Hello, world!", "key", "value")
}
Output:

Index

Examples

Constants

View Source
const (
	MinLevel = slog.Level(math.MinInt)
	MaxLevel = slog.Level(math.MaxInt)
)

Minimal and maximal possible log levels.

You can use MinLevel as the log level or callstack level in context/logger to include all logs, or use MaxLevel to exclude all logs (except logs logged explicitly at MaxLevel).

Variables

This section is empty.

Functions

func Attach

func Attach(ctx context.Context, args ...any) context.Context

Attaches logger args into context.

func AttachCallstackLevel

func AttachCallstackLevel(ctx context.Context, level slog.Leveler) context.Context

AttachCallstackLevel attaches min callstack level to the context, overriding the global one set on the logger.

func AttachLogLevel

func AttachLogLevel(ctx context.Context, level slog.Leveler) context.Context

AttachLogLevel attaches min log level to the context, overriding the global one set on the logger.

func CallstackHandler

func CallstackHandler(h slog.Handler, min slog.Leveler) slog.Handler

CallstackHandler wraps handler to print out full callstack at minimal level.

func ContextHandler

func ContextHandler(h slog.Handler) slog.Handler

ContextHandler wraps handler to handle contexts from Attach.

func GCPKeys

func GCPKeys(groups []string, a slog.Attr) slog.Attr

GCPKeys is a ReplaceAttrFunc that replaces certain keys from Attr to meet Google Cloud Structured logging's expectations.

func GCPRealIP

func GCPRealIP(r *http.Request) netip.Addr

GCPRealIP gets the real IP form an GCP request (cloud run or app engine).

It picks the last non-local IP from X-Forwarded-For header, fallback to RemoteAddrIP if none found.

func HTTPRequest

func HTTPRequest(r *http.Request, ip func(*http.Request) netip.Addr) slog.Value

HTTPRequest returns a group value for some common HTTP request data.

The ip lambda is used to determine the real ip of the request. If it's nil, RemoteAddrIP will be used.

func New

func New(opts ...Option) *slog.Logger

New creates a *slog.Logger that can handle contexts.

It also calls slog.SetDefault before returning.

Note that importing this package also has side-effect of calling New with all default options (setting global, default logger for slog to be context aware logger).

func RemoteAddrIP

func RemoteAddrIP(r *http.Request) netip.Addr

RemoteAddrIP returns the ip parsed from r.RemoteAddr.

func StringDuration

func StringDuration(groups []string, a slog.Attr) slog.Attr

StringDuration is a ReplaceAttrFunc that renders duration values as strings.

func StringInt

func StringInt(groups []string, a slog.Attr) slog.Attr

StringInt is a ReplaceAttrFunc that renders int64 and uint64 values as strings.

It's useful in cases that your log ingester parses all number values as float64 and cause loss of precision.

func WithJSON

func WithJSON(o *options)

WithJSON sets the logger to be json logger.

This is the default behavior.

func WithText

func WithText(o *options)

WithText sets the logger to be text logger.

Types

type Option

type Option func(*options)

Option define logger options for New.

func WithAddSource

func WithAddSource(v bool) Option

WithAddSource sets the AddSouce option.

Default: false.

func WithCallstack

func WithCallstack(min slog.Leveler) Option

WithCallstack adds callstack at min level.

Set it to MaxLevel to disable callstack at all levels (except logs logged explicitly at MaxLevel). To add callstack at all levels, use MinLevel.

Default: MaxLevel.

func WithGlobalKVs

func WithGlobalKVs(kv ...any) Option

WithGlobalKVs sets global key-value pairs.

func WithLevel

func WithLevel(l slog.Leveler) Option

WithLevel sets the minimal log level.

Default: slog.InfoLevel.

func WithReplaceAttr

func WithReplaceAttr(f ReplaceAttrFunc) Option

WithReplaceAttr sets the ReplaceAttr option.

Note that this option is overwriting not cumulative. To chain several ReplaceAttr functions, use ChainReplaceAttr.

func WithWriter

func WithWriter(w io.Writer) Option

WithWriter sets the writer of the logger.

Default: os.Stderr.

type ReplaceAttrFunc

type ReplaceAttrFunc = func(groups []string, a slog.Attr) slog.Attr

Type alias for slog.HandlerOptions.ReplaceAttr.

func ChainReplaceAttr

func ChainReplaceAttr(fs ...ReplaceAttrFunc) ReplaceAttrFunc

ChainReplaceAttr chains multiple ReplaceAttrFunc together.

Jump to

Keyboard shortcuts

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