slogx

package module
v1.4.0 Latest Latest
Warning

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

Go to latest
Published: Mar 23, 2024 License: MIT Imports: 2 Imported by: 8

README

slogx Go Reference Go codecov

Package slogx contains extensions for standard library's slog package.

Install

go get github.com/cappuccinotm/slogx

Handlers

  • slogx.Accumulator(slog.Handler) slog.Handler - returns a handler that accumulates attributes and groups from the WithGroup and WithAttrs calls, to pass them to the underlying handler only on Handle call. Allows middlewares to capture the handler-level attributes and groups, but may be consuming.

  • slogx.NopHandler() slog.Handler - returns a handler that does nothing. Can be used in tests, to disable logging.

  • slog.Chain - chains the multiple "middlewares" - handlers, which can modify the log entry.

  • slogt.TestHandler - returns a handler that logs the log entry through testing.T's Log function. It will shorten attributes, so the output will be more readable.

  • fblog.Handler - a handler that logs the log entry in the fblog-like format, like:

    2024-02-05 09:11:37  [INFO]: info message
                            key: 1
         some_multi_line_string: "line1\nline2\nline3"
                  multiline_any: "line1\nline2\nline3"
                      group.int: 1
                   group.string: "string"
                  group.float64: 1.1
                     group.bool: false
     ...some_very_very_long_key: 1
    

    Some benchmarks (though this handler wasn't designed for performance, but for comfortable reading of the logs in debug/local mode):

    BenchmarkHandler
    BenchmarkHandler/fblog.NewHandler
    BenchmarkHandler/fblog.NewHandler-8         	 1479525	       800.9 ns/op	     624 B/op	       8 allocs/op
    BenchmarkHandler/slog.NewJSONHandler
    BenchmarkHandler/slog.NewJSONHandler-8      	 2407322	       500.0 ns/op	      48 B/op	       1 allocs/op
    BenchmarkHandler/slog.NewTextHandler
    BenchmarkHandler/slog.NewTextHandler-8      	 2404581	       490.0 ns/op	      48 B/op	       1 allocs/op
    

    All the benchmarks were run on a MacBook Pro (14-inch, 2021) with Apple M1 processor, the benchmark contains the only log lg.Info("message", slog.Int("int", 1))

Middlewares

  • slogm.RequestID() - adds a request ID to the context and logs it.
    • slogm.ContextWithRequestID(ctx context.Context, requestID string) context.Context - adds a request ID to the context.
  • slogm.StacktraceOnError() - adds a stacktrace to the log entry if log entry's level is ERROR.
  • slogm.TrimAttrs(limit int) - trims the length of the attributes to limit.
  • slogm.MaskSecrets(replacement string) - masks secrets in logs, which are stored in the context
    • slogm.AddSecrets(ctx context.Context, secret ...string) context.Context - adds a secret value to the context
      • Note: secrets are stored in the context as a pointer to the container object, guarded by a mutex. Child context can safely add secrets to the context, and the secrets will be available for the parent context, but before using the secrets container, the container must be initialized in the parent context with this function, e.g.:
        ctx = slogm.AddSecrets(ctx)
        

Helpers

  • slogx.Error(err error) - adds an error to the log entry under "error" key.

Example

package main

import (
	"context"
	"errors"
	"os"

	"github.com/cappuccinotm/slogx"
	"github.com/cappuccinotm/slogx/slogm"
	"github.com/google/uuid"
	"log/slog"
)

func main() {
  h := slog.NewJSONHandler(os.Stderr, &slog.HandlerOptions{
    AddSource: true,
    Level:     slog.LevelInfo,
  })

  logger := slog.New(slogx.Accumulator(slogx.NewChain(h,
    slogm.RequestID(),
    slogm.StacktraceOnError(),
    slogm.MaskSecrets("***"),
  )))

  ctx := slogm.ContextWithRequestID(context.Background(), uuid.New().String())
  ctx = slogm.AddSecrets(ctx, "secret")
  logger.InfoContext(ctx,
    "some message",
    slog.String("key", "value"),
  )

  logger.ErrorContext(ctx, "oh no, an error occurred",
    slog.String("details", "some important secret error details"),
    slogx.Error(errors.New("some error")),
  )

  logger.WithGroup("group1").
    With(slog.String("omg", "the previous example was wrong")).
    WithGroup("group2").
    With(slog.String("omg", "this is the right example")).
    With(slog.String("key", "value")).
          InfoContext(ctx, "some message",
            slog.String("key", "value"))
}

Produces:

{
  "time": "2023-08-17T02:04:19.281961+06:00",
  "level": "INFO",
  "source": {
    "function": "main.main",
    "file": "/.../github.com/cappuccinotm/slogx/_example/main.go",
    "line": 25
  },
  "msg": "some message",
  "key": "value",
  "request_id": "bcda1960-fa4d-46b3-9c1b-fec72c7c07a3"
}
{
   "time": "2023-08-17T03:35:21.251385+06:00",
   "level": "ERROR",
   "source": {
       "function": "main.main",
       "file": "/Users/semior/go/src/github.com/cappuccinotm/slogx/_example/main.go",
       "line": 47
   },
   "msg": "oh no, an error occurred",
   "details": "some important *** error details",
   "error": "some error",
   "request_id": "8ba29407-5d58-4dca-99e9-54528b1ae3f0",
   "stacktrace": "main.main()\n\t/Users/semior/go/src/github.com/cappuccinotm/slogx/_example/main.go:47 +0x4a4\n"
}
{
  "time": "2024-02-18T05:02:13.030604+06:00",
  "level": "INFO",
  "source": {
    "function": "main.main",
    "file": "/Users/semior/go/src/github.com/cappuccinotm/slogx/_example/main.go",
    "line": 74
  },
  "msg": "some message",
  "key": "value",
  "group1": {
    "omg": "the previous example was wrong",
    "group2": {
      "omg": "this is the right example",
      "key": "value"
    }
  },
  "request_id": "1a34889f-a5b4-464e-9a86-0a30b50376cc"
}

Client/Server logger

Package slogx also contains a logger package, which provides a Logger service, that could be used as an HTTP server middleware and a http.RoundTripper, that logs HTTP requests and responses.

Usage
l := logger.New(
    logger.WithLogger(slog.Default()),
    logger.WithBody(1024),
    logger.WithUser(func(*http.Request) (string, error) { return "username", nil }),
)
Options
  • logger.WithLogger(logger slog.Logger) - sets the slog logger.
  • logger.WithLogFn(fn func(context.Context, *LogParts)) - sets a custom function to log request and response.
  • logger.WithBody(maxBodySize int) - logs the request and response body, maximum size of the logged body is set by maxBodySize.
  • logger.WithUser(fn func(*http.Request) (string, error)) - sets a function to get the user data from the request.

Testing handler

Library provides a slogt.TestHandler function to build a test handler, which will print out the log entries through testing.T's Log function. It will shorten attributes, so the output will be more readable.

Usage
func TestSomething(t *testing.T) {
    h := slogt.Handler(t, slogt.SplitMultiline)
    logger := slog.New(h)
    logger.Info("some\nmultiline\nmessage", slog.String("key", "value"))
}

// Output:
// === RUN   TestSomething
//     handler.go:306: t=11:36:28.649 l=DEBUG s=main_test.go:12 msg="some single-line message" key=value group.groupKey=groupValue
//     
//     testing.go:52: some
//     testing.go:52: multiline
//     testing.go:52: message
//     handler.go:306: t=11:36:28.649 l=INFO s=main_test.go:17 msg="message with newlines has been printed to t.Log" key=value

Documentation

Overview

Package slogx contains extensions for standard library's slog package.

Index

Constants

This section is empty.

Variables

View Source
var (
	ErrorKey     = "error"
	RequestIDKey = "request_id"
)

Common used keys.

View Source
var ErrAttrStrategy = LogAttrAsIs

ErrAttrStrategy specifies how to log errors. "AsIs" logs nils, when the error is nil, if you want to not log nils, use "None". Example:

2024/01/13 15:20:26 ERROR LogAttrAsIs, error       | error="some error"
2024/01/13 15:20:26 ERROR LogAttrAsIs, nil         | error=<nil>
2024/01/13 15:20:26 ERROR LogAttrNone, error       | error="some error"
2024/01/13 15:20:26 ERROR LogAttrNone, nil         |

Functions

func Accumulator added in v1.3.0

func Accumulator(h slog.Handler) slog.Handler

Accumulator is a wrapper for slog.Handler that accumulates attributes and groups and passes them to the underlying handler only on Handle call, instead of logging them immediately.

func Attrs added in v1.3.0

func Attrs(rec slog.Record) []slog.Attr

Attrs returns attributes from the given record.

func Error

func Error(err error) slog.Attr

Error returns an attribute with error key.

func NopHandler added in v0.0.3

func NopHandler() slog.Handler

NopHandler returns a slog.Handler, that does nothing.

Types

type Chain

type Chain struct {
	slog.Handler
	// contains filtered or unexported fields
}

Chain is a chain of middleware.

func NewChain

func NewChain(base slog.Handler, mws ...Middleware) *Chain

NewChain returns a new Chain with the given middleware.

func (*Chain) Handle

func (c *Chain) Handle(ctx context.Context, rec slog.Record) error

Handle runs the chain of middleware and the handler.

func (*Chain) WithAttrs

func (c *Chain) WithAttrs(attrs []slog.Attr) slog.Handler

WithAttrs returns a new Chain with the given attributes.

func (*Chain) WithGroup

func (c *Chain) WithGroup(group string) slog.Handler

WithGroup returns a new Chain with the given group. It applies middlewares on the top-level handler.

type HandleFunc

type HandleFunc func(context.Context, slog.Record) error

HandleFunc is a function that handles a record.

type LogAttrStrategy added in v1.0.0

type LogAttrStrategy uint8

LogAttrStrategy specifies what to do with the attribute that is about to be logged.

const (
	// LogAttrNone means that the attribute should not be logged.
	LogAttrNone LogAttrStrategy = iota
	// LogAttrAsIs means that the attribute should be logged as is.
	LogAttrAsIs
)

type Middleware

type Middleware func(HandleFunc) HandleFunc

Middleware is a middleware for logging handler.

Directories

Path Synopsis
Package fblog provides slog handler and its options to print logs in the fblog-like style.
Package fblog provides slog handler and its options to print logs in the fblog-like style.
internal/misc
Package misc provides miscellaneous data types and functions for better processing of log entries.
Package misc provides miscellaneous data types and functions for better processing of log entries.
Package logger contains a service that provides methods to log HTTP requests for both server and client sides.
Package logger contains a service that provides methods to log HTTP requests for both server and client sides.
Package slogm contains middlewares for chaining and decoupling process of enriching or reducing logs.
Package slogm contains middlewares for chaining and decoupling process of enriching or reducing logs.
Package slogt provides functions for comfortable using of slog in tests.
Package slogt provides functions for comfortable using of slog in tests.

Jump to

Keyboard shortcuts

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