Initial commit
This commit is contained in:
commit
35bce36222
15 changed files with 376 additions and 0 deletions
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
|
@ -0,0 +1 @@
|
||||||
|
app-exporter
|
14
Makefile
Normal file
14
Makefile
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
.PHONY: all build clean
|
||||||
|
|
||||||
|
PROJECT_NAME = $(shell head -n1 go.mod | cut -d'/' -f2)
|
||||||
|
|
||||||
|
|
||||||
|
all: build
|
||||||
|
|
||||||
|
# Build static executable
|
||||||
|
build:
|
||||||
|
CGO_ENABLED=0 go build
|
||||||
|
strip $(PROJECT_NAME)
|
||||||
|
|
||||||
|
clean:
|
||||||
|
rm $(PROJECT_NAME)
|
18
README.md
Normal file
18
README.md
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
# Prometheus Application Exporter
|
||||||
|
|
||||||
|
A Prometheus exporter to list application and their installed version.
|
||||||
|
|
||||||
|
This is mainly targeted at the Recycled Cloud hosted applications.
|
||||||
|
|
||||||
|
## Supported applications
|
||||||
|
|
||||||
|
- cloudpanel: TODO
|
||||||
|
- cubebackup
|
||||||
|
- forgejo
|
||||||
|
- forgejo_runner
|
||||||
|
- grafana
|
||||||
|
- nextcloud: `curl -s https://files.rccd:9000/status.php | jq .version -r`
|
||||||
|
- odoo
|
||||||
|
- odoo enterprise commit/date: TODO
|
||||||
|
- postgres
|
||||||
|
- vaultwarden
|
72
app_exporter.go
Normal file
72
app_exporter.go
Normal file
|
@ -0,0 +1,72 @@
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"flag"
|
||||||
|
"fmt"
|
||||||
|
"log"
|
||||||
|
"net/http"
|
||||||
|
"os"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/prometheus/client_golang/prometheus"
|
||||||
|
"github.com/prometheus/client_golang/prometheus/promhttp"
|
||||||
|
"recycled.cloud/app-exporter/apps"
|
||||||
|
)
|
||||||
|
|
||||||
|
const VERSION = "0.1.0"
|
||||||
|
|
||||||
|
const LISTEN_ADDR = ":9404"
|
||||||
|
const INTERVAL = 24 * time.Hour
|
||||||
|
|
||||||
|
var version_flag = flag.Bool("version", false, "Shows the program version")
|
||||||
|
var logfile = flag.String("logfile", "-", "Where to write the logs")
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
flag.Parse()
|
||||||
|
|
||||||
|
if *version_flag {
|
||||||
|
fmt.Printf("%v\n", VERSION)
|
||||||
|
os.Exit(0)
|
||||||
|
}
|
||||||
|
|
||||||
|
if *logfile != "-" {
|
||||||
|
f, err := os.OpenFile(*logfile, os.O_CREATE|os.O_RDWR|os.O_APPEND, 0664)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("Could not open logfile: %v\n", err)
|
||||||
|
}
|
||||||
|
defer f.Close()
|
||||||
|
log.SetOutput(f)
|
||||||
|
}
|
||||||
|
|
||||||
|
reg := prometheus.NewRegistry()
|
||||||
|
|
||||||
|
log.Printf("app-exporter version %v\n", VERSION)
|
||||||
|
|
||||||
|
m := apps.NewMetrics(reg)
|
||||||
|
|
||||||
|
go RecordMetrics(*m)
|
||||||
|
|
||||||
|
http.Handle("/metrics", promhttp.HandlerFor(reg, promhttp.HandlerOpts{Registry: reg}))
|
||||||
|
|
||||||
|
log.Printf("Listening on %v ...\n", LISTEN_ADDR)
|
||||||
|
|
||||||
|
log.Fatal(http.ListenAndServe(LISTEN_ADDR, nil))
|
||||||
|
}
|
||||||
|
|
||||||
|
func RecordMetrics(m apps.Metrics) {
|
||||||
|
for {
|
||||||
|
m.Reset()
|
||||||
|
|
||||||
|
apps.Cubebackup(m)
|
||||||
|
apps.Forgejo(m)
|
||||||
|
apps.ForgejoRunner(m)
|
||||||
|
apps.Grafana(m)
|
||||||
|
apps.Nextcloud(m)
|
||||||
|
apps.Odoo(m)
|
||||||
|
apps.Postgres(m)
|
||||||
|
apps.Vaultwarden(m)
|
||||||
|
|
||||||
|
log.Printf("> Waiting %v\n", INTERVAL)
|
||||||
|
time.Sleep(INTERVAL)
|
||||||
|
}
|
||||||
|
}
|
21
apps/cubebackup.go
Normal file
21
apps/cubebackup.go
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
package apps
|
||||||
|
|
||||||
|
import (
|
||||||
|
"log"
|
||||||
|
"os/exec"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/prometheus/client_golang/prometheus"
|
||||||
|
)
|
||||||
|
|
||||||
|
func Cubebackup(m Metrics) {
|
||||||
|
out, err := exec.Command("/opt/cubebackup365/bin/cbackup", "version").Output()
|
||||||
|
if err != nil {
|
||||||
|
log.Printf(">> WARN: Unable to get Cubebackup version: %v", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
version := strings.Split(string(out), " ")[1]
|
||||||
|
|
||||||
|
m.Cubebackup.With(prometheus.Labels{"version": version}).Set(1)
|
||||||
|
}
|
21
apps/forgejo.go
Normal file
21
apps/forgejo.go
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
package apps
|
||||||
|
|
||||||
|
import (
|
||||||
|
"log"
|
||||||
|
"os/exec"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/prometheus/client_golang/prometheus"
|
||||||
|
)
|
||||||
|
|
||||||
|
func Forgejo(m Metrics) {
|
||||||
|
out, err := exec.Command("forgejo", "--version").Output()
|
||||||
|
if err != nil {
|
||||||
|
log.Printf(">> WARN: Unable to get Forgejo version: %v", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
version := strings.Split(string(out), " ")[2]
|
||||||
|
|
||||||
|
m.Forgejo.With(prometheus.Labels{"version": version}).Set(1)
|
||||||
|
}
|
21
apps/forgejo_runner.go
Normal file
21
apps/forgejo_runner.go
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
package apps
|
||||||
|
|
||||||
|
import (
|
||||||
|
"log"
|
||||||
|
"os/exec"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/prometheus/client_golang/prometheus"
|
||||||
|
)
|
||||||
|
|
||||||
|
func ForgejoRunner(m Metrics) {
|
||||||
|
out, err := exec.Command("forgejo_runner", "--version").Output()
|
||||||
|
if err != nil {
|
||||||
|
log.Printf(">> WARN: Unable to get Forgejo_runner version: %v", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
version := strings.Split(string(out), " ")[2]
|
||||||
|
|
||||||
|
m.ForgejoRunner.With(prometheus.Labels{"version": version}).Set(1)
|
||||||
|
}
|
21
apps/grafana.go
Normal file
21
apps/grafana.go
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
package apps
|
||||||
|
|
||||||
|
import (
|
||||||
|
"log"
|
||||||
|
"os/exec"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/prometheus/client_golang/prometheus"
|
||||||
|
)
|
||||||
|
|
||||||
|
func Grafana(m Metrics) {
|
||||||
|
out, err := exec.Command("grafana-cli", "--version").Output()
|
||||||
|
if err != nil {
|
||||||
|
log.Printf(">> WARN: Unable to get Grafana version: %v", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
version := strings.Split(string(out), " ")[2]
|
||||||
|
|
||||||
|
m.Grafana.With(prometheus.Labels{"version": version}).Set(1)
|
||||||
|
}
|
56
apps/metrics.go
Normal file
56
apps/metrics.go
Normal file
|
@ -0,0 +1,56 @@
|
||||||
|
package apps
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/prometheus/client_golang/prometheus"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Metrics struct {
|
||||||
|
Cubebackup prometheus.GaugeVec
|
||||||
|
Forgejo prometheus.GaugeVec
|
||||||
|
ForgejoRunner prometheus.GaugeVec
|
||||||
|
Grafana prometheus.GaugeVec
|
||||||
|
Nextcloud prometheus.GaugeVec
|
||||||
|
Odoo prometheus.GaugeVec
|
||||||
|
Postgres prometheus.GaugeVec
|
||||||
|
Vaultwarden prometheus.GaugeVec
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewMetrics(reg prometheus.Registerer) *Metrics {
|
||||||
|
metrics := &Metrics{
|
||||||
|
Cubebackup: *prometheus.NewGaugeVec(prometheus.GaugeOpts{Namespace: "app", Subsystem: "version", Name: "cubebackup", Help: ""}, []string{"version"}),
|
||||||
|
Forgejo: *prometheus.NewGaugeVec(prometheus.GaugeOpts{Namespace: "app", Subsystem: "version", Name: "forgejo", Help: ""}, []string{"version"}),
|
||||||
|
ForgejoRunner: *prometheus.NewGaugeVec(prometheus.GaugeOpts{Namespace: "app", Subsystem: "version", Name: "forgejo_runner", Help: ""}, []string{"version"}),
|
||||||
|
Grafana: *prometheus.NewGaugeVec(prometheus.GaugeOpts{Namespace: "app", Subsystem: "version", Name: "grafana", Help: ""}, []string{"version"}),
|
||||||
|
Nextcloud: *prometheus.NewGaugeVec(prometheus.GaugeOpts{Namespace: "app", Subsystem: "version", Name: "nextcloud", Help: ""}, []string{"version"}),
|
||||||
|
Odoo: *prometheus.NewGaugeVec(prometheus.GaugeOpts{Namespace: "app", Subsystem: "version", Name: "odoo", Help: ""}, []string{"version", "version_date"}),
|
||||||
|
Postgres: *prometheus.NewGaugeVec(prometheus.GaugeOpts{Namespace: "app", Subsystem: "version", Name: "postgres", Help: ""}, []string{"version"}),
|
||||||
|
Vaultwarden: *prometheus.NewGaugeVec(prometheus.GaugeOpts{Namespace: "app", Subsystem: "version", Name: "vaultwarden", Help: ""}, []string{"version"}),
|
||||||
|
}
|
||||||
|
|
||||||
|
reg.MustRegister(
|
||||||
|
metrics.Cubebackup,
|
||||||
|
metrics.Forgejo,
|
||||||
|
metrics.ForgejoRunner,
|
||||||
|
metrics.Grafana,
|
||||||
|
metrics.Nextcloud,
|
||||||
|
metrics.Odoo,
|
||||||
|
metrics.Postgres,
|
||||||
|
metrics.Vaultwarden,
|
||||||
|
)
|
||||||
|
|
||||||
|
return metrics
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reset all metrics
|
||||||
|
//
|
||||||
|
// This should be called on every loop iteration.
|
||||||
|
func (m *Metrics) Reset() {
|
||||||
|
m.Cubebackup.Reset()
|
||||||
|
m.Forgejo.Reset()
|
||||||
|
m.ForgejoRunner.Reset()
|
||||||
|
m.Grafana.Reset()
|
||||||
|
m.Nextcloud.Reset()
|
||||||
|
m.Odoo.Reset()
|
||||||
|
m.Postgres.Reset()
|
||||||
|
m.Vaultwarden.Reset()
|
||||||
|
}
|
25
apps/nextcloud.go
Normal file
25
apps/nextcloud.go
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
package apps
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"net/http"
|
||||||
|
|
||||||
|
"github.com/prometheus/client_golang/prometheus"
|
||||||
|
)
|
||||||
|
|
||||||
|
type apiResponse struct {
|
||||||
|
version string
|
||||||
|
}
|
||||||
|
|
||||||
|
func Nextcloud(m Metrics) {
|
||||||
|
var resp, err = http.Get("http://localhost:9000/status.php")
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
defer resp.Body.Close()
|
||||||
|
|
||||||
|
var res = apiResponse{}
|
||||||
|
json.NewDecoder(resp.Body).Decode(&res)
|
||||||
|
|
||||||
|
m.Nextcloud.With(prometheus.Labels{"version": res.version}).Set(1)
|
||||||
|
}
|
23
apps/odoo.go
Normal file
23
apps/odoo.go
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
package apps
|
||||||
|
|
||||||
|
import (
|
||||||
|
"log"
|
||||||
|
"os/exec"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/prometheus/client_golang/prometheus"
|
||||||
|
)
|
||||||
|
|
||||||
|
func Odoo(m Metrics) {
|
||||||
|
out, err := exec.Command("odoo", "--version").Output()
|
||||||
|
if err != nil {
|
||||||
|
log.Printf(">> WARN: Unable to get Odoo version: %v", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
full_version := strings.Split(string(out), " ")[2]
|
||||||
|
version := strings.Split(full_version, "-")[0]
|
||||||
|
version_date := strings.TrimSpace(strings.Split(full_version, "-")[1])
|
||||||
|
|
||||||
|
m.Odoo.With(prometheus.Labels{"version": version, "version_date": version_date}).Set(1)
|
||||||
|
}
|
21
apps/postgres.go
Normal file
21
apps/postgres.go
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
package apps
|
||||||
|
|
||||||
|
import (
|
||||||
|
"log"
|
||||||
|
"os/exec"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/prometheus/client_golang/prometheus"
|
||||||
|
)
|
||||||
|
|
||||||
|
func Postgres(m Metrics) {
|
||||||
|
out, err := exec.Command("psql", "--version").Output()
|
||||||
|
if err != nil {
|
||||||
|
log.Printf(">> WARN: Unable to get Postgres version: %v", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
version := strings.Split(string(out), " ")[2]
|
||||||
|
|
||||||
|
m.Postgres.With(prometheus.Labels{"version": version}).Set(1)
|
||||||
|
}
|
21
apps/vaultwarden.go
Normal file
21
apps/vaultwarden.go
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
package apps
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"net/http"
|
||||||
|
|
||||||
|
"github.com/prometheus/client_golang/prometheus"
|
||||||
|
)
|
||||||
|
|
||||||
|
func Vaultwarden(m Metrics) {
|
||||||
|
var resp, err = http.Get("http://localhost:8080/api/version")
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
defer resp.Body.Close()
|
||||||
|
|
||||||
|
var version = new(string)
|
||||||
|
json.NewDecoder(resp.Body).Decode(version)
|
||||||
|
|
||||||
|
m.Vaultwarden.With(prometheus.Labels{"version": *version}).Set(1)
|
||||||
|
}
|
17
go.mod
Normal file
17
go.mod
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
module recycled.cloud/app-exporter
|
||||||
|
|
||||||
|
go 1.23.2
|
||||||
|
|
||||||
|
require github.com/prometheus/client_golang v1.20.5
|
||||||
|
|
||||||
|
require (
|
||||||
|
github.com/beorn7/perks v1.0.1 // indirect
|
||||||
|
github.com/cespare/xxhash/v2 v2.3.0 // indirect
|
||||||
|
github.com/klauspost/compress v1.17.9 // indirect
|
||||||
|
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
|
||||||
|
github.com/prometheus/client_model v0.6.1 // indirect
|
||||||
|
github.com/prometheus/common v0.55.0 // indirect
|
||||||
|
github.com/prometheus/procfs v0.15.1 // indirect
|
||||||
|
golang.org/x/sys v0.22.0 // indirect
|
||||||
|
google.golang.org/protobuf v1.34.2 // indirect
|
||||||
|
)
|
24
go.sum
Normal file
24
go.sum
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
|
||||||
|
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
|
||||||
|
github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs=
|
||||||
|
github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
||||||
|
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
|
||||||
|
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
||||||
|
github.com/klauspost/compress v1.17.9 h1:6KIumPrER1LHsvBVuDa0r5xaG0Es51mhhB9BQB2qeMA=
|
||||||
|
github.com/klauspost/compress v1.17.9/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw=
|
||||||
|
github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc=
|
||||||
|
github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw=
|
||||||
|
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA=
|
||||||
|
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
|
||||||
|
github.com/prometheus/client_golang v1.20.5 h1:cxppBPuYhUnsO6yo/aoRol4L7q7UFfdm+bR9r+8l63Y=
|
||||||
|
github.com/prometheus/client_golang v1.20.5/go.mod h1:PIEt8X02hGcP8JWbeHyeZ53Y/jReSnHgO035n//V5WE=
|
||||||
|
github.com/prometheus/client_model v0.6.1 h1:ZKSh/rekM+n3CeS952MLRAdFwIKqeY8b62p8ais2e9E=
|
||||||
|
github.com/prometheus/client_model v0.6.1/go.mod h1:OrxVMOVHjw3lKMa8+x6HeMGkHMQyHDk9E3jmP2AmGiY=
|
||||||
|
github.com/prometheus/common v0.55.0 h1:KEi6DK7lXW/m7Ig5i47x0vRzuBsHuvJdi5ee6Y3G1dc=
|
||||||
|
github.com/prometheus/common v0.55.0/go.mod h1:2SECS4xJG1kd8XF9IcM1gMX6510RAEL65zxzNImwdc8=
|
||||||
|
github.com/prometheus/procfs v0.15.1 h1:YagwOFzUgYfKKHX6Dr+sHT7km/hxC76UB0learggepc=
|
||||||
|
github.com/prometheus/procfs v0.15.1/go.mod h1:fB45yRUv8NstnjriLhBQLuOUt+WW4BsoGhij/e3PBqk=
|
||||||
|
golang.org/x/sys v0.22.0 h1:RI27ohtqKCnwULzJLqkv897zojh5/DwS/ENaMzUOaWI=
|
||||||
|
golang.org/x/sys v0.22.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||||
|
google.golang.org/protobuf v1.34.2 h1:6xV6lTsCfpGD21XK49h7MhtcApnLqkfYgPcdHftf6hg=
|
||||||
|
google.golang.org/protobuf v1.34.2/go.mod h1:qYOHts0dSfpeUzUFpOMr/WGzszTmLH+DiWniOlNbLDw=
|
Loading…
Reference in a new issue