From 7854a9eb9aba49682b1d09070a7008ee931e97f6 Mon Sep 17 00:00:00 2001 From: m0ar Date: Wed, 29 Sep 2021 13:57:46 +0200 Subject: [PATCH] Add CpuTime and Duration quantiles to available worker metrics --- README.md | 2 ++ cloudflare.go | 24 +++++++++++++++++++++++- main.go | 9 +++++---- prometheus.go | 30 ++++++++++++++++++++++++++++++ 4 files changed, 60 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 3d87a47..332a369 100644 --- a/README.md +++ b/README.md @@ -68,6 +68,8 @@ The original method of zone filtering by using env variables `ZONE_` is no ## List of available metrics ``` +# HELP cloudflare_worker_cpu_time CPU time quantiles by script name +# HELP cloudflare_worker_duration Duration quantiles by script name (GB*s) # HELP cloudflare_worker_errors_count Number of errors by script name # HELP cloudflare_worker_requests_count Number of requests sent to worker by script name # HELP cloudflare_zone_bandwidth_cached Cached bandwidth per zone in bytes diff --git a/cloudflare.go b/cloudflare.go index 1b556f9..0cb2819 100644 --- a/cloudflare.go +++ b/cloudflare.go @@ -4,7 +4,7 @@ import ( "context" "time" - cloudflare "github.com/cloudflare/cloudflare-go" + "github.com/cloudflare/cloudflare-go" "github.com/machinebox/graphql" log "github.com/sirupsen/logrus" ) @@ -43,6 +43,17 @@ type accountResp struct { Errors uint64 `json:"errors"` Duration float64 `json:"duration"` } `json:"sum"` + + Quantiles struct { + CpuTimeP50 float32 `json:"cpuTimeP50"` + CpuTimeP75 float32 `json:"cpuTimeP75"` + CpuTimeP99 float32 `json:"cpuTimeP99"` + CpuTimeP999 float32 `json:"cpuTimeP999"` + DurationP50 float32 `json:"durationP50"` + DurationP75 float32 `json:"durationP75"` + DurationP99 float32 `json:"durationP99"` + DurationP999 float32 `json:"durationP999"` + } `json:"quantiles"` } `json:"workersInvocationsAdaptive"` } @@ -402,6 +413,17 @@ func fetchWorkerTotals(accountID string) (*cloudflareResponseAccts, error) { errors duration } + + quantiles { + cpuTimeP50 + cpuTimeP75 + cpuTimeP99 + cpuTimeP999 + durationP50 + durationP75 + durationP99 + durationP999 + } } } } diff --git a/main.go b/main.go index 85c7783..565dbfd 100644 --- a/main.go +++ b/main.go @@ -7,7 +7,7 @@ import ( "sync" "time" - cloudflare "github.com/cloudflare/cloudflare-go" + "github.com/cloudflare/cloudflare-go" "github.com/namsral/flag" "github.com/nelkinda/health-go" "github.com/prometheus/client_golang/prometheus/promhttp" @@ -22,6 +22,7 @@ var ( cfgMetricsPath = "/metrics" cfgZones = "" cfgScrapeDelay = 300 + cfgFreeTier = false ) func getTargetZones() []string { @@ -30,7 +31,7 @@ func getTargetZones() []string { if len(cfgZones) > 0 { zoneIDs = strings.Split(cfgZones, ",") } else { - //depricated + // deprecated for _, e := range os.Environ() { if strings.HasPrefix(e, "ZONE_") { split := strings.SplitN(e, "=", 2) @@ -64,7 +65,6 @@ func fetchMetrics() { var wg sync.WaitGroup zones := fetchZones() accounts := fetchAccounts() - filteredZones := filterZones(zones, getTargetZones()) for _, a := range accounts { @@ -96,7 +96,8 @@ func main() { flag.StringVar(&cfgCfAPIEmail, "cf_api_email", cfgCfAPIEmail, "cloudflare api email, works with api_key flag") flag.StringVar(&cfgCfAPIToken, "cf_api_token", cfgCfAPIToken, "cloudflare api token (preferred)") flag.StringVar(&cfgZones, "cf_zones", cfgZones, "cloudflare zones to export, comma delimited list") - flag.IntVar(&cfgScrapeDelay, "scrape_delay", cfgScrapeDelay , "scrape delay in seconds, defaults to 300") + flag.IntVar(&cfgScrapeDelay, "scrape_delay", cfgScrapeDelay, "scrape delay in seconds, defaults to 300") + flag.BoolVar(&cfgFreeTier, "free_tier", cfgFreeTier, "scrape only metrics included in free plan") flag.Parse() if !(len(cfgCfAPIToken) > 0 || (len(cfgCfAPIEmail) > 0 && len(cfgCfAPIKey) > 0)) { log.Fatal("Please provide CF_API_KEY+CF_API_EMAIL or CF_API_TOKEN") diff --git a/prometheus.go b/prometheus.go index 69f396e..a836bf8 100644 --- a/prometheus.go +++ b/prometheus.go @@ -185,6 +185,18 @@ var ( Help: "Number of errors by script name", }, []string{"script_name"}, ) + + workerCpuTime = promauto.NewGaugeVec(prometheus.GaugeOpts{ + Name: "cloudflare_worker_cpu_time", + Help: "CPU time quantiles by script name", + }, []string{"script_name", "quantile"}, + ) + + workerDuration = promauto.NewGaugeVec(prometheus.GaugeOpts{ + Name: "cloudflare_worker_duration", + Help: "Duration quantiles by script name (GB*s)", + }, []string{"script_name", "quantile"}, + ) ) func fetchWorkerAnalytics(account cloudflare.Account, wg *sync.WaitGroup) { @@ -200,6 +212,14 @@ func fetchWorkerAnalytics(account cloudflare.Account, wg *sync.WaitGroup) { for _, w := range a.WorkersInvocationsAdaptive { workerRequests.With(prometheus.Labels{"script_name": w.Dimensions.ScriptName}).Add(float64(w.Sum.Requests)) workerErrors.With(prometheus.Labels{"script_name": w.Dimensions.ScriptName}).Add(float64(w.Sum.Errors)) + workerCpuTime.With(prometheus.Labels{"script_name": w.Dimensions.ScriptName, "quantile": "P50"}).Set(float64(w.Quantiles.CpuTimeP50)) + workerCpuTime.With(prometheus.Labels{"script_name": w.Dimensions.ScriptName, "quantile": "P75"}).Set(float64(w.Quantiles.CpuTimeP75)) + workerCpuTime.With(prometheus.Labels{"script_name": w.Dimensions.ScriptName, "quantile": "P99"}).Set(float64(w.Quantiles.CpuTimeP99)) + workerCpuTime.With(prometheus.Labels{"script_name": w.Dimensions.ScriptName, "quantile": "P999"}).Set(float64(w.Quantiles.CpuTimeP999)) + workerDuration.With(prometheus.Labels{"script_name": w.Dimensions.ScriptName, "quantile": "P50"}).Set(float64(w.Quantiles.DurationP50)) + workerDuration.With(prometheus.Labels{"script_name": w.Dimensions.ScriptName, "quantile": "P75"}).Set(float64(w.Quantiles.DurationP75)) + workerDuration.With(prometheus.Labels{"script_name": w.Dimensions.ScriptName, "quantile": "P99"}).Set(float64(w.Quantiles.DurationP99)) + workerDuration.With(prometheus.Labels{"script_name": w.Dimensions.ScriptName, "quantile": "P999"}).Set(float64(w.Quantiles.DurationP999)) } } } @@ -207,6 +227,11 @@ func fetchWorkerAnalytics(account cloudflare.Account, wg *sync.WaitGroup) { func fetchZoneColocationAnalytics(zones []cloudflare.Zone, wg *sync.WaitGroup) { wg.Add(1) defer wg.Done() + + // Colocation metrics are not available in non-enterprise zones + if cfgFreeTier { + return + } zoneIDs := extractZoneIDs(zones) r, err := fetchColoTotals(zoneIDs) @@ -229,6 +254,11 @@ func fetchZoneAnalytics(zones []cloudflare.Zone, wg *sync.WaitGroup) { wg.Add(1) defer wg.Done() + // None of the below referenced metrics are available in the free tier + if cfgFreeTier { + return + } + zoneIDs := extractZoneIDs(zones) r, err := fetchZoneTotals(zoneIDs)