Track total count of episodes with cutoff unmet in Sonarr (#375)

* Add sonarr_episode_cutoff_unmet_total metric

* Fix sonarr test fixture by adding missing json file

* Add radarr_movie_cutoff_unmet_total metric

* Remove compiled file

* Fix expected_metrics.txt for radarr using wrong HELP string

* Add missing end-of-line to test ficture JSON files

* Fix redeclare of CutoffUnmet type

* Fix EOL for radarr model

* Fix test fixture data for sonarr and radarr to match expectations
This commit is contained in:
ShawnHardwick 2025-08-12 00:14:47 -04:00 committed by GitHub
parent 1c6341f0b1
commit 367f6031df
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
10 changed files with 67 additions and 1 deletions

View File

@ -19,6 +19,7 @@ type radarrCollector struct {
movieUnmonitoredMetric *prometheus.Desc // Total number of unmonitored movies
movieWantedMetric *prometheus.Desc // Total number of wanted movies
movieMissingMetric *prometheus.Desc // Total number of missing movies
movieCutoffUnmetMetric *prometheus.Desc // Total number of movies with cutoff unmet
movieQualitiesMetric *prometheus.Desc // Total number of movies by quality
movieFileSizeMetric *prometheus.Desc // Total fizesize of all movies in bytes
errorMetric *prometheus.Desc // Error Description for use with InvalidMetric
@ -70,6 +71,12 @@ func NewRadarrCollector(c *config.ArrConfig) *radarrCollector {
nil,
prometheus.Labels{"url": c.URL},
),
movieCutoffUnmetMetric: prometheus.NewDesc(
"radarr_movie_cutoff_unmet_total",
"Total number of movies with cutoff unmet",
nil,
prometheus.Labels{"url": c.URL},
),
movieFileSizeMetric: prometheus.NewDesc(
"radarr_movie_filesize_total",
"Total filesize of all movies",
@ -105,6 +112,7 @@ func (collector *radarrCollector) Describe(ch chan<- *prometheus.Desc) {
ch <- collector.movieUnmonitoredMetric
ch <- collector.movieWantedMetric
ch <- collector.movieMissingMetric
ch <- collector.movieCutoffUnmetMetric
ch <- collector.movieFileSizeMetric
ch <- collector.movieQualitiesMetric
ch <- collector.movieTagsMetric
@ -202,6 +210,17 @@ func (collector *radarrCollector) Collect(ch chan<- prometheus.Metric) {
}
}
moviesCutoffUnmet := model.CutoffUnmetMovies{}
moviesCutoffUnmetParams := client.QueryParams{}
params.Add("sortKey", "airDateUtc")
if err := c.DoRequest("wanted/cutoff", &moviesCutoffUnmet, moviesCutoffUnmetParams); err != nil {
log.Errorw("Error getting cutoff unmet",
"error", err)
ch <- prometheus.NewInvalidMetric(collector.errorMetric, err)
return
}
ch <- prometheus.MustNewConstMetric(collector.movieEdition, prometheus.GaugeValue, float64(editions))
ch <- prometheus.MustNewConstMetric(collector.movieMetric, prometheus.GaugeValue, float64(len(movies)))
ch <- prometheus.MustNewConstMetric(collector.movieDownloadedMetric, prometheus.GaugeValue, float64(downloaded))
@ -209,6 +228,7 @@ func (collector *radarrCollector) Collect(ch chan<- prometheus.Metric) {
ch <- prometheus.MustNewConstMetric(collector.movieUnmonitoredMetric, prometheus.GaugeValue, float64(unmonitored))
ch <- prometheus.MustNewConstMetric(collector.movieWantedMetric, prometheus.GaugeValue, float64(wanted))
ch <- prometheus.MustNewConstMetric(collector.movieMissingMetric, prometheus.GaugeValue, float64(missing))
ch <- prometheus.MustNewConstMetric(collector.movieCutoffUnmetMetric, prometheus.GaugeValue, float64(moviesCutoffUnmet.TotalRecords))
ch <- prometheus.MustNewConstMetric(collector.movieFileSizeMetric, prometheus.GaugeValue, float64(fileSize))
if len(qualities) > 0 {

View File

@ -28,6 +28,7 @@ type sonarrCollector struct {
episodeUnmonitoredMetric *prometheus.Desc // Total number of unmonitored episodes
episodeDownloadedMetric *prometheus.Desc // Total number of downloaded episodes
episodeMissingMetric *prometheus.Desc // Total number of missing episodes
episodeCutoffUnmetMetric *prometheus.Desc // Total number of episodes with cutoff unmet
episodeQualitiesMetric *prometheus.Desc // Total number of episodes by quality
errorMetric *prometheus.Desc // Error Description for use with InvalidMetric
}
@ -119,6 +120,12 @@ func NewSonarrCollector(conf *config.ArrConfig) *sonarrCollector {
nil,
prometheus.Labels{"url": conf.URL},
),
episodeCutoffUnmetMetric: prometheus.NewDesc(
"sonarr_episode_cutoff_unmet_total",
"Total number of episodes with cutoff unmet",
nil,
prometheus.Labels{"url": conf.URL},
),
episodeQualitiesMetric: prometheus.NewDesc(
"sonarr_episode_quality_total",
"Total number of downloaded episodes by quality",
@ -149,6 +156,7 @@ func (collector *sonarrCollector) Describe(ch chan<- *prometheus.Desc) {
ch <- collector.episodeUnmonitoredMetric
ch <- collector.episodeDownloadedMetric
ch <- collector.episodeMissingMetric
ch <- collector.episodeCutoffUnmetMetric
ch <- collector.episodeQualitiesMetric
}
@ -287,6 +295,16 @@ func (collector *sonarrCollector) Collect(ch chan<- prometheus.Metric) {
return
}
episodesCutoffUnmet := model.CutoffUnmet{}
// Cutoff unmet endpoint uses the same params as missing
if err := c.DoRequest("wanted/cutoff", &episodesCutoffUnmet, params); err != nil {
log.Errorw("Error getting cutoff unmet",
"error", err)
ch <- prometheus.NewInvalidMetric(collector.errorMetric, err)
return
}
ch <- prometheus.MustNewConstMetric(collector.seriesMetric, prometheus.GaugeValue, float64(len(series)))
ch <- prometheus.MustNewConstMetric(collector.seriesDownloadedMetric, prometheus.GaugeValue, float64(seriesDownloaded))
ch <- prometheus.MustNewConstMetric(collector.seriesMonitoredMetric, prometheus.GaugeValue, float64(seriesMonitored))
@ -299,6 +317,7 @@ func (collector *sonarrCollector) Collect(ch chan<- prometheus.Metric) {
ch <- prometheus.MustNewConstMetric(collector.episodeMetric, prometheus.GaugeValue, float64(episodes))
ch <- prometheus.MustNewConstMetric(collector.episodeDownloadedMetric, prometheus.GaugeValue, float64(episodesDownloaded))
ch <- prometheus.MustNewConstMetric(collector.episodeMissingMetric, prometheus.GaugeValue, float64(episodesMissing.TotalRecords))
ch <- prometheus.MustNewConstMetric(collector.episodeCutoffUnmetMetric, prometheus.GaugeValue, float64(episodesCutoffUnmet.TotalRecords))
if collector.config.EnableAdditionalMetrics {
ch <- prometheus.MustNewConstMetric(collector.episodeMonitoredMetric, prometheus.GaugeValue, float64(episodesMonitored))

View File

@ -23,3 +23,9 @@ type TagMovies []struct {
Label string `json:"label"`
MovieIds []int `json:"movieIds"`
}
// CutoffUnmetMovies - Stores struct of JSON response
// https://radarr.video/docs/api/#/Cutoff/get_api_v3_wanted_cutoff
type CutoffUnmetMovies struct {
TotalRecords int `json:"totalRecords"`
}

View File

@ -42,6 +42,12 @@ type Missing struct {
TotalRecords int `json:"totalRecords"`
}
// CutoffUnmet - Stores struct of JSON response
// https://sonarr.tv/docs/api/#/Cutoff/get_api_v3_wanted_cutoff
type CutoffUnmet struct {
TotalRecords int `json:"totalRecords"`
}
// EpisodeFile - Stores struct of JSON response
// https://github.com/Sonarr/Sonarr/wiki/EpisodeFile
type EpisodeFile []struct {

View File

@ -10,6 +10,9 @@ radarr_movie_filesize_total{url="SOMEURL"} 1.47062956689e+11
# HELP radarr_movie_missing_total Total number of missing movies
# TYPE radarr_movie_missing_total gauge
radarr_movie_missing_total{url="SOMEURL"} 2
# HELP radarr_movie_cutoff_unmet_total Total number of movies with cutoff unmet
# TYPE radarr_movie_cutoff_unmet_total gauge
radarr_movie_cutoff_unmet_total{url="SOMEURL"} 1179
# HELP radarr_movie_monitored_total Total number of monitored movies
# TYPE radarr_movie_monitored_total gauge
radarr_movie_monitored_total{url="SOMEURL"} 7

View File

@ -0,0 +1,3 @@
{
"totalRecords": 1179
}

View File

@ -4,6 +4,9 @@ sonarr_episode_downloaded_total{url="SOMEURL"} 285
# HELP sonarr_episode_missing_total Total number of missing episodes
# TYPE sonarr_episode_missing_total gauge
sonarr_episode_missing_total{url="SOMEURL"} 1179
# HELP sonarr_episode_cutoff_unmet_total Total number of episodes with cutoff unmet
# TYPE sonarr_episode_cutoff_unmet_total gauge
sonarr_episode_cutoff_unmet_total{url="SOMEURL"} 1179
# HELP sonarr_episode_total Total number of episodes
# TYPE sonarr_episode_total gauge
sonarr_episode_total{url="SOMEURL"} 675

View File

@ -4,6 +4,9 @@ sonarr_episode_downloaded_total{url="SOMEURL"} 285
# HELP sonarr_episode_missing_total Total number of missing episodes
# TYPE sonarr_episode_missing_total gauge
sonarr_episode_missing_total{url="SOMEURL"} 1179
# HELP sonarr_episode_cutoff_unmet_total Total number of episodes with cutoff unmet
# TYPE sonarr_episode_cutoff_unmet_total gauge
sonarr_episode_cutoff_unmet_total{url="SOMEURL"} 1179
# HELP sonarr_episode_monitored_total Total number of monitored episodes
# TYPE sonarr_episode_monitored_total gauge
sonarr_episode_monitored_total{url="SOMEURL"} 12

View File

@ -0,0 +1,3 @@
{
"totalRecords": 1179
}

View File

@ -1,3 +1,3 @@
{
"totalRecords": 1179
}
}