httplog

package module
v2.0.11 Latest Latest
Warning

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

Go to latest
Published: Apr 22, 2024 License: MIT Imports: 15 Imported by: 47

README

httplog

Small but powerful structured logging package for HTTP request logging built on the Go 1.21+ stdlib slog package.

go get -u github.com/go-chi/httplog/v2

Example

(see _example/)

package main

import (
  "log/slog"
  "net/http"
  "github.com/go-chi/chi/v5"
  "github.com/go-chi/chi/v5/middleware"
  "github.com/go-chi/httplog/v2"
)

func main() {
  // Logger
  logger := httplog.NewLogger("httplog-example", httplog.Options{
    // JSON:             true,
    LogLevel:         slog.LevelDebug,
    Concise:          true,
    RequestHeaders:   true,
    MessageFieldName: "message",
    // TimeFieldFormat: time.RFC850,
    Tags: map[string]string{
      "version": "v1.0-81aa4244d9fc8076a",
      "env":     "dev",
    },
    QuietDownRoutes: []string{
      "/",
      "/ping",
    },
    QuietDownPeriod: 10 * time.Second,
    // SourceFieldName: "source",
  })

  // Service
  r := chi.NewRouter()
  r.Use(httplog.RequestLogger(logger))
  r.Use(middleware.Heartbeat("/ping"))

  r.Use(func(next http.Handler) http.Handler {
    return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
      ctx := r.Context()
      httplog.LogEntrySetField(ctx, "user", slog.StringValue("user1"))
      next.ServeHTTP(w, r.WithContext(ctx))
    })
  })

  r.Get("/", func(w http.ResponseWriter, r *http.Request) {
    w.Write([]byte("hello world"))
  })

  r.Get("/panic", func(w http.ResponseWriter, r *http.Request) {
    panic("oh no")
  })

  r.Get("/info", func(w http.ResponseWriter, r *http.Request) {
    oplog := httplog.LogEntry(r.Context())
    w.Header().Add("Content-Type", "text/plain")
    oplog.Info("info here")
    w.Write([]byte("info here"))
  })

  r.Get("/warn", func(w http.ResponseWriter, r *http.Request) {
    oplog := httplog.LogEntry(r.Context())
    oplog.Warn("warn here")
    w.WriteHeader(400)
    w.Write([]byte("warn here"))
  })

  r.Get("/err", func(w http.ResponseWriter, r *http.Request) {
    oplog := httplog.LogEntry(r.Context())
    oplog.Error("msg here", "err", errors.New("err here"))
    w.WriteHeader(500)
    w.Write([]byte("oops, err"))
  })

  http.ListenAndServe("localhost:8000", r)
}

License

MIT

Documentation

Index

Constants

This section is empty.

Variables

View Source
var DefaultHandlerConfig = &slog.HandlerOptions{
	Level:     slog.LevelInfo,
	AddSource: true,
}
View Source
var IsTTY bool

Functions

func ErrAttr added in v2.0.5

func ErrAttr(err error) slog.Attr

func Handler

func Handler(logger *Logger, optSkipPaths ...[]string) func(next http.Handler) http.Handler

func LevelByName added in v2.0.6

func LevelByName(name string) slog.Level

func LogEntry

func LogEntry(ctx context.Context) *slog.Logger

func LogEntrySetField

func LogEntrySetField(ctx context.Context, key string, value slog.Value)

func LogEntrySetFields

func LogEntrySetFields(ctx context.Context, fields map[string]interface{})

func RequestLogger

func RequestLogger(logger *Logger, skipPaths ...[]string) func(next http.Handler) http.Handler

RequestLogger is an http middleware to log http requests and responses.

NOTE: for simplicity, RequestLogger automatically makes use of the chi RequestID and Recoverer middleware.

func StructValue added in v2.0.8

func StructValue(v interface{}) slog.Value

StructValue will convert a struct or slice of structs to a slog.Value

Types

type Logger

type Logger struct {
	*slog.Logger
	Options Options
}

