summaryrefslogtreecommitdiffstats
path: root/src/go/collectors/go.d.plugin/modules/supervisord/client.go
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--src/go/collectors/go.d.plugin/modules/supervisord/client.go109
1 files changed, 109 insertions, 0 deletions
diff --git a/src/go/collectors/go.d.plugin/modules/supervisord/client.go b/src/go/collectors/go.d.plugin/modules/supervisord/client.go
new file mode 100644
index 000000000..da62ca21c
--- /dev/null
+++ b/src/go/collectors/go.d.plugin/modules/supervisord/client.go
@@ -0,0 +1,109 @@
+// SPDX-License-Identifier: GPL-3.0-or-later
+
+package supervisord
+
+import (
+ "context"
+ "errors"
+ "fmt"
+ "net"
+ "net/http"
+ "net/url"
+ "strings"
+
+ "github.com/mattn/go-xmlrpc"
+)
+
+type supervisorRPCClient struct {
+ client *xmlrpc.Client
+}
+
+func newSupervisorRPCClient(serverURL *url.URL, httpClient *http.Client) (supervisorClient, error) {
+ switch serverURL.Scheme {
+ case "http", "https":
+ c := xmlrpc.NewClient(serverURL.String())
+ c.HttpClient = httpClient
+ return &supervisorRPCClient{client: c}, nil
+ case "unix":
+ c := xmlrpc.NewClient("http://unix/RPC2")
+ t, ok := httpClient.Transport.(*http.Transport)
+ if !ok {
+ return nil, errors.New("unexpected HTTP client transport")
+ }
+ t.DialContext = func(ctx context.Context, _, _ string) (net.Conn, error) {
+ d := net.Dialer{Timeout: httpClient.Timeout}
+ return d.DialContext(ctx, "unix", serverURL.Path)
+ }
+ c.HttpClient = httpClient
+ return &supervisorRPCClient{client: c}, nil
+ default:
+ return nil, fmt.Errorf("unexpected URL scheme: %s", serverURL)
+ }
+}
+
+// http://supervisord.org/api.html#process-control
+type processStatus struct {
+ name string // name of the process.
+ group string // name of the process’ group.
+ start int // UNIX timestamp of when the process was started.
+ stop int // UNIX timestamp of when the process last ended, or 0 if the process has never been stopped.
+ now int // UNIX timestamp of the current time, which can be used to calculate process up-time.
+ state int // state code.
+ stateName string // string description of state.
+ exitStatus int // exit status (errorlevel) of process, or 0 if the process is still running.
+}
+
+func (c *supervisorRPCClient) getAllProcessInfo() ([]processStatus, error) {
+ const fn = "supervisor.getAllProcessInfo"
+ resp, err := c.client.Call(fn)
+ if err != nil {
+ return nil, fmt.Errorf("error on '%s' function call: %v", fn, err)
+ }
+ return parseGetAllProcessInfo(resp)
+}
+
+func (c *supervisorRPCClient) closeIdleConnections() {
+ c.client.HttpClient.CloseIdleConnections()
+}
+
+func parseGetAllProcessInfo(resp interface{}) ([]processStatus, error) {
+ arr, ok := resp.(xmlrpc.Array)
+ if !ok {
+ return nil, fmt.Errorf("unexpected response type, want=xmlrpc.Array, got=%T", resp)
+ }
+
+ var info []processStatus
+
+ for _, item := range arr {
+ s, ok := item.(xmlrpc.Struct)
+ if !ok {
+ continue
+ }
+
+ var p processStatus
+ for k, v := range s {
+ switch strings.ToLower(k) {
+ case "name":
+ p.name, _ = v.(string)
+ case "group":
+ p.group, _ = v.(string)
+ case "start":
+ p.start, _ = v.(int)
+ case "stop":
+ p.stop, _ = v.(int)
+ case "now":
+ p.now, _ = v.(int)
+ case "state":
+ p.state, _ = v.(int)
+ case "statename":
+ p.stateName, _ = v.(string)
+ case "exitstatus":
+ p.exitStatus, _ = v.(int)
+ }
+ }
+ if p.name != "" && p.group != "" && p.stateName != "" {
+ info = append(info, p)
+ }
+ }
+ return info, nil
+}