diff --git a/README.md b/README.md index b4173f1..772b488 100644 --- a/README.md +++ b/README.md @@ -12,6 +12,16 @@ go install github.com/systemli/prometheus-etherpad-exporter $GOPATH/bin/prometheus-etherpad-exporter ``` +### Commandline options + +``` +-web.listen-address ":9011" # Address on which to expose metrics and web interface. +-etherpad.url "http://localhost:9001" # URL to connect with Etherpad +-etherpad.api-token "" # "API Token for Etherpad" +``` + +With configured API Token the metrics `etherpad_total_pads`, `etherpad_total_sessions` and `etherpad_total_active_pads` will appended to the metrics + ### Docker ``` @@ -21,6 +31,15 @@ docker run -p 9011:9011 systemli/prometheus-etherpad-exporter:latest -etherpad.u ## Metrics ``` +# HELP etherpad_total_pads +# TYPE etherpad_total_pads gauge +etherpad_total_pads 8 +# HELP etherpad_total_sessions +# TYPE etherpad_total_sessions gauge +etherpad_total_sessions 0 +# HELP etherpad_total_active_pads +# TYPE etherpad_total_active_pads gauge +etherpad_total_active_pads 0 # HELP etherpad_memory_usage # TYPE etherpad_memory_usage gauge etherpad_memory_usage{type="total"} 102801408 diff --git a/go.mod b/go.mod index 3324e42..8be1b95 100644 --- a/go.mod +++ b/go.mod @@ -2,4 +2,8 @@ module github.com/systemli/prometheus-etherpad-exporter go 1.16 -require github.com/google/go-cmp v0.5.5 // indirect +require ( + github.com/google/go-cmp v0.5.5 // indirect + github.com/sirupsen/logrus v1.8.1 // indirect + golang.org/x/sys v0.0.0-20210320140829-1e4c9ba3b0c4 // indirect +) diff --git a/go.sum b/go.sum index 40edc1d..2a4fe1b 100644 --- a/go.sum +++ b/go.sum @@ -1,3 +1,12 @@ +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/sirupsen/logrus v1.8.1 h1:dJKuHgqk1NNQlqoA6BTlM1Wf9DOH3NBjQyu0h9+AZZE= +github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= +github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +golang.org/x/sys v0.0.0-20191026070338-33540a1f6037 h1:YyJpGZS1sBuBCzLAR1VEpK193GlqGZbnPFnPV/5Rsb4= +golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210320140829-1e4c9ba3b0c4 h1:EZ2mChiOa8udjfp6rRmswTbtZN/QzUQp4ptM4rnjHvc= +golang.org/x/sys v0.0.0-20210320140829-1e4c9ba3b0c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= diff --git a/main.go b/main.go index ca068df..c56d912 100644 --- a/main.go +++ b/main.go @@ -3,14 +3,18 @@ package main import ( "encoding/json" "flag" - "log" + "fmt" "net/http" + "os" "text/template" + + log "github.com/sirupsen/logrus" ) var ( - addr = flag.String("web.listen-address", ":9011", "Address on which to expose metrics and web interface.") - etherpadURL = flag.String("etherpad.url", "http://localhost:9001", "URL to connect with Etherpad") + addr = flag.String("web.listen-address", ":9011", "Address on which to expose metrics and web interface.") + etherpadURL = flag.String("etherpad.url", "http://localhost:9001", "URL to connect with Etherpad") + etherpadAPIToken = flag.String("etherpad.api-token", "", "API Token for Etherpad") ) type etherpadStats struct { @@ -24,6 +28,16 @@ type etherpadStats struct { Edits edits `json:"edits"` } +type etherpadAPIStats struct { + Code int `json:"code"` + Message string `json:"message"` + Data struct { + TotalPads int `json:"totalPads"` + TotalSessions int `json:"totalSessions"` + TotalActivePads int `json:"totalActivePads"` + } `json:"data"` +} + type httpRequests struct { Meter meter `json:"meter"` Histogram histogram `json:"histogram"` @@ -58,7 +72,7 @@ type histogram struct { P999 float64 `json:"p999"` } -var tpl = template.Must(template.New("stats").Parse(`# HELP etherpad_memory_usage +var statsTpl = template.Must(template.New("stats").Parse(`# HELP etherpad_memory_usage # TYPE etherpad_memory_usage gauge etherpad_memory_usage{type="total"} {{.MemoryUsage}} etherpad_memory_usage{type="heap"} {{.MemoryUsageHeap}} @@ -79,43 +93,76 @@ etherpad_connects {{.Connects.Count}} etherpad_connects {{.Edits.Meter.Count}} `)) +var apiStatsTpl = template.Must(template.New("apiStats").Parse(`# HELP etherpad_total_pads +# TYPE etherpad_total_pads gauge +etherpad_total_pads {{.Data.TotalPads}} +# HELP etherpad_total_sessions +# TYPE etherpad_total_sessions gauge +etherpad_total_sessions {{.Data.TotalSessions}} +# HELP etherpad_total_active_pads +# TYPE etherpad_total_active_pads gauge +etherpad_total_active_pads {{.Data.TotalActivePads}} +`)) + type handler struct { - etherpadURL string + etherpadURL string + etherpadAPIToken string } func (h handler) ServeHTTP(w http.ResponseWriter, req *http.Request) { - resp, err := http.Get(h.etherpadURL + "/stats") + res, err := http.Get(h.etherpadURL + "/stats") if err != nil { - log.Printf("scrape error: %v", err) + log.WithError(err).Error("error while fetching /stats from etherpad") http.Error(w, err.Error(), http.StatusInternalServerError) return } - defer resp.Body.Close() + defer res.Body.Close() var stats etherpadStats - if err := json.NewDecoder(resp.Body).Decode(&stats); err != nil { - log.Printf("json decoding error: %v", err) + if err := json.NewDecoder(res.Body).Decode(&stats); err != nil { + log.WithError(err).Error("error while decoding json") http.Error(w, err.Error(), http.StatusInternalServerError) return } + if h.etherpadAPIToken != "" { + res, err := http.Get(h.etherpadURL + fmt.Sprintf("/api/1.2.14/getStats?apikey=%s", h.etherpadAPIToken)) + if err != nil { + log.WithError(err).Error("error while fetching /getStats from etherpad api") + } + defer res.Body.Close() + + var apiStats etherpadAPIStats + if err := json.NewDecoder(res.Body).Decode(&apiStats); err != nil { + log.WithError(err).Error("error while decoding json") + } + + err = apiStatsTpl.Execute(w, &apiStats) + if err != nil { + log.WithError(err).Error("error while executing template for apiStats") + } + } + w.Header().Set("Content-Type", "text/plain") - err = tpl.Execute(w, &stats) + err = statsTpl.Execute(w, &stats) if err != nil { - log.Printf("template error: %v", err) + log.WithError(err).Error("error while executing template for stats") http.Error(w, err.Error(), http.StatusInternalServerError) return } } +func init() { + log.SetFormatter(&log.JSONFormatter{}) + log.SetOutput(os.Stdout) +} + func main() { - log.SetFlags(0) flag.Parse() - http.Handle("/metrics", handler{etherpadURL: *etherpadURL}) + log.Info("Started Etherpad Metrics Exporter") + http.Handle("/metrics", handler{etherpadURL: *etherpadURL, etherpadAPIToken: *etherpadAPIToken}) if err := http.ListenAndServe(*addr, nil); err != nil { - log.Fatal(err) + log.WithError(err).Error("error while try to start exporter") } - - log.Println("Started Etherpad Metrics Exporter") }