Skip to content

Commit d7831b0

Browse files
committed
Merge pull request #129 from icholy/master
Add supervisord collector
2 parents 9810c57 + 9c03025 commit d7831b0

File tree

1 file changed

+134
-0
lines changed

1 file changed

+134
-0
lines changed

collector/supervisord.go

Lines changed: 134 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,134 @@
1+
// Copyright 2015 The Prometheus Authors
2+
// Licensed under the Apache License, Version 2.0 (the "License");
3+
// you may not use this file except in compliance with the License.
4+
// You may obtain a copy of the License at
5+
//
6+
// http://www.apache.org/licenses/LICENSE-2.0
7+
//
8+
// Unless required by applicable law or agreed to in writing, software
9+
// distributed under the License is distributed on an "AS IS" BASIS,
10+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11+
// See the License for the specific language governing permissions and
12+
// limitations under the License.
13+
14+
// +build !nosupervisord
15+
package collector
16+
17+
import (
18+
"flag"
19+
20+
"github.com/kolo/xmlrpc"
21+
"github.com/prometheus/client_golang/prometheus"
22+
"github.com/prometheus/log"
23+
)
24+
25+
var (
26+
supervisordURL = flag.String("collector.supervisord.url", "http://localhost:9001/RPC2", "XML RPC endpoint")
27+
)
28+
29+
type supervisordCollector struct {
30+
client *xmlrpc.Client
31+
upDesc *prometheus.Desc
32+
stateDesc *prometheus.Desc
33+
exitStatusDesc *prometheus.Desc
34+
uptimeDesc *prometheus.Desc
35+
}
36+
37+
func init() {
38+
Factories["supervisord"] = NewSupervisordCollector
39+
}
40+
41+
func NewSupervisordCollector() (Collector, error) {
42+
client, err := xmlrpc.NewClient(*supervisordURL, nil)
43+
if err != nil {
44+
return nil, err
45+
}
46+
47+
var (
48+
subsystem = "supervisord"
49+
labelNames = []string{"name", "group"}
50+
)
51+
return &supervisordCollector{
52+
client: client,
53+
upDesc: prometheus.NewDesc(
54+
prometheus.BuildFQName(Namespace, subsystem, "up"),
55+
"Process Up",
56+
labelNames,
57+
nil,
58+
),
59+
stateDesc: prometheus.NewDesc(
60+
prometheus.BuildFQName(Namespace, subsystem, "state"),
61+
"Process State",
62+
labelNames,
63+
nil,
64+
),
65+
exitStatusDesc: prometheus.NewDesc(
66+
prometheus.BuildFQName(Namespace, subsystem, "exit_status"),
67+
"Process Exit Status",
68+
labelNames,
69+
nil,
70+
),
71+
uptimeDesc: prometheus.NewDesc(
72+
prometheus.BuildFQName(Namespace, subsystem, "uptime"),
73+
"Process Uptime",
74+
labelNames,
75+
nil,
76+
),
77+
}, nil
78+
}
79+
80+
func (c *supervisordCollector) isRunning(state int) bool {
81+
// http://supervisord.org/subprocess.html#process-states
82+
const (
83+
STOPPED = 0
84+
STARTING = 10
85+
RUNNING = 20
86+
BACKOFF = 30
87+
STOPPING = 40
88+
EXITED = 100
89+
FATAL = 200
90+
UNKNOWN = 1000
91+
)
92+
switch state {
93+
case STARTING, RUNNING, STOPPING:
94+
return true
95+
}
96+
return false
97+
}
98+
99+
func (c *supervisordCollector) Update(ch chan<- prometheus.Metric) error {
100+
var infos []struct {
101+
Name string `xmlrpc:"name"`
102+
Group string `xmlrpc:"group"`
103+
Start int `xmlrpc:"start"`
104+
Stop int `xmlrpc:"stop"`
105+
Now int `xmlrpc:"now"`
106+
State int `xmlrpc:"state"`
107+
StateName string `xmlrpc:"statename"`
108+
SpawnErr string `xmlrpc:"spanerr"`
109+
ExitStatus int `xmlrpc:"exitstatus"`
110+
StdoutLogfile string `xmlrcp:"stdout_logfile"`
111+
StderrLogfile string `xmlrcp:"stderr_logfile"`
112+
PID int `xmlrpc:"pid"`
113+
}
114+
if err := c.client.Call("supervisor.getAllProcessInfo", nil, &infos); err != nil {
115+
return err
116+
}
117+
for _, info := range infos {
118+
lables := []string{info.Name, info.Group}
119+
120+
ch <- prometheus.MustNewConstMetric(c.stateDesc, prometheus.GaugeValue, float64(info.State), lables...)
121+
ch <- prometheus.MustNewConstMetric(c.exitStatusDesc, prometheus.GaugeValue, float64(info.ExitStatus), lables...)
122+
123+
if c.isRunning(info.State) {
124+
ch <- prometheus.MustNewConstMetric(c.upDesc, prometheus.GaugeValue, 1, lables...)
125+
ch <- prometheus.MustNewConstMetric(c.uptimeDesc, prometheus.CounterValue, float64(info.Now-info.Start), lables...)
126+
} else {
127+
ch <- prometheus.MustNewConstMetric(c.upDesc, prometheus.GaugeValue, 0, lables...)
128+
ch <- prometheus.MustNewConstMetric(c.uptimeDesc, prometheus.CounterValue, 0, lables...)
129+
}
130+
log.Debugf("%s:%s is %s on pid %d", info.Group, info.Name, info.StateName, info.PID)
131+
}
132+
133+
return nil
134+
}

0 commit comments

Comments
 (0)