363 lines
9.3 KiB
Go
363 lines
9.3 KiB
Go
package metrics
|
|
|
|
import (
|
|
"fmt"
|
|
"friendica-exporter/internal/client"
|
|
"friendica-exporter/serverinfo"
|
|
"github.com/prometheus/client_golang/prometheus"
|
|
"github.com/sirupsen/logrus"
|
|
)
|
|
|
|
const (
|
|
metricPrefix = "friendica_"
|
|
|
|
labelErrorCauseOther = "other"
|
|
labelErrorCauseAuth = "auth"
|
|
labelErrorCauseRateLimit = "ratelimit"
|
|
)
|
|
|
|
var (
|
|
updateAvailableDesc = prometheus.NewDesc(
|
|
metricPrefix+"update_available",
|
|
"Contains information whether a system update is available (0 = no, 1 = yes). The available_version level contains the latest available Friendica version, whereas the version level contains the current installed Friendica version.",
|
|
[]string{"version", "available_version"}, nil)
|
|
updateStatus = prometheus.NewDesc(
|
|
metricPrefix+"update_status",
|
|
"Contains information whether a system update was successful (1 = no, 0 = yes).",
|
|
nil, nil)
|
|
updateDatabaseStatus = prometheus.NewDesc(
|
|
metricPrefix+"update_db_status",
|
|
"Contains information whether a database update was successful (0 = no, 1 = yes).",
|
|
nil, nil)
|
|
cronLastExecution = prometheus.NewDesc(
|
|
metricPrefix+"cron_last_execution",
|
|
"Contains information about the last execution of cron of this Instance.",
|
|
[]string{"datetime"}, nil)
|
|
workerLastExecution = prometheus.NewDesc(
|
|
metricPrefix+"worker_last_execution",
|
|
"Contains information about the last execution of worker of this Instance.",
|
|
[]string{"datetime"}, nil)
|
|
workerJPM = prometheus.NewDesc(
|
|
metricPrefix+"worker_jpm",
|
|
"Number of jobs per Minute.",
|
|
[]string{"frequency"}, nil)
|
|
workerTasksTotal = prometheus.NewDesc(
|
|
metricPrefix+"worker_tasks_total",
|
|
"Number of worker tasks of this Instance.",
|
|
[]string{"level"}, nil)
|
|
workerTasksActive = prometheus.NewDesc(
|
|
metricPrefix+"worker_tasks_active",
|
|
"Number of active worker tasks of this Instance.",
|
|
[]string{"level"}, nil)
|
|
usersTotal = prometheus.NewDesc(
|
|
metricPrefix+"users_total",
|
|
"Number of total users of this Instance.",
|
|
nil, nil)
|
|
usersActiveWeek = prometheus.NewDesc(
|
|
metricPrefix+"users_active_week",
|
|
"Number of active users of the last week.",
|
|
nil, nil)
|
|
usersActiveMonth = prometheus.NewDesc(
|
|
metricPrefix+"users_active_month",
|
|
"Number of active users of the last month.",
|
|
nil, nil)
|
|
usersActiveHalfYear = prometheus.NewDesc(
|
|
metricPrefix+"users_active_half_year",
|
|
"Number of active users of the last half year.",
|
|
nil, nil)
|
|
usersPending = prometheus.NewDesc(
|
|
metricPrefix+"users_pending",
|
|
"Number of pending users.",
|
|
nil, nil)
|
|
)
|
|
|
|
type friendicaCollector struct {
|
|
log logrus.FieldLogger
|
|
infoClient client.InfoClient
|
|
|
|
upMetric prometheus.Gauge
|
|
scrapeErrorsMetric *prometheus.CounterVec
|
|
}
|
|
|
|
func RegisterCollector(log logrus.FieldLogger, infoClient client.InfoClient) error {
|
|
c := &friendicaCollector{
|
|
log: log,
|
|
infoClient: infoClient,
|
|
|
|
upMetric: prometheus.NewGauge(prometheus.GaugeOpts{
|
|
Name: metricPrefix + "up",
|
|
Help: "Indicates if the metrics could be scraped by the exporter.",
|
|
}),
|
|
scrapeErrorsMetric: prometheus.NewCounterVec(prometheus.CounterOpts{
|
|
Name: metricPrefix + "scrape_errors_total",
|
|
Help: "Counts the number of scrape errors by this collector.",
|
|
}, []string{"cause"}),
|
|
}
|
|
|
|
return prometheus.Register(c)
|
|
}
|
|
|
|
func (c *friendicaCollector) Describe(ch chan<- *prometheus.Desc) {
|
|
c.upMetric.Describe(ch)
|
|
c.scrapeErrorsMetric.Describe(ch)
|
|
ch <- updateAvailableDesc
|
|
ch <- updateStatus
|
|
ch <- updateDatabaseStatus
|
|
ch <- cronLastExecution
|
|
ch <- workerLastExecution
|
|
ch <- workerJPM
|
|
ch <- workerTasksTotal
|
|
ch <- workerTasksActive
|
|
ch <- usersTotal
|
|
ch <- usersActiveWeek
|
|
ch <- usersActiveMonth
|
|
ch <- usersActiveHalfYear
|
|
ch <- usersPending
|
|
}
|
|
|
|
func (c *friendicaCollector) Collect(ch chan<- prometheus.Metric) {
|
|
if err := c.collectFriendica(ch); err != nil {
|
|
c.log.Errorf("Error during scrape: %s", err)
|
|
|
|
cause := labelErrorCauseOther
|
|
if err == client.ErrNotAuthorized {
|
|
cause = labelErrorCauseAuth
|
|
} else if err == client.ErrRatelimit {
|
|
cause = labelErrorCauseRateLimit
|
|
}
|
|
c.scrapeErrorsMetric.WithLabelValues(cause).Inc()
|
|
c.upMetric.Set(0)
|
|
} else {
|
|
c.upMetric.Set(1)
|
|
}
|
|
|
|
c.upMetric.Collect(ch)
|
|
c.scrapeErrorsMetric.Collect(ch)
|
|
}
|
|
|
|
func (c *friendicaCollector) collectFriendica(ch chan<- prometheus.Metric) error {
|
|
status, err := c.infoClient()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
return readMetrics(ch, status)
|
|
}
|
|
|
|
func readMetrics(ch chan<- prometheus.Metric, status *serverinfo.ServerInfo) error {
|
|
if err := collectSimpleMetrics(ch, status); err != nil {
|
|
return err
|
|
}
|
|
|
|
if err := collectWorkerTotal(ch, status); err != nil {
|
|
return err
|
|
}
|
|
|
|
if err := collectJPM(ch, status); err != nil {
|
|
return err
|
|
}
|
|
|
|
if err := collectLastExecutions(ch, status); err != nil {
|
|
return err
|
|
}
|
|
|
|
if err := collectUpdate(ch, status); err != nil {
|
|
return err
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func collectUpdate(ch chan<- prometheus.Metric, status *serverinfo.ServerInfo) error {
|
|
updateInfo := status.Update
|
|
serverInfo := status.Server
|
|
updateAvailableValue := 0.0
|
|
|
|
// Fix small bug: its indicated as "true" even if there is no real update available.
|
|
if updateInfo.Available && serverInfo.Version != updateInfo.AvailableVersion {
|
|
updateAvailableValue = 1.0
|
|
}
|
|
|
|
metric, err := prometheus.NewConstMetric(updateAvailableDesc, prometheus.GaugeValue, updateAvailableValue, serverInfo.Version, updateInfo.AvailableVersion)
|
|
if err != nil {
|
|
return fmt.Errorf("error creating metric for %s: %w", updateAvailableDesc, err)
|
|
}
|
|
ch <- metric
|
|
|
|
return nil
|
|
}
|
|
|
|
type simpleMetric struct {
|
|
desc *prometheus.Desc
|
|
value float64
|
|
}
|
|
|
|
func collectSimpleMetrics(ch chan<- prometheus.Metric, status *serverinfo.ServerInfo) error {
|
|
metrics := []simpleMetric{
|
|
{
|
|
desc: updateStatus,
|
|
value: float64(status.Update.Status),
|
|
},
|
|
{
|
|
desc: updateDatabaseStatus,
|
|
value: float64(status.Update.DatabaseStatus),
|
|
},
|
|
{
|
|
desc: usersTotal,
|
|
value: float64(status.Users.Total),
|
|
},
|
|
{
|
|
desc: usersActiveWeek,
|
|
value: float64(status.Users.ActiveWeek),
|
|
},
|
|
{
|
|
desc: usersActiveMonth,
|
|
value: float64(status.Users.ActiveMonth),
|
|
},
|
|
{
|
|
desc: usersActiveHalfYear,
|
|
value: float64(status.Users.ActiveHalfYear),
|
|
},
|
|
{
|
|
desc: usersPending,
|
|
value: float64(status.Users.Pending),
|
|
},
|
|
}
|
|
|
|
for _, m := range metrics {
|
|
metric, err := prometheus.NewConstMetric(m.desc, prometheus.GaugeValue, m.value)
|
|
if err != nil {
|
|
return fmt.Errorf("error creating metric for %s: %w", m.desc, err)
|
|
}
|
|
ch <- metric
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
type workerMetric struct {
|
|
desc *prometheus.Desc
|
|
value float64
|
|
level string
|
|
}
|
|
|
|
func collectWorkerTotal(ch chan<- prometheus.Metric, status *serverinfo.ServerInfo) error {
|
|
metrics := []workerMetric{
|
|
{
|
|
desc: workerTasksActive,
|
|
value: float64(status.Worker.Active.Critical),
|
|
level: "critical",
|
|
},
|
|
{
|
|
desc: workerTasksActive,
|
|
value: float64(status.Worker.Active.High),
|
|
level: "high",
|
|
},
|
|
{
|
|
desc: workerTasksActive,
|
|
value: float64(status.Worker.Active.Medium),
|
|
level: "medium",
|
|
},
|
|
{
|
|
desc: workerTasksActive,
|
|
value: float64(status.Worker.Active.Low),
|
|
level: "low",
|
|
},
|
|
{
|
|
desc: workerTasksActive,
|
|
value: float64(status.Worker.Active.Negligible),
|
|
level: "negligible",
|
|
},
|
|
{
|
|
desc: workerTasksTotal,
|
|
value: float64(status.Worker.Total.Critical),
|
|
level: "critical",
|
|
},
|
|
{
|
|
desc: workerTasksTotal,
|
|
value: float64(status.Worker.Total.High),
|
|
level: "high",
|
|
},
|
|
{
|
|
desc: workerTasksTotal,
|
|
value: float64(status.Worker.Total.Medium),
|
|
level: "medium",
|
|
},
|
|
{
|
|
desc: workerTasksTotal,
|
|
value: float64(status.Worker.Total.Low),
|
|
level: "low",
|
|
},
|
|
{
|
|
desc: workerTasksTotal,
|
|
value: float64(status.Worker.Total.Negligible),
|
|
level: "negligible",
|
|
},
|
|
}
|
|
|
|
for _, m := range metrics {
|
|
metric, err := prometheus.NewConstMetric(m.desc, prometheus.GaugeValue, m.value, m.level)
|
|
if err != nil {
|
|
return fmt.Errorf("error creating metric for %s: %w", m.desc, err)
|
|
}
|
|
ch <- metric
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
type jpmMetric struct {
|
|
desc *prometheus.Desc
|
|
value float64
|
|
frequency string
|
|
}
|
|
|
|
func collectJPM(ch chan<- prometheus.Metric, status *serverinfo.ServerInfo) error {
|
|
metrics := []jpmMetric{
|
|
{
|
|
desc: workerJPM,
|
|
value: float64(status.Worker.JPM.OneMinute),
|
|
frequency: "1 minute",
|
|
},
|
|
{
|
|
desc: workerJPM,
|
|
value: float64(status.Worker.JPM.ThreeMinutes),
|
|
frequency: "3 minutes",
|
|
},
|
|
{
|
|
desc: workerJPM,
|
|
value: float64(status.Worker.JPM.FiveMinutes),
|
|
frequency: "5 minutes",
|
|
},
|
|
}
|
|
|
|
for _, m := range metrics {
|
|
metric, err := prometheus.NewConstMetric(m.desc, prometheus.GaugeValue, m.value, m.frequency)
|
|
if err != nil {
|
|
return fmt.Errorf("error creating metric for %s: %w", m.desc, err)
|
|
}
|
|
ch <- metric
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func collectLastExecutions(ch chan<- prometheus.Metric, status *serverinfo.ServerInfo) error {
|
|
workerInfo := status.Worker
|
|
|
|
metric, err := prometheus.NewConstMetric(workerLastExecution, prometheus.GaugeValue, float64(workerInfo.LastExecution.Timestamp), workerInfo.LastExecution.DateTime)
|
|
if err != nil {
|
|
return fmt.Errorf("error creating metric for %s: %w", workerLastExecution, err)
|
|
}
|
|
ch <- metric
|
|
|
|
cronInfo := status.Cron
|
|
|
|
metric, err = prometheus.NewConstMetric(cronLastExecution, prometheus.GaugeValue, float64(cronInfo.LastExecution.Timestamp), cronInfo.LastExecution.DateTime)
|
|
if err != nil {
|
|
return fmt.Errorf("error creating metric for %s: %w", cronLastExecution, err)
|
|
}
|
|
ch <- metric
|
|
|
|
return nil
|
|
}
|