1 package reaper
2
3 import (
4 "context"
5 "os"
6
7 "github.com/cybertec-postgresql/pgwatch/v3/internal/metrics"
8 )
9
10 func DoesEmergencyTriggerfileExist(fname string) bool {
11
12
13
14
15 if fname == "" {
16 return false
17 }
18 _, err := os.Stat(fname)
19 return err == nil
20 }
21
22 const (
23 metricCPULoad = "cpu_load"
24 metricPsutilCPU = "psutil_cpu"
25 metricPsutilDisk = "psutil_disk"
26 metricPsutilDiskIoTotal = "psutil_disk_io_total"
27 metricPsutilMem = "psutil_mem"
28 )
29
30 const (
31 sqlPgDirs = `select
32 current_setting('data_directory') as dd,
33 current_setting('log_directory') as ld,
34 current_setting('server_version_num')::int as pgver`
35 sqlTsDirs = `select
36 spcname::text as name,
37 pg_catalog.pg_tablespace_location(oid) as location
38 from pg_catalog.pg_tablespace
39 where not spcname like any(array[E'pg\\_%'])`
40 )
41
42 var directlyFetchableOSMetrics = map[string]bool{metricPsutilCPU: true, metricPsutilDisk: true, metricPsutilDiskIoTotal: true, metricPsutilMem: true, metricCPULoad: true}
43
44 func IsDirectlyFetchableMetric(metric string) bool {
45 _, ok := directlyFetchableOSMetrics[metric]
46 return ok
47 }
48
49 func FetchStatsDirectlyFromOS(ctx context.Context, msg MetricFetchConfig, vme MonitoredDatabaseSettings, mvp metrics.Metric) (*metrics.MeasurementEnvelope, error) {
50 var data, dataDirs, dataTblspDirs metrics.Measurements
51 var err error
52
53 switch msg.MetricName {
54 case metricCPULoad:
55 data, err = GetLoadAvgLocal()
56 case metricPsutilCPU:
57 data, err = GetGoPsutilCPU(msg.Interval)
58 case metricPsutilDisk:
59 if dataDirs, err = QueryMeasurements(ctx, msg.DBUniqueName, sqlPgDirs); err != nil {
60 return nil, err
61 }
62 if dataTblspDirs, err = QueryMeasurements(ctx, msg.DBUniqueName, sqlTsDirs); err != nil {
63 return nil, err
64 }
65 data, err = GetGoPsutilDiskPG(dataDirs, dataTblspDirs)
66 case metricPsutilDiskIoTotal:
67 data, err = GetGoPsutilDiskTotals()
68 case metricPsutilMem:
69 data, err = GetGoPsutilMem()
70 }
71 if err != nil {
72 return nil, err
73 }
74
75 msm, err := DataRowsToMeasurementEnvelope(data, msg, vme, mvp)
76 if err != nil {
77 return nil, err
78 }
79 return &msm, nil
80 }
81
82
83 func DataRowsToMeasurementEnvelope(data metrics.Measurements, msg MetricFetchConfig, vme MonitoredDatabaseSettings, mvp metrics.Metric) (metrics.MeasurementEnvelope, error) {
84 md, err := GetMonitoredDatabaseByUniqueName(msg.DBUniqueName)
85 if err != nil {
86 return metrics.MeasurementEnvelope{}, err
87 }
88 return metrics.MeasurementEnvelope{
89 DBName: msg.DBUniqueName,
90 SourceType: string(msg.Source),
91 MetricName: msg.MetricName,
92 CustomTags: md.CustomTags,
93 Data: data,
94 MetricDef: mvp,
95 RealDbname: vme.RealDbname,
96 SystemIdentifier: vme.SystemIdentifier,
97 }, nil
98 }
99