| 1 | // SPDX-License-Identifier: GPL-3.0-or-later |
| 2 | |
| 3 | //go:build cgo |
| 4 | |
| 5 | package as400 |
| 6 | |
| 7 | import ( |
| 8 | "context" |
| 9 | "fmt" |
| 10 | "math" |
| 11 | "strings" |
| 12 | ) |
| 13 | |
| 14 | // collectActiveJobs collects metrics for explicitly configured active jobs |
| 15 | func (a *Collector) collectActiveJobs(ctx context.Context) error { |
| 16 | if len(a.activeJobTargets) == 0 { |
| 17 | return nil |
| 18 | } |
| 19 | if !a.CollectActiveJobs.IsEnabled() { |
| 20 | return nil |
| 21 | } |
| 22 | |
| 23 | var firstErr error |
| 24 | |
| 25 | for _, target := range a.activeJobTargets { |
| 26 | key := target.ID() |
| 27 | meta := a.getActiveJobMetrics(key) |
| 28 | meta.qualifiedName = key |
| 29 | meta.jobNumber = target.Number |
| 30 | meta.jobUser = target.User |
| 31 | meta.jobName = target.Name |
| 32 | |
| 33 | metrics := activeJobInstanceMetrics{} |
| 34 | found := false |
| 35 | |
| 36 | queryName := fmt.Sprintf("active_job_%s_%s_%s", target.Number, target.User, target.Name) |
| 37 | query := buildActiveJobQuery(target) |
| 38 | |
| 39 | err := a.doQuery(ctx, queryName, query, func(column, value string, lineEnd bool) { |
| 40 | switch column { |
| 41 | case "JOB_NAME": |
| 42 | qualified := strings.TrimSpace(value) |
| 43 | if qualified != "" { |
| 44 | meta.qualifiedName = qualified |
| 45 | } |
| 46 | case "JOB_USER": |
| 47 | user := strings.TrimSpace(value) |
| 48 | if user != "" { |
| 49 | meta.jobUser = strings.ToUpper(user) |
| 50 | } |
| 51 | case "JOB_NUMBER": |
| 52 | number := strings.TrimSpace(value) |
| 53 | if number != "" { |
| 54 | meta.jobNumber = number |
| 55 | } |
| 56 | case "JOB_STATUS": |
| 57 | meta.jobStatus = strings.TrimSpace(value) |
| 58 | case "SUBSYSTEM": |
| 59 | meta.subsystem = strings.TrimSpace(value) |
| 60 | case "JOB_TYPE": |
| 61 | meta.jobType = strings.TrimSpace(value) |
| 62 | case "ELAPSED_CPU_TIME": |
| 63 | if v, ok := a.parseInt64Value(value, 1); ok { |
| 64 | metrics.ElapsedCPUTime = v |
| 65 | } |
| 66 | case "ELAPSED_TIME": |
| 67 | if v, ok := a.parseInt64Value(value, 1); ok { |
| 68 | metrics.ElapsedTime = v |
| 69 | } |
| 70 | case "TEMPORARY_STORAGE": |
| 71 | if v, ok := a.parseInt64Value(value, 1); ok { |
| 72 | metrics.TemporaryStorage = v / 1024 // Convert KB to MB |
| 73 | } |
| 74 | case "CPU_PERCENTAGE": |
| 75 | if f, ok := a.parseFloat64Value(value); ok { |
| 76 | metrics.CPUPercentage = int64(math.Round(f * float64(precision))) |
| 77 | } |
| 78 | case "ELAPSED_INTERACTIVE_TRANSACTIONS": |
| 79 | if v, ok := a.parseInt64Value(value, 1); ok { |
| 80 | metrics.ElapsedInteractiveTransactions = v |
| 81 | } |
| 82 | case "ELAPSED_TOTAL_DISK_IO_COUNT": |
| 83 | if v, ok := a.parseInt64Value(value, 1); ok { |
| 84 | metrics.ElapsedDiskIO = v |
| 85 | } |
| 86 | case "THREAD_COUNT": |
| 87 | if v, ok := a.parseInt64Value(value, 1); ok { |
| 88 | metrics.ThreadCount = v |
| 89 | } |
| 90 | } |
| 91 | |
| 92 | if lineEnd { |
| 93 | found = true |
| 94 | } |
| 95 | }) |
| 96 | |
| 97 | if err != nil { |
| 98 | if firstErr == nil { |
| 99 | firstErr = fmt.Errorf("active job %s: %w", key, err) |
| 100 | } |
| 101 | continue |
| 102 | } |
| 103 | |
| 104 | if !found { |
| 105 | meta.jobStatus = "NOT FOUND" |
| 106 | meta.subsystem = "" |
| 107 | meta.jobType = "" |
| 108 | metrics = activeJobInstanceMetrics{} |
| 109 | } |
| 110 | |
| 111 | a.mx.activeJobs[key] = metrics |
| 112 | } |
| 113 | |
| 114 | return firstErr |
| 115 | } |