| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869 |
- package util
- import (
- "context"
- "errors"
- "fmt"
- "log/slog"
- )
- type ContextualError struct {
- RealError error
- Fields map[string]any
- Context string
- }
- func NewContextualError(msg string, fields map[string]any, realError error) *ContextualError {
- return &ContextualError{Context: msg, Fields: fields, RealError: realError}
- }
- // ContextualizeIfNeeded is a helper function to turn an error into a ContextualError if it is not already one
- func ContextualizeIfNeeded(msg string, err error) error {
- switch err.(type) {
- case *ContextualError:
- return err
- default:
- return NewContextualError(msg, nil, err)
- }
- }
- // LogWithContextIfNeeded is a helper function to log an error line for an error or ContextualError
- func LogWithContextIfNeeded(msg string, err error, l *slog.Logger) {
- switch v := err.(type) {
- case *ContextualError:
- v.Log(l)
- default:
- l.Error(msg, "error", err)
- }
- }
- func (ce *ContextualError) Error() string {
- if ce.RealError == nil {
- return ce.Context
- }
- return fmt.Errorf("%s (%v): %w", ce.Context, ce.Fields, ce.RealError).Error()
- }
- func (ce *ContextualError) Unwrap() error {
- if ce.RealError == nil {
- return errors.New(ce.Context)
- }
- return ce.RealError
- }
- // Log emits ce as a single error-level log line with Fields and RealError
- // promoted to top-level attributes, producing a flat shape callers can grep
- // or parse without walking into a nested object.
- func (ce *ContextualError) Log(l *slog.Logger) {
- attrs := make([]slog.Attr, 0, len(ce.Fields)+1)
- for k, v := range ce.Fields {
- attrs = append(attrs, slog.Any(k, v))
- }
- if ce.RealError != nil {
- attrs = append(attrs, slog.Any("error", ce.RealError))
- }
- // LogAttrs is intentional: attrs is built from a map[string]any so it has
- // no pair-form equivalent.
- //nolint:sloglint
- l.LogAttrs(context.Background(), slog.LevelError, ce.Context, attrs...)
- }
|