Documentation
¶
Overview ¶
Package errs provides error values that carry structured context for logs: the location of every wrap, a full stack trace from the point of origin, a machine-readable code, a client-safe public message, and allowlisted metadata.
Errors compose like fmt.Errorf — Error() output is byte-identical to the usual "pkg: op: %w" convention and errors.Is/As/Join work unchanged — but each wrap level keeps its own message and call site, so logs can render the chain step by step instead of one concatenated string.
The internal message (Error()) is never meant for clients. Attach Public to set what a client may see; httperr renders it as the Problem detail. Stack traces and chains appear in logs via LogValue; httperr also includes them in responses, but only in dev mode (WithExposeInternal).
Package-level sentinels should stay stdlib errors.New: an errs.New sentinel would freeze an init-time stack and share mutable attrs across requests. Wrap the sentinel per call instead: errs.Wrap(ErrNotFound, "news: get"). For a sentinel that also carries a code, a public message or an HTTP status, declare an errs.Definition instead (see define.go): definitions are immutable and stackless, so they are safe as package-level vars, and every occurrence still gets its own stack captured at the call site via Definition.New/Wrap.
Index ¶
- func CodeOf(err error) string
- func Errorf(format string, args ...any) error
- func New(msg string, attrs ...Attr) error
- func NewPanic(rec any, attrs ...Attr) error
- func PublicOf(err error) string
- func StatusOf(err error) int
- func Wrap(err error, msg string, attrs ...Attr) error
- func Wrapf(err error, format string, args ...any) error
- type Attr
- type Definition
- type Error
- type Frame
- type Step
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func CodeOf ¶
CodeOf returns the first code found walking err's chain from the outside in, or "" if none is set. A bare *Definition (returned instead of an instantiated error by mistake) is also recognized, so misuse still surfaces a code rather than none.
func Errorf ¶
Errorf builds a new error fmt.Errorf-style; %w (single and multi) works as usual. The stack is captured here unless a wrapped cause already has one.
func NewPanic ¶
NewPanic builds an error from a recovered panic value, capturing the stack at the recovery point. Called inside a deferred function during unwinding, the captured stack still contains the panic site below runtime.gopanic. An error panic value becomes the cause, so errors.Is/As keep working; any other value is formatted as "panic: %v". It must call newError directly so the callerSkip depth stays the same as New (pinned by TestNewPanicCapturesPanicSite).
func PublicOf ¶
PublicOf returns the first client-safe message found walking err's chain from the outside in, or "" if none is set.
func StatusOf ¶
StatusOf returns the first HTTP status found walking err's chain from the outside in, or 0 if none is set. httperr.mapProblem falls back to 500.
Types ¶
type Attr ¶
type Attr func(*Error)
Attr attaches optional context to an error at construction time.
func Code ¶
Code sets a machine-readable error code, e.g. "contact_create_failed": snake_case, stable across releases. It becomes the Sentry issue title and grouping fingerprint (see sentryx), the "errs.code" log/tag field and the RFC 9457 "code" member of the HTTP response. Convention: "<module>_<action>_failed" for unexpected operational failures (e.g. "contact_create_failed"), "<module>_<condition>" for expected business errors (e.g. "contact_not_found").
func Public ¶
Public sets the client-safe message. It is the only text from the error that may reach an HTTP response, and is shown as the Sentry issue's secondary line (see sentryx) in place of the internal composed message.
type Definition ¶
type Definition struct {
// contains filtered or unexported fields
}
Definition is a declared error kind: a stable code, a default client-safe message and an optional HTTP status, shared by every occurrence of one failure mode. Declare one per domain error at package level —
var ErrSubmit = errs.Define("contact_submit_failed",
errs.Public("Sikertelen mentés, próbálja újra később."))
— and instantiate it at the failure site with New/Newf/Wrap/Wrapf, which capture the call site and stack exactly like the package-level counterparts:
return ErrSubmit.Wrap(err, "contact: insert")
A Definition itself carries no stack and no mutable state, so unlike an errs.New sentinel it is safe as a package-level var (see the package doc). errors.Is(err, ErrSubmit) matches any error instantiated from it, at any depth of further wrapping, via (*Error).Is.
func Define ¶
func Define(code string, attrs ...Attr) *Definition
Define declares an error kind. code becomes the Sentry issue title and grouping fingerprint, the "errs.code" tag, and the RFC 9457 "code" member (see the Code attr doc for the naming convention). attrs accepts Public, Status and With to set the definition's defaults; Code is redundant here (code is already the first argument) and Status must be a 4xx or 5xx HTTP status or Define panics — both are programmer errors caught at init time, not request time.
func (*Definition) Error ¶
func (d *Definition) Error() string
Error returns the definition's code, so a *Definition is itself a legal errors.Is target (and, if ever returned directly by mistake, still produces a meaningful message instead of a blank one). Never return a Definition itself as an error — always instantiate with New/Newf/Wrap/Wrapf so a stack is captured at the call site.
func (*Definition) New ¶
func (d *Definition) New(msg string, attrs ...Attr) error
New builds a new error of this kind, capturing the call site and a full stack trace. attrs are applied after the definition's defaults, so they can override code/public/status/meta for this occurrence.
It calls newError directly (like NewPanic) so callerSkip stays pinned to the same depth as the package-level constructors; see TestDefinitionCaptureSkip.
func (*Definition) Newf ¶
func (d *Definition) Newf(format string, args ...any) error
Newf is New with a fmt.Sprintf message.
func (*Definition) Wrap ¶
func (d *Definition) Wrap(err error, msg string, attrs ...Attr) error
Wrap annotates err with a message and the call site, stamped with this definition. It returns nil when err is nil, so it is safe in one-line returns. A full stack trace is captured only if no error in err's chain carries one already.
type Error ¶
type Error struct {
// contains filtered or unexported fields
}
Error is the concrete error type. It is exported only so errors.As works; construct values with New, Errorf, Wrap or Wrapf.
func (*Error) Is ¶
Is reports whether e was instantiated from the given Definition, so errors.Is(err, someDefinition) matches any occurrence stamped from it (Definition.New/.Wrap), no matter how deeply it is later wrapped. It returns false for any other target, leaving errors.Is's default identity comparison (and any other Is method in the chain) untouched.
func (*Error) LogValue ¶
LogValue renders the error as a structured group so slog.Any("error", err) emits per-level detail instead of one flattened string:
"error": {
"msg": "news: publish: news article: get: connection refused",
"code": "article_get",
"public": "...",
"chain": [{"msg","file","line","function","code","meta"}, ...],
"stack": [{"file","line","function"}, ...]
}
chain lists every wrap level with its own message, call site and attrs; stack is the full call path from the point of origin. Stacks resolve lazily — the cost is paid only when the error is actually logged.
func (*Error) StackTrace ¶
StackTrace returns the program counters of the chain's full stack. The method shape is recognized by sentry-go's reflected stack extraction.
type Frame ¶
type Frame struct {
File string `json:"file"` // last two path segments, e.g. "pg/transactor.go"
Line int `json:"line"`
Function string `json:"function"` // without module path, e.g. "pg.(*Transactor).WithinTx"
}
Frame is one resolved stack frame, structured for log pipelines. Frames shortens File to the last two path segments; FullFrames keeps the absolute path for console renderers that want exact locations.
func Frames ¶
Frames returns the full stack from the error's point of origin, resolved lazily, with File shortened to the last two path segments. It returns nil when no error in the chain carries a stack.
func FullFrames ¶
FullFrames is Frames with untruncated absolute file paths. Console renderers that print clickable locations (otelx LOG_FORMAT=monolog) use it; most log pipelines want the shorter Frames.
type Step ¶
type Step struct {
Msg string `json:"msg"`
File string `json:"file,omitempty"`
Line int `json:"line,omitempty"`
Function string `json:"function,omitempty"`
Code string `json:"code,omitempty"`
Meta map[string]any `json:"meta,omitempty"`
}
Step is one level of an error chain: the level's own message, the call site of the wrap, and the attrs set at that level. The root cause appears as a final Step without location.