logevent

package module
v0.0.4 Latest Latest
Warning

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

Go to latest
Published: Aug 4, 2026 License: MIT Imports: 4 Imported by: 0

README

LogEvent

CI Go Reference

This library provides utilities to implement the concept of emitting one canonical log (wide log event) after processing a unit of work, inspired by logging patterns from companies like Stripe or Google

This library provides the raw functionality to implement for any unit of work but also provides two middlewares, one for HTTP and another one for gRPC to be used out of the box. Check the examples folder for more information.

The steps are the following:

  • We define a struct that we are going to update/populate when serving a request.
  • We implement the Log method of the LogEvent interface. This allows us to change the way we want to log the event based on the values.
  • When serving the unit of work, we populate that struct event with all the useful information that we want to see in a the log entry.
  • Once the unit of work is served, the library will log that canonical log event by calling the method Log we implemented.

This is better described in loggingsucks.

To see it directly in action, check the examples folder.

Requirements

  • Go 1.25.0 or newer

⬇️ How to get it

go get github.com/manuelarte/logevent

🚀 Features

The library provides a generic function that can be used to implement the concept of adding a LogEvent to a context.Context, then do some work, and then Log that LogEvent.

But it also provides some out-of-the-box implementations for:

HTTP Middleware

This library provides a middleware that can be used to emit a log event after an HTTP request.

// Step 1. Define your log event struct and how to log it.
type transferLogEvent struct {
  Source string
  Target string
  Amount string
  Err    error
}

// Log the event either with Info if everything succeeded or with Error if there was an error.
func (e transferLogEvent) Log(ctx context.Context, li *slog.Logger) {
  if e.Err != nil {
    li.ErrorContext(
      ctx,
      "Error when transferring money",
      slog.String("source", e.Source),
      slog.String("target", e.Target),
      slog.String("amount", e.Amount),
      slog.Any("error", e.Err),
    )
    return
  }

  li.InfoContext(
    ctx,
    "Money transferred successfully",
    slog.String("source", e.Source),
    slog.String("target", e.Target),
    slog.String("amount", e.Amount),
  )
}

// Step 2. Add the middleware to your endpoint.
func registerRoutes() {
  http.Handle(
    "/my-endpoint",
    logeventmiddleware.AddLogEventMiddleware(transferLogEvent{}, slog.Default())(http.HandlerFunc(myHandler)),
  )
}

func myHandler(w http.ResponseWriter, r *http.Request) {
  // Step 3. Update your log event while serving the request.
  _ = logeventmiddleware.UpdateLogEvent(r.Context(), func(t *transferLogEvent) {
    t.Source = "Alice"
    t.Target = "Bob"
    t.Amount = "100"
  })
  ...
  err := transferMoney("Alice", "Bob", 100)
  _ = logeventmiddleware.UpdateLogEvent(r.Context(), func(t *transferLogEvent) {
    t.Err = err
  })
  ...
}
gRPC Interceptor

This library also provides a unary server interceptor for your gRPC server.

// Step 1. Define your log event struct and how to log it.
type transferLogEvent struct {
  Source string
  Target string
  Amount string
  Err    error
}

// Log the event either with Info if everything succeeded or with Error if there was an error.
func (e transferLogEvent) Log(ctx context.Context, li *slog.Logger) {
  if e.Err != nil {
    li.ErrorContext(
      ctx,
      "Error when transferring money",
      slog.String("source", e.Source),
      slog.String("target", e.Target),
      slog.String("amount", e.Amount),
      slog.Any("error", e.Err),
    )
    return
  }

  li.InfoContext(
    ctx,
    "Money transferred successfully",
    slog.String("source", e.Source),
    slog.String("target", e.Target),
    slog.String("amount", e.Amount),
  )
}

// Step 2. Add the interceptor to your server.
server := grpc.NewServer(
  grpc.UnaryInterceptor(
    logeventgrpc.UnaryServerInterceptor(transferLogEvent{}, slog.Default()),
  ),
)

func (s transferMoneyServer) Transfer(ctx context.Context, req *TransferMoneyRequest) (*TransferMoneyResponse, error) {
  // Step 3. Update your log event while handling the request.
  _ = logeventmiddleware.UpdateLogEvent(ctx, func(t *transferLogEvent) {
    t.Source = "Alice"
    t.Target = "Bob"
    t.Amount = "100"
  })
  ...
  err := transferMoney("Alice", "Bob", 100)
  _ = logeventmiddleware.UpdateLogEvent(ctx, func(t *transferLogEvent) {
    t.Err = err
  })
  ...
}

Architecture

This library provides an HTTP middleware and a gRPC interceptor, but also a generic implementation for a custom way to serve a request that encapsulates:

  1. Creating a per-request copy of the log event struct
  2. Wrapping it with thread-safe access (concurrency support)
  3. Storing it in the request context
  4. Deferring the log output until after the request handler completes
  5. Checking for any updates made by the handler

This ensures consistent behavior and makes it easy to update the logging logic in a single place.

Examples

For runnable examples check the examples folder.

Documentation

Index

Constants

This section is empty.

Variables

View Source
var ErrLogEventNotInitialized = errors.New("LogEvent not initialized")

ErrLogEventNotInitialized error returned when adding context to a log event but the log event was not initialized.

Functions

This section is empty.

Types

type DifferentLogEventTypeError

type DifferentLogEventTypeError struct {
	// contains filtered or unexported fields
}

func NewDifferentLogEventTypeError

func NewDifferentLogEventTypeError(previousType, currentType reflect.Type) *DifferentLogEventTypeError

func (DifferentLogEventTypeError) Error

type LogEvent

type LogEvent[L Logger] interface {
	// Log the event.
	Log(ctx context.Context, li L)
}

LogEvent is the interface that wraps how to Log the event.

type Logger added in v0.0.4

type Logger any

Logger is the interface that represents a logger.

Directories

Path Synopsis
Package middlewares provides functionality to use log events in any kind of scenario.
Package middlewares provides functionality to use log events in any kind of scenario.

Jump to

Keyboard shortcuts

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