github.com/netdata/go.d.plugin@v0.58.1/modules/supervisord/collect.go (about) 1 // SPDX-License-Identifier: GPL-3.0-or-later 2 3 package supervisord 4 5 import ( 6 "fmt" 7 "strings" 8 9 "github.com/netdata/go.d.plugin/agent/module" 10 ) 11 12 func (s *Supervisord) collect() (map[string]int64, error) { 13 info, err := s.client.getAllProcessInfo() 14 if err != nil { 15 return nil, err 16 } 17 18 ms := make(map[string]int64) 19 s.collectAllProcessInfo(ms, info) 20 21 return ms, nil 22 } 23 24 func (s *Supervisord) collectAllProcessInfo(ms map[string]int64, info []processStatus) { 25 s.resetCache() 26 ms["running_processes"] = 0 27 ms["non_running_processes"] = 0 28 for _, p := range info { 29 if _, ok := s.cache[p.group]; !ok { 30 s.cache[p.group] = make(map[string]bool) 31 s.addProcessGroupCharts(p) 32 } 33 if _, ok := s.cache[p.group][p.name]; !ok { 34 s.addProcessToCharts(p) 35 } 36 s.cache[p.group][p.name] = true 37 38 ms["group_"+p.group+"_running_processes"] += 0 39 ms["group_"+p.group+"_non_running_processes"] += 0 40 if isProcRunning(p) { 41 ms["running_processes"] += 1 42 ms["group_"+p.group+"_running_processes"] += 1 43 } else { 44 ms["non_running_processes"] += 1 45 ms["group_"+p.group+"_non_running_processes"] += 1 46 } 47 id := procID(p) 48 ms[id+"_state_code"] = int64(p.state) 49 ms[id+"_exit_status"] = int64(p.exitStatus) 50 ms[id+"_uptime"] = calcProcessUptime(p) 51 ms[id+"_downtime"] = calcProcessDowntime(p) 52 } 53 s.cleanupCache() 54 } 55 56 func (s *Supervisord) resetCache() { 57 for _, procs := range s.cache { 58 for name := range procs { 59 procs[name] = false 60 } 61 } 62 } 63 64 func (s *Supervisord) cleanupCache() { 65 for group, procs := range s.cache { 66 for name, ok := range procs { 67 if !ok { 68 s.removeProcessFromCharts(group, name) 69 delete(s.cache[group], name) 70 } 71 } 72 if len(s.cache[group]) == 0 { 73 s.removeProcessGroupCharts(group) 74 delete(s.cache, group) 75 } 76 } 77 } 78 79 func calcProcessUptime(p processStatus) int64 { 80 if !isProcRunning(p) { 81 return 0 82 } 83 return int64(p.now - p.start) 84 } 85 86 func calcProcessDowntime(p processStatus) int64 { 87 if isProcRunning(p) || p.stop == 0 { 88 return 0 89 } 90 return int64(p.now - p.stop) 91 } 92 93 func (s *Supervisord) addProcessGroupCharts(p processStatus) { 94 charts := newProcGroupCharts(p.group) 95 if err := s.Charts().Add(*charts...); err != nil { 96 s.Warning(err) 97 } 98 } 99 100 func (s *Supervisord) addProcessToCharts(p processStatus) { 101 id := procID(p) 102 for _, c := range *s.Charts() { 103 var dimID string 104 switch c.ID { 105 case fmt.Sprintf(groupProcessesStateCodeChartTmpl.ID, p.group): 106 dimID = id + "_state_code" 107 case fmt.Sprintf(groupProcessesExitStatusChartTmpl.ID, p.group): 108 dimID = id + "_exit_status" 109 case fmt.Sprintf(groupProcessesUptimeChartTmpl.ID, p.group): 110 dimID = id + "_uptime" 111 case fmt.Sprintf(groupProcessesDowntimeChartTmpl.ID, p.group): 112 dimID = id + "_downtime" 113 default: 114 continue 115 } 116 dim := &module.Dim{ID: dimID, Name: p.name} 117 if err := c.AddDim(dim); err != nil { 118 s.Warning(err) 119 return 120 } 121 c.MarkNotCreated() 122 } 123 } 124 125 func (s *Supervisord) removeProcessGroupCharts(group string) { 126 prefix := "group_" + group 127 for _, c := range *s.Charts() { 128 if strings.HasPrefix(c.ID, prefix) { 129 c.MarkRemove() 130 c.MarkNotCreated() 131 } 132 } 133 } 134 135 func (s *Supervisord) removeProcessFromCharts(group, name string) { 136 id := procID(processStatus{name: name, group: group}) 137 for _, c := range *s.Charts() { 138 var dimID string 139 switch c.ID { 140 case fmt.Sprintf(groupProcessesStateCodeChartTmpl.ID, group): 141 dimID = id + "_state_code" 142 case fmt.Sprintf(groupProcessesExitStatusChartTmpl.ID, group): 143 dimID = id + "_exit_status" 144 case fmt.Sprintf(groupProcessesUptimeChartTmpl.ID, group): 145 dimID = id + "_uptime" 146 case fmt.Sprintf(groupProcessesDowntimeChartTmpl.ID, group): 147 dimID = id + "_downtime" 148 default: 149 continue 150 } 151 if err := c.MarkDimRemove(dimID, true); err != nil { 152 s.Warning(err) 153 return 154 } 155 c.MarkNotCreated() 156 } 157 } 158 159 func procID(p processStatus) string { 160 return fmt.Sprintf("group_%s_process_%s", p.group, p.name) 161 } 162 163 func isProcRunning(p processStatus) bool { 164 // http://supervisord.org/subprocess.html#process-states 165 // STOPPED (0) 166 // STARTING (10) 167 // RUNNING (20) 168 // BACKOFF (30) 169 // STOPPING (40) 170 // EXITED (100) 171 // FATAL (200) 172 // UNKNOWN (1000) 173 return p.state == 20 174 }