Skip to content

Commit f3a7639

Browse files
committed
Add 5-minute HTTP request stats grouped by origin IP
1 parent c88169a commit f3a7639

3 files changed

Lines changed: 149 additions & 0 deletions

File tree

cloudflare.go

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -217,7 +217,17 @@ type zoneResp struct {
217217
OriginResponseStatus uint16 `json:"originResponseStatus"`
218218
ClientCountryName string `json:"clientCountryName"`
219219
ClientRequestHTTPHost string `json:"clientRequestHTTPHost"`
220+
OriginIP string `json:"originIP"`
220221
} `json:"dimensions"`
222+
Quantiles struct {
223+
EdgeTimeToFirstByteMsP50 int `json:"edgeTimeToFirstByteMsP50"`
224+
EdgeTimeToFirstByteMsP95 int `json:"edgeTimeToFirstByteMsP95"`
225+
EdgeTimeToFirstByteMsP99 int `json:"edgeTimeToFirstByteMsP99"`
226+
} `json:"quantiles"`
227+
Ratio struct {
228+
Status5xx float64 `json:"status5xx"`
229+
Status4xx float64 `json:"status4xx"`
230+
} `json:"ratio"`
221231
} `json:"httpRequestsAdaptiveGroups"`
222232

223233
HTTPRequestsEdgeCountryHost []struct {
@@ -484,6 +494,52 @@ func fetchAccounts() []cfaccounts.Account {
484494
return cfAccounts
485495
}
486496

497+
func fetchZone5mStats(zoneIDs []string) (*cloudflareResponse, error) {
498+
request := graphql.NewRequest(`
499+
query ($zoneIDs: [String!], $mintime: Time!, $maxtime: Time!, $limit: Int!) {
500+
viewer {
501+
zones(filter: { zoneTag_in: $zoneIDs }) {
502+
zoneTag
503+
httpRequestsAdaptiveGroups(filter:{datetime_gt: $start, datetime_lt: $end}, limit: $limit) {
504+
dimensions {
505+
originIP
506+
}
507+
ratio {
508+
status4xx
509+
status5xx
510+
}
511+
quantiles {
512+
edgeTimeToFirstByteMsP50
513+
edgeTimeToFirstByteMsP95
514+
edgeTimeToFirstByteMsP99
515+
}
516+
count
517+
}
518+
}
519+
}
520+
`)
521+
522+
now, _ := GetTimeRange()
523+
request.Var("limit", gqlQueryLimit)
524+
request.Var("maxtime", now)
525+
request.Var("mintime", now.Add(-5*time.Minute))
526+
request.Var("zoneIDs", zoneIDs)
527+
528+
gql.Mu.RLock()
529+
defer gql.Mu.RUnlock()
530+
531+
ctx, cancel := context.WithTimeout(context.Background(), cftimeout)
532+
defer cancel()
533+
534+
var resp cloudflareResponse
535+
if err := gql.Client.Run(ctx, request, &resp); err != nil {
536+
log.Errorf("failed to fetch zone 5-minute totals, err:%v", err)
537+
return nil, err
538+
}
539+
540+
return &resp, nil
541+
}
542+
487543
func fetchZoneTotals(zoneIDs []string) (*cloudflareResponse, error) {
488544
request := graphql.NewRequest(`
489545
query ($zoneIDs: [String!], $mintime: Time!, $maxtime: Time!, $limit: Int!) {

main.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -128,6 +128,7 @@ func fetchMetrics(deniedMetricsSet MetricsSet) {
128128
zoneCount := len(filteredZones)
129129
if zoneCount > 0 && zoneCount <= cfgraphqlreqlimit {
130130
go fetchZoneAnalytics(filteredZones, &wg, deniedMetricsSet)
131+
go fetchZoneAdaptiveHTTPStats(filteredZones, &wg, deniedMetricsSet)
131132
go fetchZoneColocationAnalytics(filteredZones, &wg, deniedMetricsSet)
132133
go fetchLoadBalancerAnalytics(filteredZones, &wg, deniedMetricsSet)
133134
go fetchLogpushAnalyticsForZone(filteredZones, &wg, deniedMetricsSet)
@@ -138,6 +139,7 @@ func fetchMetrics(deniedMetricsSet MetricsSet) {
138139
e = zoneCount
139140
}
140141
go fetchZoneAnalytics(filteredZones[s:e], &wg, deniedMetricsSet)
142+
go fetchZoneAdaptiveHTTPStats(filteredZones[s:e], &wg, deniedMetricsSet)
141143
go fetchZoneColocationAnalytics(filteredZones[s:e], &wg, deniedMetricsSet)
142144
go fetchLoadBalancerAnalytics(filteredZones[s:e], &wg, deniedMetricsSet)
143145
go fetchLogpushAnalyticsForZone(filteredZones[s:e], &wg, deniedMetricsSet)

prometheus.go

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,8 @@ const (
2626
zoneRequestContentTypeMetricName MetricName = "cloudflare_zone_requests_content_type"
2727
zoneRequestCountryMetricName MetricName = "cloudflare_zone_requests_country"
2828
zoneRequestHTTPStatusMetricName MetricName = "cloudflare_zone_requests_status"
29+
zoneRequestStatus5mRatioMetricName MetricName = "cloudflare_zone_requests_status_5m_ratio"
30+
zoneRequestEdgeTTFB5mQuantilesMetricName MetricName = "cloudflare_zone_requests_edge_ttfb_5m_quantiles"
2931
zoneRequestBrowserMapMetricName MetricName = "cloudflare_zone_requests_browser_map_page_views_count"
3032
zoneRequestOriginStatusCountryHostMetricName MetricName = "cloudflare_zone_requests_origin_status_country_host"
3133
zoneRequestStatusCountryHostMetricName MetricName = "cloudflare_zone_requests_status_country_host"
@@ -112,6 +114,18 @@ var (
112114
}, []string{"zone", "account", "status"},
113115
)
114116

117+
zoneRequestStatus5mRatio = prometheus.NewGaugeVec(prometheus.GaugeOpts{
118+
Name: zoneRequestStatus5mRatioMetricName.String(),
119+
Help: "Ratio of 4xx and 5xx responses over the past 5 minutes",
120+
}, []string{"zone", "account", "origin_ip", "status_group"},
121+
)
122+
123+
zoneRequestEdgeTTFB5mQuantiles = prometheus.NewGaugeVec(prometheus.GaugeOpts{
124+
Name: zoneRequestEdgeTTFB5mQuantilesMetricName.String(),
125+
Help: "Time to first byte (TTFB) quantiles over the past 5 minutes",
126+
}, []string{"zone", "account", "origin_ip", "quantile"},
127+
)
128+
115129
zoneRequestBrowserMap = prometheus.NewCounterVec(prometheus.CounterOpts{
116130
Name: zoneRequestBrowserMapMetricName.String(),
117131
Help: "Number of successful requests for HTML pages per zone",
@@ -330,6 +344,8 @@ func buildAllMetricsSet() MetricsSet {
330344
allMetricsSet.Add(zoneRequestContentTypeMetricName)
331345
allMetricsSet.Add(zoneRequestCountryMetricName)
332346
allMetricsSet.Add(zoneRequestHTTPStatusMetricName)
347+
allMetricsSet.Add(zoneRequestStatus5mRatioMetricName)
348+
allMetricsSet.Add(zoneRequestEdgeTTFB5mQuantilesMetricName)
333349
allMetricsSet.Add(zoneRequestBrowserMapMetricName)
334350
allMetricsSet.Add(zoneRequestOriginStatusCountryHostMetricName)
335351
allMetricsSet.Add(zoneRequestStatusCountryHostMetricName)
@@ -399,6 +415,12 @@ func mustRegisterMetrics(deniedMetrics MetricsSet) {
399415
if !deniedMetrics.Has(zoneRequestHTTPStatusMetricName) {
400416
prometheus.MustRegister(zoneRequestHTTPStatus)
401417
}
418+
if !deniedMetrics.Has(zoneRequestStatus5mRatioMetricName) {
419+
prometheus.MustRegister(zoneRequestStatus5mRatio)
420+
}
421+
if !deniedMetrics.Has(zoneRequestEdgeTTFB5mQuantilesMetricName) {
422+
prometheus.MustRegister(zoneRequestEdgeTTFB5mQuantiles)
423+
}
402424
if !deniedMetrics.Has(zoneRequestBrowserMapMetricName) {
403425
prometheus.MustRegister(zoneRequestBrowserMap)
404426
}
@@ -706,6 +728,75 @@ func fetchZoneColocationAnalytics(zones []cfzones.Zone, wg *sync.WaitGroup, deni
706728
}
707729
}
708730

731+
func fetchZoneAdaptiveHTTPStats(zones []cfzones.Zone, wg *sync.WaitGroup, deniedMetricsSet MetricsSet) {
732+
wg.Add(1)
733+
defer wg.Done()
734+
735+
if deniedMetricsSet.Has(zoneRequestStatus5mRatioMetricName) && deniedMetricsSet.Has(zoneRequestEdgeTTFB5mQuantilesMetricName) {
736+
return
737+
}
738+
739+
zoneIDs := extractZoneIDs(zones)
740+
if len(zoneIDs) == 0 {
741+
return
742+
}
743+
744+
r, err := fetchZone5mStats(zoneIDs)
745+
if err != nil {
746+
log.Error("failed to fetch analyzed zone 5-minute stats: ", err)
747+
return
748+
}
749+
750+
for _, z := range r.Viewer.Zones {
751+
name, account := findZoneAccountName(zones, z.ZoneTag)
752+
753+
if !deniedMetricsSet.Has(zoneRequestStatus5mRatioMetricName) {
754+
for _, g := range z.HTTPRequestsAdaptiveGroups {
755+
zoneRequestStatus5mRatio.With(
756+
prometheus.Labels{
757+
"zone": name,
758+
"account": account,
759+
"origin_ip": g.Dimensions.OriginIP,
760+
"status_group": "4xx",
761+
}).Add(float64(g.Ratio.Status4xx))
762+
zoneRequestStatus5mRatio.With(
763+
prometheus.Labels{
764+
"zone": name,
765+
"account": account,
766+
"origin_ip": g.Dimensions.OriginIP,
767+
"status_group": "5xx",
768+
}).Add(float64(g.Ratio.Status5xx))
769+
}
770+
}
771+
772+
if !deniedMetricsSet.Has(zoneRequestEdgeTTFB5mQuantilesMetricName) {
773+
for _, g := range z.HTTPRequestsAdaptiveGroups {
774+
zoneRequestEdgeTTFB5mQuantiles.With(
775+
prometheus.Labels{
776+
"zone": name,
777+
"account": account,
778+
"origin_ip": g.Dimensions.OriginIP,
779+
"quantile": "P50",
780+
}).Set(float64(g.Quantiles.EdgeTimeToFirstByteMsP50))
781+
zoneRequestEdgeTTFB5mQuantiles.With(
782+
prometheus.Labels{
783+
"zone": name,
784+
"account": account,
785+
"origin_ip": g.Dimensions.OriginIP,
786+
"quantile": "P95",
787+
}).Set(float64(g.Quantiles.EdgeTimeToFirstByteMsP95))
788+
zoneRequestEdgeTTFB5mQuantiles.With(
789+
prometheus.Labels{
790+
"zone": name,
791+
"account": account,
792+
"origin_ip": g.Dimensions.OriginIP,
793+
"quantile": "P99",
794+
}).Set(float64(g.Quantiles.EdgeTimeToFirstByteMsP99))
795+
}
796+
}
797+
}
798+
}
799+
709800
func fetchZoneAnalytics(zones []cfzones.Zone, wg *sync.WaitGroup, deniedMetricsSet MetricsSet) {
710801
wg.Add(1)
711802
defer wg.Done()

0 commit comments

Comments
 (0)