-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathseverity.go
More file actions
93 lines (86 loc) · 3.79 KB
/
severity.go
File metadata and controls
93 lines (86 loc) · 3.79 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
// Package errors is pleme-io's standard error model for Go services and tools.
// It is the Go counterpart to the Rust fleet's use of `anyhow` (free-form
// context wrapping) and `thiserror` (typed, inspectable errors), with the
// severity ladder from pleme-actions-shared folded in so a single error value
// carries its message, its cause chain, an optional machine code, and how
// loudly an operator should hear about it.
//
// The model is deliberately small. Everything is one concrete type — [Error] —
// that satisfies the standard library's error interface and participates fully
// in [errors.Is], [errors.As], and [errors.Unwrap]. There is no parallel error
// hierarchy to learn: you wrap with [Wrap], you create with [New], you read the
// metadata back with [SeverityOf] and [CodeOf], and you keep using the stdlib
// errors package for everything else.
//
// # Anyhow analog — context wrapping
//
// if err := step(); err != nil {
// return errs.Wrap(err, "reconcile tenant config")
// }
//
// Each [Wrap] adds a layer of human context while preserving the original cause
// for [errors.Is]/[errors.As]. [Wrap] returns nil when its input is nil, so it
// is safe to call unconditionally in a tail position.
//
// # Thiserror analog — typed sentinels and codes
//
// var ErrNotFound = errs.New("tenant not found", errs.WithCode("E_NOT_FOUND"))
//
// if errors.Is(err, ErrNotFound) { ... } // matches across wraps
// code := errs.CodeOf(err) // "E_NOT_FOUND", walks the chain
//
// # Severity ladder — pleme-actions-shared
//
// err := errs.New("token nearing expiry", errs.WithSeverity(errs.SeverityWarning))
// switch errs.SeverityOf(err) {
// case errs.SeverityNotice: // informational
// case errs.SeverityWarning: // degraded, still operating
// case errs.SeverityError: // failed (the default)
// }
//
// # Aggregation
//
// [Join] mirrors [errors.Join]: it collects several errors into one whose
// [errors.Is]/[errors.As] reach every member. The aggregate's severity is the
// most severe of its members.
package errors
import "strconv"
// Severity is the operator-facing weight of an [Error], mirroring the severity
// ladder used by pleme-actions-shared. Higher values are more severe, so
// severities compose with the builtin comparison operators and with [max].
type Severity int
// The severity constants are prefixed (SeverityNotice, SeverityWarning,
// SeverityError) because the marquee type of this package is [Error] — a bare
// const named Error would collide with it. This mirrors log/slog's
// LevelInfo/LevelWarn convention exactly.
const (
// SeverityNotice is informational: something worth recording, but not a
// failure and not a degradation. The quietest rung of the ladder.
SeverityNotice Severity = iota
// SeverityWarning marks a degraded-but-operating condition — a soft
// failure, a retry that eventually succeeded, a resource nearing a limit.
SeverityWarning
// SeverityError marks an outright failure. It is the default severity for
// any error created or wrapped without an explicit [WithSeverity], so an
// un-annotated error is never silently treated as benign.
SeverityError
)
// String returns the lowercase name of the severity ("notice", "warning",
// "error"). Unknown values render as severity(N) so logs stay unambiguous even
// if the ladder is extended out of band.
func (s Severity) String() string {
switch s {
case SeverityNotice:
return "notice"
case SeverityWarning:
return "warning"
case SeverityError:
return "error"
default:
return "severity(" + strconv.Itoa(int(s)) + ")"
}
}
// DefaultSeverity is the severity assigned to any [Error] built without an
// explicit [WithSeverity], and the value [SeverityOf] returns when no Error in
// a chain carries severity metadata. Failures are loud by default.
const DefaultSeverity = SeverityError