Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
aos
GitHub Repository: aos/grafana-agent
Path: blob/main/component/component_health.go
4093 views
1
package component
2
3
import (
4
"encoding"
5
"fmt"
6
"time"
7
)
8
9
// HealthComponent is an optional extension interface for Components which
10
// report health information.
11
//
12
// Health information is exposed to the end user for informational purposes and
13
// cannot be referened in a River expression.
14
type HealthComponent interface {
15
Component
16
17
// CurrentHealth returns the current Health status for the component.
18
//
19
// CurrentHealth may be overridden by the Flow controller if there is a
20
// higher-level issue, such as a config file being invalid or a Component
21
// shutting down unexpectedly.
22
CurrentHealth() Health
23
}
24
25
// Health is the reported health state of a component. It can be encoded to
26
// River.
27
type Health struct {
28
// The specific health value.
29
Health HealthType `river:"state,attr"`
30
31
// An optional message to describe the health; useful to say why a component
32
// is unhealthy.
33
Message string `river:"message,attr,optional"`
34
35
// An optional time to indicate when the component last modified something
36
// which updated its health.
37
UpdateTime time.Time `river:"update_time,attr,optional"`
38
}
39
40
// HealthType holds the health value for a component.
41
type HealthType uint8
42
43
var (
44
_ encoding.TextMarshaler = HealthType(0)
45
_ encoding.TextUnmarshaler = (*HealthType)(nil)
46
)
47
48
const (
49
// HealthTypeUnknown is the initial health of components, set when they're
50
// first created.
51
HealthTypeUnknown HealthType = iota
52
53
// HealthTypeHealthy represents a component which is working as expected.
54
HealthTypeHealthy
55
56
// HealthTypeUnhealthy represents a component which is not working as
57
// expected.
58
HealthTypeUnhealthy
59
60
// HealthTypeExited represents a component which has stopped running.
61
HealthTypeExited
62
)
63
64
// String returns the string representation of ht.
65
func (ht HealthType) String() string {
66
switch ht {
67
case HealthTypeHealthy:
68
return "healthy"
69
case HealthTypeUnhealthy:
70
return "unhealthy"
71
case HealthTypeExited:
72
return "exited"
73
default:
74
return "unknown"
75
}
76
}
77
78
// MarshalText implements encoding.TextMarshaler.
79
func (ht HealthType) MarshalText() (text []byte, err error) {
80
return []byte(ht.String()), nil
81
}
82
83
// UnmarshalText implements encoding.TextUnmarshaler.
84
func (ht *HealthType) UnmarshalText(text []byte) error {
85
switch string(text) {
86
case "healthy":
87
*ht = HealthTypeHealthy
88
case "unhealthy":
89
*ht = HealthTypeUnhealthy
90
case "unknown":
91
*ht = HealthTypeUnknown
92
case "exited":
93
*ht = HealthTypeExited
94
default:
95
return fmt.Errorf("invalid health type %q", string(text))
96
}
97
return nil
98
}
99
100
// LeastHealthy returns the Health from the provided arguments which is
101
// considered to be the least healthy.
102
//
103
// Health types are first prioritized by [HealthTypeExited], followed by
104
// [HealthTypeUnhealthy], [HealthTypeUnknown], and [HealthTypeHealthy].
105
//
106
// If multiple arguments have the same Health type, the Health with the most
107
// recent timestamp is returned.
108
//
109
// Finally, if multiple arguments have the same Health type and the same
110
// timestamp, the earlier argument is chosen.
111
func LeastHealthy(h Health, hh ...Health) Health {
112
if len(hh) == 0 {
113
return h
114
}
115
116
leastHealthy := h
117
118
for _, compareHealth := range hh {
119
switch {
120
case healthPriority[compareHealth.Health] > healthPriority[leastHealthy.Health]:
121
// Higher health precedence.
122
leastHealthy = compareHealth
123
case compareHealth.Health == leastHealthy.Health:
124
// Same health precedence; check timestamp.
125
if compareHealth.UpdateTime.After(leastHealthy.UpdateTime) {
126
leastHealthy = compareHealth
127
}
128
}
129
}
130
131
return leastHealthy
132
}
133
134
// healthPriority maps a HealthType to its priority; higher numbers means "less
135
// healthy."
136
var healthPriority = [...]int{
137
HealthTypeHealthy: 0,
138
HealthTypeUnknown: 1,
139
HealthTypeUnhealthy: 2,
140
HealthTypeExited: 3,
141
}
142
143