func NewLogger

func NewLogger(serviceName string, options ...Options) *Logger

func (*Logger) Configure

func (l *Logger) Configure(opts Options)

Configure will set new options for the httplog instance and behaviour of underlying slog pkg and its global logger.

type Options

type Options struct {
	// LogLevel defines the minimum level of severity that app should log.
	// Must be one of:
	// slog.LevelDebug, slog.LevelInfo, slog.LevelWarn, slog.LevelError
	LogLevel slog.Level

	// LevelFieldName sets the field name for the log level or severity.
	// Some providers parse and search for different field names.
	LevelFieldName string

	// MessageFieldName sets the field name for the message.
	// Default is "msg".
	MessageFieldName string

	// JSON enables structured logging output in json. Make sure to enable this
	// in production mode so log aggregators can receive data in parsable format.
	//
	// In local development mode, its appropriate to set this value to false to
	// receive pretty output and stacktraces to stdout.
	JSON bool

	// Concise mode includes fewer log details during the request flow. For example
	// excluding details like request content length, user-agent and other details.
	// This is useful if during development your console is too noisy.
	Concise bool

	// Tags are additional fields included at the root level of all logs.
	// These can be useful for example the commit hash of a build, or an environment
	// name like prod/stg/dev
	Tags map[string]string

	// RequestHeaders enables logging of all request headers, however sensitive
	// headers like authorization, cookie and set-cookie are hidden.
	RequestHeaders bool

	// HideRequestHeaders are additional requests headers which are redacted from the logs
	HideRequestHeaders []string

	// ResponseHeaders enables logging of all response headers.
	ResponseHeaders bool

	// QuietDownRoutes are routes which are temporarily excluded from logging for a QuietDownPeriod after it occurs
	// for the first time
	// to cancel noise from logging for routes that are known to be noisy.
	QuietDownRoutes []string

	// QuietDownPeriod is the duration for which a route is excluded from logging after it occurs for the first time
	// if the route is in QuietDownRoutes
	QuietDownPeriod time.Duration

	// TimeFieldFormat defines the time format of the Time field, defaulting to "time.RFC3339Nano" see options at:
	// https://pkg.go.dev/time#pkg-constants
	TimeFieldFormat string

	// TimeFieldName sets the field name for the time field.
	// Some providers parse and search for different field names.
	TimeFieldName string

	// SourceFieldName sets the field name for the source field which logs
	// the location in the program source code where the logger was called.
	// If set to "" then it'll be disabled.
	SourceFieldName string

	// Writer is the log writer, default is os.Stdout
	Writer io.Writer

	// ReplaceAttrsOverride allows to add custom logic to replace attributes
	// in addition to the default logic set in this package.
	ReplaceAttrsOverride func(groups []string, a slog.Attr) slog.Attr
}

type PrettyHandler

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

func NewPrettyHandler

func NewPrettyHandler(w io.Writer, options ...*slog.HandlerOptions) *PrettyHandler

func (*PrettyHandler) Enabled

func (h *PrettyHandler) Enabled(ctx context.Context, level slog.Level) bool

func (*PrettyHandler) Handle

func (h *PrettyHandler) Handle(ctx context.Context, r slog.Record) error

func (*PrettyHandler) WithAttrs

func (h *PrettyHandler) WithAttrs(attrs []slog.Attr) slog.Handler

func (*PrettyHandler) WithGroup

func (h *PrettyHandler) WithGroup(name string) slog.Handler

type RequestLoggerEntry

type RequestLoggerEntry struct {
	Logger  *slog.Logger
	Options Options
	// contains filtered or unexported fields
}

func (*RequestLoggerEntry) Panic

func (l *RequestLoggerEntry) Panic(v interface{}, stack []byte)

func (*RequestLoggerEntry) Write

func (l *RequestLoggerEntry) Write(status, bytes int, header http.Header, elapsed time.Duration, extra interface{})

Directories

Path Synopsis

Jump to

Keyboard shortcuts

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