1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package metrics
17
18 import (
19 "context"
20 "reflect"
21
22 "github.com/go-logr/logr"
23 "github.com/prometheus/client_golang/prometheus"
24 ctrl "sigs.k8s.io/controller-runtime"
25 "sigs.k8s.io/controller-runtime/pkg/cache"
26
27 "github.com/chaos-mesh/chaos-mesh/api/v1alpha1"
28 "github.com/chaos-mesh/chaos-mesh/pkg/status"
29 )
30
31 const (
32
33 chaosControllerManagerMetricsSubsystem = "chaos_controller_manager"
34 )
35
36
37 type ChaosControllerManagerMetricsCollector struct {
38 logger logr.Logger
39 store cache.Cache
40 chaosExperiments *prometheus.GaugeVec
41 SidecarTemplates prometheus.Gauge
42 ConfigTemplates *prometheus.GaugeVec
43 InjectionConfigs *prometheus.GaugeVec
44 TemplateNotExist *prometheus.CounterVec
45 TemplateLoadError prometheus.Counter
46 ConfigNameDuplicate *prometheus.CounterVec
47 InjectRequired *prometheus.CounterVec
48 Injections *prometheus.CounterVec
49 chaosSchedules *prometheus.GaugeVec
50 chaosWorkflows *prometheus.GaugeVec
51 EmittedEvents *prometheus.CounterVec
52 }
53
54
55 func NewChaosControllerManagerMetricsCollector(manager ctrl.Manager, registerer *prometheus.Registry, logger logr.Logger) *ChaosControllerManagerMetricsCollector {
56 var store cache.Cache
57 if manager != nil {
58 store = manager.GetCache()
59 }
60
61 c := &ChaosControllerManagerMetricsCollector{
62 logger: logger,
63 store: store,
64 chaosExperiments: prometheus.NewGaugeVec(prometheus.GaugeOpts{
65 Subsystem: chaosControllerManagerMetricsSubsystem,
66 Name: "chaos_experiments",
67 Help: "Total number of chaos experiments and their phases",
68 }, []string{"namespace", "kind", "phase"}),
69 SidecarTemplates: prometheus.NewGauge(prometheus.GaugeOpts{
70 Subsystem: chaosControllerManagerMetricsSubsystem,
71 Name: "chaos_mesh_templates",
72 Help: "Total number of injection templates",
73 }),
74 ConfigTemplates: prometheus.NewGaugeVec(prometheus.GaugeOpts{
75 Subsystem: chaosControllerManagerMetricsSubsystem,
76 Name: "chaos_mesh_config_templates",
77 Help: "Total number of config templates",
78 }, []string{"namespace", "template"}),
79 InjectionConfigs: prometheus.NewGaugeVec(prometheus.GaugeOpts{
80 Subsystem: chaosControllerManagerMetricsSubsystem,
81 Name: "chaos_mesh_injection_configs",
82 Help: "Total number of injection configs",
83 }, []string{"namespace", "template"}),
84 TemplateNotExist: prometheus.NewCounterVec(prometheus.CounterOpts{
85 Subsystem: chaosControllerManagerMetricsSubsystem,
86 Name: "chaos_mesh_template_not_exist_total",
87 Help: "Total number of template not exist error",
88 }, []string{"namespace", "template"}),
89 ConfigNameDuplicate: prometheus.NewCounterVec(prometheus.CounterOpts{
90 Subsystem: chaosControllerManagerMetricsSubsystem,
91 Name: "chaos_mesh_config_name_duplicate_total",
92 Help: "Total number of config name duplication error",
93 }, []string{"namespace", "config"}),
94 TemplateLoadError: prometheus.NewCounter(prometheus.CounterOpts{
95 Subsystem: chaosControllerManagerMetricsSubsystem,
96 Name: "chaos_mesh_template_load_failed_total",
97 Help: "Total number of failures when rendering config args to template",
98 }),
99 InjectRequired: prometheus.NewCounterVec(prometheus.CounterOpts{
100 Subsystem: chaosControllerManagerMetricsSubsystem,
101 Name: "chaos_mesh_inject_required_total",
102 Help: "Total number of injections required",
103 }, []string{"namespace", "config"}),
104 Injections: prometheus.NewCounterVec(prometheus.CounterOpts{
105 Name: "chaos_mesh_injections_total",
106 Help: "Total number of sidecar injections performed on the webhook",
107 }, []string{"namespace", "config"}),
108 chaosSchedules: prometheus.NewGaugeVec(prometheus.GaugeOpts{
109 Subsystem: chaosControllerManagerMetricsSubsystem,
110 Name: "chaos_schedules",
111 Help: "Total number of chaos schedules",
112 }, []string{"namespace"}),
113 chaosWorkflows: prometheus.NewGaugeVec(prometheus.GaugeOpts{
114 Subsystem: chaosControllerManagerMetricsSubsystem,
115 Name: "chaos_workflows",
116 Help: "Total number of chaos workflows",
117 }, []string{"namespace"}),
118 EmittedEvents: prometheus.NewCounterVec(prometheus.CounterOpts{
119 Subsystem: chaosControllerManagerMetricsSubsystem,
120 Name: "emitted_event_total",
121 Help: "Total number of the emitted event by chaos-controller-manager",
122 }, []string{"type", "reason", "namespace"}),
123 }
124
125 if registerer != nil {
126 registerer.MustRegister(c)
127 }
128
129 return c
130 }
131
132
133 func (collector *ChaosControllerManagerMetricsCollector) Describe(ch chan<- *prometheus.Desc) {
134 collector.chaosExperiments.Describe(ch)
135 collector.SidecarTemplates.Describe(ch)
136 collector.ConfigTemplates.Describe(ch)
137 collector.InjectionConfigs.Describe(ch)
138 collector.TemplateNotExist.Describe(ch)
139 collector.ConfigNameDuplicate.Describe(ch)
140 collector.TemplateLoadError.Describe(ch)
141 collector.InjectRequired.Describe(ch)
142 collector.Injections.Describe(ch)
143 collector.EmittedEvents.Describe(ch)
144 collector.chaosSchedules.Describe(ch)
145 collector.chaosWorkflows.Describe(ch)
146 }
147
148
149 func (collector *ChaosControllerManagerMetricsCollector) Collect(ch chan<- prometheus.Metric) {
150 collector.collectChaosExperiments()
151 collector.collectChaosSchedules()
152 collector.collectChaosWorkflows()
153 collector.SidecarTemplates.Collect(ch)
154 collector.ConfigTemplates.Collect(ch)
155 collector.InjectionConfigs.Collect(ch)
156 collector.TemplateNotExist.Collect(ch)
157 collector.ConfigNameDuplicate.Collect(ch)
158 collector.TemplateLoadError.Collect(ch)
159 collector.InjectRequired.Collect(ch)
160 collector.Injections.Collect(ch)
161 collector.chaosExperiments.Collect(ch)
162 collector.chaosSchedules.Collect(ch)
163 collector.chaosWorkflows.Collect(ch)
164 collector.EmittedEvents.Collect(ch)
165 }
166
167 func (collector *ChaosControllerManagerMetricsCollector) collectChaosExperiments() {
168
169
170 collector.chaosExperiments.Reset()
171
172 for kind, obj := range v1alpha1.AllKinds() {
173 expCache := map[string]map[string]int{}
174 chaosList := obj.SpawnList()
175 if err := collector.store.List(context.TODO(), chaosList); err != nil {
176 collector.logger.Error(err, "failed to list chaos", "kind", kind)
177 return
178 }
179
180 items := chaosList.GetItems()
181 for _, item := range items {
182 if _, ok := expCache[item.GetNamespace()]; !ok {
183
184 expCache[item.GetNamespace()] = make(map[string]int, 4)
185 }
186 innerObject := reflect.ValueOf(item).Interface().(v1alpha1.InnerObject)
187 expCache[item.GetNamespace()][string(status.GetChaosStatus(innerObject))]++
188 }
189
190 for ns, v := range expCache {
191 for phase, count := range v {
192 collector.chaosExperiments.WithLabelValues(ns, kind, phase).Set(float64(count))
193 }
194 }
195 }
196 }
197
198 func (collector *ChaosControllerManagerMetricsCollector) collectChaosSchedules() {
199 collector.chaosSchedules.Reset()
200
201 schedules := &v1alpha1.ScheduleList{}
202 if err := collector.store.List(context.TODO(), schedules); err != nil {
203 collector.logger.Error(err, "failed to list schedules")
204 return
205 }
206
207 countByNamespace := make(map[string]int)
208 items := schedules.GetItems()
209 for _, item := range items {
210 countByNamespace[item.GetNamespace()]++
211 }
212
213 for namespace, count := range countByNamespace {
214 collector.chaosSchedules.WithLabelValues(namespace).Set(float64(count))
215 }
216 }
217
218 func (collector *ChaosControllerManagerMetricsCollector) collectChaosWorkflows() {
219 collector.chaosWorkflows.Reset()
220
221 workflows := &v1alpha1.WorkflowList{}
222 if err := collector.store.List(context.TODO(), workflows); err != nil {
223 collector.logger.Error(err, "failed to list workflows")
224 return
225 }
226
227 countByNamespace := make(map[string]int)
228 items := workflows.GetItems()
229 for _, item := range items {
230 countByNamespace[item.GetNamespace()]++
231 }
232
233 for namespace, count := range countByNamespace {
234 collector.chaosWorkflows.WithLabelValues(namespace).Set(float64(count))
235 }
236 }
237