From 0bf2b5a6ee1494cc889c91bad2a7ae01f760f0bc Mon Sep 17 00:00:00 2001 From: Pedro Pombeiro Date: Tue, 21 Nov 2023 19:51:57 +0100 Subject: [PATCH] feat: export job status counts (#10) --- src/immich/data.go | 42 ++++++++++++++++++++++++++++++------ src/models/api.go | 30 ++++++++++++++++++++++++++ src/prometheus/prometheus.go | 34 ++++++++++++++++++++++++++++- 3 files changed, 99 insertions(+), 7 deletions(-) diff --git a/src/immich/data.go b/src/immich/data.go index c5be7dd..61c5bdc 100644 --- a/src/immich/data.go +++ b/src/immich/data.go @@ -32,23 +32,30 @@ func Allrequests(r *prometheus.Registry) { func Analyze(r *prometheus.Registry) { defer wg.Done() + alljobsstatus := make(chan func() (*models.StructAllJobsStatus, error)) allusers := make(chan func() (*models.StructAllUsers, error)) serverinfo := make(chan func() (*models.StructServerInfo, error)) + defer func() { + close(serverinfo) + close(allusers) + close(alljobsstatus) + }() + wg.Add(1) + go GetAllJobsStatus(alljobsstatus) + res1, err := (<-alljobsstatus)() wg.Add(1) go GetAllUsers(allusers) - res1, err := (<-allusers)() + res2, err2 := (<-allusers)() wg.Add(1) go ServerInfo(serverinfo) - res2, err2 := (<-serverinfo)() + res3, err3 := (<-serverinfo)() - if err != nil && err2 != nil { + if err != nil && err2 != nil && err3 != nil { } else { - prom.SendBackMessagePreference(res2, res1, r) + prom.SendBackMessagePreference(res3, res2, res1, r) } - close(serverinfo) - close(allusers) } func GetAllUsers(c chan func() (*models.StructAllUsers, error)) { @@ -118,6 +125,29 @@ func ServerInfo(c chan func() (*models.StructServerInfo, error)) { } } +func GetAllJobsStatus(c chan func() (*models.StructAllJobsStatus, error)) { + defer wg.Done() + resp, err := Apirequest("/api/jobs", "GET") + if err == nil { + + if models.GetPromptError() == true { + models.SetPromptError(false) + } + body, err := ioutil.ReadAll(resp.Body) + if err != nil { + log.Fatalln(err) + } else { + + result := new(models.StructAllJobsStatus) + if err := json.Unmarshal(body, &result); err != nil { // Parse []byte to go struct pointer + log.Println(unmarshalError) + } + c <- (func() (*models.StructAllJobsStatus, error) { return result, nil }) + + } + } +} + func Apirequest(uri string, method string) (*http.Response, error) { req, err := http.NewRequest(method, models.Getbaseurl()+uri, nil) diff --git a/src/models/api.go b/src/models/api.go index edc8b11..03dc1da 100644 --- a/src/models/api.go +++ b/src/models/api.go @@ -58,3 +58,33 @@ type StructCustomUser struct { Name string IsAdmin bool } + +type StructJobStatus struct { + JobCounts struct { + Active int `json:"active"` + Completed int `json:"completed"` + Failed int `json:"failed"` + Delayed int `json:"delayed"` + Waiting int `json:"waiting"` + Paused int `json:"paused"` + } `json:"jobCounts"` + QueueStatus struct { + IsActive bool `json:"isActive"` + IsPaused bool `json:"isPaused"` + } `json:"queueStatus"` +} + +type StructAllJobsStatus struct { + ThumbnailGeneration StructJobStatus `json:"thumbnailGeneration"` + MetadataExtraction StructJobStatus `json:"metadataExtraction"` + VideoConversion StructJobStatus `json:"videoConversion"` + ObjectTagging StructJobStatus `json:"objectTagging"` + RecognizeFaces StructJobStatus `json:"recognizeFaces"` + ClipEncoding StructJobStatus `json:"clipEncoding"` + BackgroundTask StructJobStatus `json:"backgroundTask"` + StorageTemplateMigration StructJobStatus `json:"storageTemplateMigration"` + Migration StructJobStatus `json:"migration"` + Search StructJobStatus `json:"search"` + Sidecar StructJobStatus `json:"sidecar"` + Library StructJobStatus `json:"library"` +} diff --git a/src/prometheus/prometheus.go b/src/prometheus/prometheus.go index 0ffe08e..2b62a56 100644 --- a/src/prometheus/prometheus.go +++ b/src/prometheus/prometheus.go @@ -14,7 +14,12 @@ type Gauge []struct { value float64 } -func SendBackMessagePreference(result *models.StructServerInfo, result2 *models.StructAllUsers, r *prometheus.Registry) { +func SendBackMessagePreference( + result *models.StructServerInfo, + result2 *models.StructAllUsers, + result3 *models.StructAllJobsStatus, + r *prometheus.Registry, +) { gauges := Gauge{ {"total photos", "The total number of photos", float64((*result).Photos)}, @@ -43,10 +48,16 @@ func SendBackMessagePreference(result *models.StructServerInfo, result2 *models. Help: "The number of videos of the user", }, []string{"uid", "name"}) + job_count := prometheus.NewGaugeVec(prometheus.GaugeOpts{ + Name: "immich_job_count", + Help: "The item count in the job", + }, []string{"status", "job_name"}) + r.MustRegister(user_info) r.MustRegister(user_usage) r.MustRegister(user_videos) r.MustRegister(user_photos) + r.MustRegister(job_count) for i := 0; i < len((*result).UsageByUser); i++ { var myuser = GetName((*result).UsageByUser[i].UserID, result2) @@ -56,6 +67,27 @@ func SendBackMessagePreference(result *models.StructServerInfo, result2 *models. user_videos.With(prometheus.Labels{"uid": (*result).UsageByUser[i].UserID, "name": myuser.Name}).Set(float64((*result).UsageByUser[i].Videos)) } + setJobStatusCounts(job_count, "background_task", &result3.BackgroundTask) + setJobStatusCounts(job_count, "clip_encoding", &result3.ClipEncoding) + setJobStatusCounts(job_count, "library", &result3.Library) + setJobStatusCounts(job_count, "metadata_extraction", &result3.MetadataExtraction) + setJobStatusCounts(job_count, "migration", &result3.Migration) + setJobStatusCounts(job_count, "object_tagging", &result3.ObjectTagging) + setJobStatusCounts(job_count, "recognize_faces", &result3.RecognizeFaces) + setJobStatusCounts(job_count, "search", &result3.Search) + setJobStatusCounts(job_count, "sidecar", &result3.Sidecar) + setJobStatusCounts(job_count, "storage_template_migration", &result3.StorageTemplateMigration) + setJobStatusCounts(job_count, "thumbnail_generation", &result3.ThumbnailGeneration) + setJobStatusCounts(job_count, "video_conversion", &result3.VideoConversion) +} + +func setJobStatusCounts(job_count *prometheus.GaugeVec, jobName string, result *models.StructJobStatus) { + job_count.With(prometheus.Labels{"status": "active", "job_name": jobName}).Set(float64(result.JobCounts.Active)) + job_count.With(prometheus.Labels{"status": "completed", "job_name": jobName}).Set(float64(result.JobCounts.Completed)) + job_count.With(prometheus.Labels{"status": "failed", "job_name": jobName}).Set(float64(result.JobCounts.Failed)) + job_count.With(prometheus.Labels{"status": "delayed", "job_name": jobName}).Set(float64(result.JobCounts.Delayed)) + job_count.With(prometheus.Labels{"status": "waiting", "job_name": jobName}).Set(float64(result.JobCounts.Waiting)) + job_count.With(prometheus.Labels{"status": "paused", "job_name": jobName}).Set(float64(result.JobCounts.Paused)) } func SendBackMessageserverVersion(result *models.StructServerVersion, r *prometheus.Registry) {