Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
56 changes: 56 additions & 0 deletions cloudflare.go
Original file line number Diff line number Diff line change
Expand Up @@ -217,7 +217,17 @@ type zoneResp struct {
OriginResponseStatus uint16 `json:"originResponseStatus"`
ClientCountryName string `json:"clientCountryName"`
ClientRequestHTTPHost string `json:"clientRequestHTTPHost"`
OriginIP string `json:"originIP"`
} `json:"dimensions"`
Quantiles struct {
EdgeTimeToFirstByteMsP50 int `json:"edgeTimeToFirstByteMsP50"`
EdgeTimeToFirstByteMsP95 int `json:"edgeTimeToFirstByteMsP95"`
EdgeTimeToFirstByteMsP99 int `json:"edgeTimeToFirstByteMsP99"`
} `json:"quantiles"`
Ratio struct {
Status5xx float64 `json:"status5xx"`
Status4xx float64 `json:"status4xx"`
} `json:"ratio"`
} `json:"httpRequestsAdaptiveGroups"`

HTTPRequestsEdgeCountryHost []struct {
Expand Down Expand Up @@ -484,6 +494,52 @@ func fetchAccounts() []cfaccounts.Account {
return cfAccounts
}

func fetchZone5mStats(zoneIDs []string) (*cloudflareResponse, error) {
request := graphql.NewRequest(`
query ($zoneIDs: [String!], $mintime: Time!, $maxtime: Time!, $limit: Int!) {
viewer {
zones(filter: { zoneTag_in: $zoneIDs }) {
zoneTag
httpRequestsAdaptiveGroups(filter:{datetime_gt: $start, datetime_lt: $end}, limit: $limit) {
dimensions {
originIP
}
ratio {
status4xx
status5xx
}
quantiles {
edgeTimeToFirstByteMsP50
edgeTimeToFirstByteMsP95
edgeTimeToFirstByteMsP99
}
count
}
}
}
`)

now, _ := GetTimeRange()
request.Var("limit", gqlQueryLimit)
request.Var("maxtime", now)
request.Var("mintime", now.Add(-5*time.Minute))
request.Var("zoneIDs", zoneIDs)

gql.Mu.RLock()
defer gql.Mu.RUnlock()

ctx, cancel := context.WithTimeout(context.Background(), cftimeout)
defer cancel()

var resp cloudflareResponse
if err := gql.Client.Run(ctx, request, &resp); err != nil {
log.Errorf("failed to fetch zone 5-minute totals, err:%v", err)
return nil, err
}

return &resp, nil
}

func fetchZoneTotals(zoneIDs []string) (*cloudflareResponse, error) {
request := graphql.NewRequest(`
query ($zoneIDs: [String!], $mintime: Time!, $maxtime: Time!, $limit: Int!) {
Expand Down
2 changes: 2 additions & 0 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,7 @@ func fetchMetrics(deniedMetricsSet MetricsSet) {
zoneCount := len(filteredZones)
if zoneCount > 0 && zoneCount <= cfgraphqlreqlimit {
go fetchZoneAnalytics(filteredZones, &wg, deniedMetricsSet)
go fetchZoneAdaptiveHTTPStats(filteredZones, &wg, deniedMetricsSet)
go fetchZoneColocationAnalytics(filteredZones, &wg, deniedMetricsSet)
go fetchLoadBalancerAnalytics(filteredZones, &wg, deniedMetricsSet)
go fetchLogpushAnalyticsForZone(filteredZones, &wg, deniedMetricsSet)
Expand All @@ -138,6 +139,7 @@ func fetchMetrics(deniedMetricsSet MetricsSet) {
e = zoneCount
}
go fetchZoneAnalytics(filteredZones[s:e], &wg, deniedMetricsSet)
go fetchZoneAdaptiveHTTPStats(filteredZones[s:e], &wg, deniedMetricsSet)
go fetchZoneColocationAnalytics(filteredZones[s:e], &wg, deniedMetricsSet)
go fetchLoadBalancerAnalytics(filteredZones[s:e], &wg, deniedMetricsSet)
go fetchLogpushAnalyticsForZone(filteredZones[s:e], &wg, deniedMetricsSet)
Expand Down
91 changes: 91 additions & 0 deletions prometheus.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@ const (
zoneRequestContentTypeMetricName MetricName = "cloudflare_zone_requests_content_type"
zoneRequestCountryMetricName MetricName = "cloudflare_zone_requests_country"
zoneRequestHTTPStatusMetricName MetricName = "cloudflare_zone_requests_status"
zoneRequestStatus5mRatioMetricName MetricName = "cloudflare_zone_requests_status_5m_ratio"
zoneRequestEdgeTTFB5mQuantilesMetricName MetricName = "cloudflare_zone_requests_edge_ttfb_5m_quantiles"
zoneRequestBrowserMapMetricName MetricName = "cloudflare_zone_requests_browser_map_page_views_count"
zoneRequestOriginStatusCountryHostMetricName MetricName = "cloudflare_zone_requests_origin_status_country_host"
zoneRequestStatusCountryHostMetricName MetricName = "cloudflare_zone_requests_status_country_host"
Expand Down Expand Up @@ -112,6 +114,18 @@ var (
}, []string{"zone", "account", "status"},
)

zoneRequestStatus5mRatio = prometheus.NewGaugeVec(prometheus.GaugeOpts{
Name: zoneRequestStatus5mRatioMetricName.String(),
Help: "Ratio of 4xx and 5xx responses over the past 5 minutes",
}, []string{"zone", "account", "origin_ip", "status_group"},
)

zoneRequestEdgeTTFB5mQuantiles = prometheus.NewGaugeVec(prometheus.GaugeOpts{
Name: zoneRequestEdgeTTFB5mQuantilesMetricName.String(),
Help: "Time to first byte (TTFB) quantiles over the past 5 minutes",
}, []string{"zone", "account", "origin_ip", "quantile"},
)

zoneRequestBrowserMap = prometheus.NewCounterVec(prometheus.CounterOpts{
Name: zoneRequestBrowserMapMetricName.String(),
Help: "Number of successful requests for HTML pages per zone",
Expand Down Expand Up @@ -330,6 +344,8 @@ func buildAllMetricsSet() MetricsSet {
allMetricsSet.Add(zoneRequestContentTypeMetricName)
allMetricsSet.Add(zoneRequestCountryMetricName)
allMetricsSet.Add(zoneRequestHTTPStatusMetricName)
allMetricsSet.Add(zoneRequestStatus5mRatioMetricName)
allMetricsSet.Add(zoneRequestEdgeTTFB5mQuantilesMetricName)
allMetricsSet.Add(zoneRequestBrowserMapMetricName)
allMetricsSet.Add(zoneRequestOriginStatusCountryHostMetricName)
allMetricsSet.Add(zoneRequestStatusCountryHostMetricName)
Expand Down Expand Up @@ -399,6 +415,12 @@ func mustRegisterMetrics(deniedMetrics MetricsSet) {
if !deniedMetrics.Has(zoneRequestHTTPStatusMetricName) {
prometheus.MustRegister(zoneRequestHTTPStatus)
}
if !deniedMetrics.Has(zoneRequestStatus5mRatioMetricName) {
prometheus.MustRegister(zoneRequestStatus5mRatio)
}
if !deniedMetrics.Has(zoneRequestEdgeTTFB5mQuantilesMetricName) {
prometheus.MustRegister(zoneRequestEdgeTTFB5mQuantiles)
}
if !deniedMetrics.Has(zoneRequestBrowserMapMetricName) {
prometheus.MustRegister(zoneRequestBrowserMap)
}
Expand Down Expand Up @@ -706,6 +728,75 @@ func fetchZoneColocationAnalytics(zones []cfzones.Zone, wg *sync.WaitGroup, deni
}
}

func fetchZoneAdaptiveHTTPStats(zones []cfzones.Zone, wg *sync.WaitGroup, deniedMetricsSet MetricsSet) {
wg.Add(1)
defer wg.Done()

if deniedMetricsSet.Has(zoneRequestStatus5mRatioMetricName) && deniedMetricsSet.Has(zoneRequestEdgeTTFB5mQuantilesMetricName) {
return
}

zoneIDs := extractZoneIDs(zones)
if len(zoneIDs) == 0 {
return
}

r, err := fetchZone5mStats(zoneIDs)
if err != nil {
log.Error("failed to fetch analyzed zone 5-minute stats: ", err)
return
}

for _, z := range r.Viewer.Zones {
name, account := findZoneAccountName(zones, z.ZoneTag)

if !deniedMetricsSet.Has(zoneRequestStatus5mRatioMetricName) {
for _, g := range z.HTTPRequestsAdaptiveGroups {
zoneRequestStatus5mRatio.With(
prometheus.Labels{
"zone": name,
"account": account,
"origin_ip": g.Dimensions.OriginIP,
"status_group": "4xx",
}).Add(float64(g.Ratio.Status4xx))
zoneRequestStatus5mRatio.With(
prometheus.Labels{
"zone": name,
"account": account,
"origin_ip": g.Dimensions.OriginIP,
"status_group": "5xx",
}).Add(float64(g.Ratio.Status5xx))
}
}

if !deniedMetricsSet.Has(zoneRequestEdgeTTFB5mQuantilesMetricName) {
for _, g := range z.HTTPRequestsAdaptiveGroups {
zoneRequestEdgeTTFB5mQuantiles.With(
prometheus.Labels{
"zone": name,
"account": account,
"origin_ip": g.Dimensions.OriginIP,
"quantile": "P50",
}).Set(float64(g.Quantiles.EdgeTimeToFirstByteMsP50))
zoneRequestEdgeTTFB5mQuantiles.With(
prometheus.Labels{
"zone": name,
"account": account,
"origin_ip": g.Dimensions.OriginIP,
"quantile": "P95",
}).Set(float64(g.Quantiles.EdgeTimeToFirstByteMsP95))
zoneRequestEdgeTTFB5mQuantiles.With(
prometheus.Labels{
"zone": name,
"account": account,
"origin_ip": g.Dimensions.OriginIP,
"quantile": "P99",
}).Set(float64(g.Quantiles.EdgeTimeToFirstByteMsP99))
}
}
}
}

func fetchZoneAnalytics(zones []cfzones.Zone, wg *sync.WaitGroup, deniedMetricsSet MetricsSet) {
wg.Add(1)
defer wg.Done()
Expand Down