Skip to content

Commit

Permalink
add workers stats
Browse files Browse the repository at this point in the history
Signed-off-by: rare-magma <[email protected]>
  • Loading branch information
rare-magma committed Sep 27, 2024
1 parent bc002d5 commit 1c93347
Show file tree
Hide file tree
Showing 3 changed files with 126 additions and 2 deletions.
6 changes: 6 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ Bash script that uploads the Cloudflare Analytics API data to influxdb on an hou

## Dependencies

- [awk](https://www.gnu.org/software/gawk/manual/gawk.html)
- [bash](https://www.gnu.org/software/bash/)
- [coreutils (cat)](https://www.gnu.org/software/coreutils/)
- [coreutils (date)](https://www.gnu.org/software/coreutils/)
Expand Down Expand Up @@ -97,6 +98,7 @@ ORG='home'
BUCKET='cloudflare'
CLOUDFLARE_API_TOKEN='ZXhhbXBsZXRva2VuZXhhcXdzZGFzZGptcW9kcXdvZGptcXdvZHF3b2RqbXF3ZHFhc2RhCg=='
CLOUDFLARE_ACCOUNT_EMAIL='[email protected]'
CLOUDFLARE_ACCOUNT_TAG='aa0a0aa000a0000aa00a00aa0e000a0a'
```
- `INFLUXDB_HOST` should be the FQDN of the influxdb server.
Expand All @@ -106,6 +108,8 @@ CLOUDFLARE_ACCOUNT_EMAIL='[email protected]'
- This token should have write access to the `BUCKET` defined above.
- `CLOUDFLARE_API_TOKEN` should be the cloudflare API token value.
- This token should be assigned the `All zones - Analytics:Read` permission.
- Additionally, the `Account Analytics:Read` permission is necessary for workers metrics.
- `CLOUDFLARE_ACCOUNT_TAG` should be the tag associated with the cloudflare account.
- Required for cloudflare accounts on a paid plan:
- `CLOUDFLARE_ACCOUNT_EMAIL` should be the email associated with the paid cloudflare account.
Expand Down Expand Up @@ -143,6 +147,7 @@ systemctl --user list-timers
- cloudflare_stats_ip: Request statistics broken down by robot type
- cloudflare_stats_responses: Request statistics broken down by response status code
- cloudflare_stats: General request statistics
- cloudflare_stats_workers: Workers statistics grouped by hour
## Exported metrics example
Expand All @@ -153,6 +158,7 @@ cloudflare_stats_countries,zone="example.com",country="CA" bytes=312170,requests
cloudflare_stats_ip,zone="example.com",ipType="searchEngine" requests=21 1703894400
cloudflare_stats_responses,zone="example.com",status=403 requests=1 1703894400
cloudflare_stats,zone="example.com" bytes=2032039,cachedBytes=40607,cachedRequests=17,encryptedBytes=2020727,encryptedRequests=251,pageViews=178,requests=266,threats=0,uniqueVisitors=2 1703894400'
cloudflare_stats_workers,account=aa0a0aa000a0000aa00a00aa0e000a0a,worker=worker-name status="scriptThrewException",cpuTimeP50=1246,cpuTimeP99=1246,durationP50=0.001246,durationP99=0.001246,responseBodySizeP50=0,responseBodySizeP99=0,wallTimeP50=1605,wallTimeP99=1605,clientDisconnects=0,cpuTimeUs=1246,duration=0.001246,errors=1,requests=1,responseBodySize=0,subrequests=0,wallTime=1605 1727340566
```

## Example grafana dashboard
Expand Down
1 change: 1 addition & 0 deletions cloudflare_exporter.conf
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,4 @@ ORG=''
BUCKET=''
CLOUDFLARE_API_TOKEN=''
CLOUDFLARE_ACCOUNT_EMAIL=''
CLOUDFLARE_ACCOUNT_TAG=''
121 changes: 119 additions & 2 deletions cloudflare_exporter.sh
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,15 @@

set -Eeo pipefail

dependencies=(cat curl date gzip jq)
dependencies=(awk cat curl date gzip jq)
for program in "${dependencies[@]}"; do
command -v "$program" >/dev/null 2>&1 || {
echo >&2 "Couldn't find dependency: $program. Aborting."
exit 1
}
done

AWK=$(command -v awk)
CAT=$(command -v cat)
CURL=$(command -v curl)
DATE=$(command -v date)
Expand All @@ -19,10 +20,13 @@ JQ=$(command -v jq)
if [[ "${RUNNING_IN_DOCKER}" ]]; then
source "/app/cloudflare_exporter.conf"
CLOUDFLARE_ZONE_LIST=$($CAT /app/cloudflare_zone_list.json)
else
elif [[ -f $CREDENTIALS_DIRECTORY/creds ]]; then
#shellcheck source=/dev/null
source "$CREDENTIALS_DIRECTORY/creds"
CLOUDFLARE_ZONE_LIST=$($CAT $CREDENTIALS_DIRECTORY/list)
else
source "./cloudflare_exporter.conf"
CLOUDFLARE_ZONE_LIST=$($CAT ./cloudflare_zone_list.json)
fi

[[ -z "${INFLUXDB_HOST}" ]] && echo >&2 "INFLUXDB_HOST is empty. Aborting" && exit 1
Expand All @@ -31,10 +35,13 @@ fi
[[ -z "${BUCKET}" ]] && echo >&2 "BUCKET is empty. Aborting" && exit 1
[[ -z "${CLOUDFLARE_API_TOKEN}" ]] && echo >&2 "CLOUDFLARE_API_TOKEN is empty. Aborting" && exit 1
[[ -z "${CLOUDFLARE_ZONE_LIST}" ]] && echo >&2 "CLOUDFLARE_ZONE_LIST is empty. Aborting" && exit 1
[[ -z "${CLOUDFLARE_ACCOUNT_TAG}" ]] && echo >&2 "CLOUDFLARE_ACCOUNT_TAG is empty. Aborting" && exit 1
[[ $(echo "${CLOUDFLARE_ZONE_LIST}" | $JQ type 1>/dev/null) ]] && echo >&2 "CLOUDFLARE_ZONE_LIST is not valid JSON. Aborting" && exit 1
[[ -n "${CLOUDFLARE_ACCOUNT_EMAIL}" ]] && CF_EMAIL_HEADER="X-Auth-Email: ${CLOUDFLARE_ACCOUNT_EMAIL}"

RFC_CURRENT_DATE=$($DATE --rfc-3339=date)
ISO_CURRENT_DATE_TIME=$($DATE --iso-8601=seconds)
ISO_CURRENT_DATE_TIME_1H_AGO=$($DATE --iso-8601=seconds --date "1 hour ago")
INFLUXDB_URL="https://$INFLUXDB_HOST/api/v2/write?precision=s&org=$ORG&bucket=$BUCKET"
CF_URL="https://api.cloudflare.com/client/v4/graphql"

Expand Down Expand Up @@ -248,3 +255,113 @@ END_HEREDOC
--data-binary @-
fi
done

WORKERS_GRAPHQL_QUERY=$(
cat <<END_HEREDOC
{ "query":
"query GetWorkersAnalytics(\$accountTag: string, \$datetimeStart: string, \$datetimeEnd: string) {
viewer {
accounts(filter: {accountTag: \$accountTag}) {
workersInvocationsAdaptive(limit: 100, filter: {
datetime_geq: \$datetimeStart,
datetime_leq: \$datetimeEnd
}) {
sum {
clientDisconnects
cpuTimeUs
duration
errors
requests
subrequests
responseBodySize
wallTime
}
quantiles {
cpuTimeP50
cpuTimeP99
durationP50
durationP99
responseBodySizeP50
responseBodySizeP99
wallTimeP50
wallTimeP99
}
dimensions{
datetimeHour
scriptName
status
}
}
}
}
}",
"variables": {
"accountTag": "$CLOUDFLARE_ACCOUNT_TAG",
"datetimeStart": "$ISO_CURRENT_DATE_TIME_1H_AGO",
"datetimeEnd": "$ISO_CURRENT_DATE_TIME"
}
}
END_HEREDOC
)

cf_workers_json=$(
$CURL --silent --fail --show-error --compressed \
--request POST \
--header "Content-Type: application/json" \
--header "$CF_EMAIL_HEADER" \
--header "Authorization: Bearer $CLOUDFLARE_API_TOKEN" \
--data "$(echo -n $WORKERS_GRAPHQL_QUERY)" \
"$CF_URL"
)

cf_workers_nb_errors=$(echo $cf_workers_json | $JQ ".errors | length")

if [[ $cf_workers_nb_errors -gt 0 ]]; then
cf_workers_errors=$(echo $cf_workers_json | $JQ --raw-output ".errors[] | .message")
printf "Cloudflare API request failed with: \n%s\nAborting\n" "$cf_workers_errors" >&2
exit 1
fi

cf_nb_invocations=$(echo $cf_workers_json | $JQ ".data.viewer.accounts[0].workersInvocationsAdaptive | length")

if [[ $cf_nb_invocations -gt 0 ]]; then
cf_workers_json_parsed=$(echo $cf_workers_json | $JQ ".data.viewer.accounts[0].workersInvocationsAdaptive")
cf_stats_workers=$(
echo "$cf_workers_json_parsed" |
$JQ --raw-output "
(.[] |
[\"${CLOUDFLARE_ACCOUNT_TAG}\",
.dimensions.scriptName,
.dimensions.status,
.quantiles.cpuTimeP50,
.quantiles.cpuTimeP99,
.quantiles.durationP50,
.quantiles.durationP99,
.quantiles.responseBodySizeP50,
.quantiles.responseBodySizeP99,
.quantiles.wallTimeP50,
.quantiles.wallTimeP99,
.sum.clientDisconnects,
.sum.cpuTimeUs,
.sum.duration,
.sum.errors,
.sum.requests,
.sum.responseBodySize,
.sum.subrequests,
.sum.wallTime,
(.dimensions.datetimeHour | fromdateiso8601)
])
| @tsv" |
$AWK '{printf "cloudflare_stats_workers,account=%s,worker=%s status=\"%s\",cpuTimeP50=%s,cpuTimeP99=%s,durationP50=%s,durationP99=%s,responseBodySizeP50=%s,responseBodySizeP99=%s,wallTimeP50=%s,wallTimeP99=%s,clientDisconnects=%s,cpuTimeUs=%s,duration=%s,errors=%s,requests=%s,responseBodySize=%s,subrequests=%s,wallTime=%s %s\n", $1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16, $17, $18, $19, $20}'
)

echo "$cf_stats_workers" | $GZIP |
$CURL --silent --fail --show-error \
--request POST "${INFLUXDB_URL}" \
--header 'Content-Encoding: gzip' \
--header "Authorization: Token $INFLUXDB_API_TOKEN" \
--header "Content-Type: text/plain; charset=utf-8" \
--header "Accept: application/json" \
--data-binary @-

fi

0 comments on commit 1c93347

Please sign in to comment.