cf-cli-tools/cf-analytics
feibisi 1be3d8ef8d 初始提交:Cloudflare CLI 工具集
debian 开发,modiqi 修复 cf_load_profile 缺失问题。
9 个命令:cf-api/cf-zone/cf-dns/cf-cache/cf-ssl/cf-fw/cf-pagerule/cf-analytics/cf-hostname
支持多账号、域名自动解析 zone_id。

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-02-24 02:39:31 +08:00

116 lines
4.2 KiB
Bash
Executable file

#!/usr/bin/env bash
set -euo pipefail
# cf-analytics — Cloudflare 流量分析
# 用法: cf-analytics <domain> [-d days] 流量概览(默认最近 1 天)
# cf-analytics top <domain> [-d days] 热门 URL/国家/IP
# cf-analytics threats <domain> 威胁分析
# 选项: -p <profile> 指定 profile
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
source "$SCRIPT_DIR/cf-lib.sh"
cf_parse_profile "$@"
set -- "${CF_REMAINING_ARGS[@]}"
cf_load_profile
usage() {
cat >&2 <<'EOF'
用法: cf-analytics <command> <domain> [args...]
命令:
overview <domain> [-d days] 流量概览(默认 1 天)
top <domain> [-d days] 热门国家/状态码
threats <domain> [-d days] 威胁分析
EOF
exit 1
}
[[ $# -lt 1 ]] && usage
CMD="$1"; shift
get_time_range() {
local days="${1:-1}"
SINCE=$(date -u -d "$days days ago" '+%Y-%m-%dT%H:%M:%SZ' 2>/dev/null || date -u -v-${days}d '+%Y-%m-%dT%H:%M:%SZ')
UNTIL=$(date -u '+%Y-%m-%dT%H:%M:%SZ')
}
case "$CMD" in
overview)
[[ $# -lt 1 ]] && { echo "用法: cf-analytics overview <domain> [-d days]" >&2; exit 1; }
DOMAIN="$1"; shift
DAYS=1
while [[ $# -gt 0 ]]; do
case "$1" in
-d) DAYS="$2"; shift 2 ;;
*) shift ;;
esac
done
ZONE_ID=$(cf_resolve_zone "$DOMAIN")
get_time_range "$DAYS"
resp=$(cf_call GET "/zones/$ZONE_ID/analytics/dashboard?since=$SINCE&until=$UNTIL")
cf_check_error "$resp"
echo "=== $DOMAIN 流量概览(最近 ${DAYS} 天)==="
echo "$resp" | jq '.result.totals | {
"总请求": .requests.all,
"缓存命中": .requests.cached,
"未缓存": .requests.uncached,
"缓存率": (if .requests.all > 0 then ((.requests.cached / .requests.all * 100 * 10 | round / 10) | tostring) + "%" else "N/A" end),
"总流量_MB": ((.bandwidth.all / 1048576) | round),
"缓存流量_MB": ((.bandwidth.cached / 1048576) | round),
"独立访客": .uniques.all,
"威胁": .threats.all,
"页面浏览": .pageviews.all
}'
;;
top)
[[ $# -lt 1 ]] && { echo "用法: cf-analytics top <domain> [-d days]" >&2; exit 1; }
DOMAIN="$1"; shift
DAYS=1
while [[ $# -gt 0 ]]; do
case "$1" in
-d) DAYS="$2"; shift 2 ;;
*) shift ;;
esac
done
ZONE_ID=$(cf_resolve_zone "$DOMAIN")
get_time_range "$DAYS"
resp=$(cf_call GET "/zones/$ZONE_ID/analytics/dashboard?since=$SINCE&until=$UNTIL")
cf_check_error "$resp"
echo "=== 热门国家 ==="
echo "$resp" | jq -r '.result.totals.requests.country | to_entries | sort_by(-.value) | .[0:10][] | "\(.key): \(.value)"'
echo ""
echo "=== HTTP 状态码 ==="
echo "$resp" | jq -r '.result.totals.requests.http_status | to_entries | sort_by(-.value) | .[] | "\(.key): \(.value)"'
echo ""
echo "=== 内容类型 ==="
echo "$resp" | jq -r '.result.totals.requests.content_type | to_entries | sort_by(-.value) | .[0:10][] | "\(.key): \(.value)"'
;;
threats)
[[ $# -lt 1 ]] && { echo "用法: cf-analytics threats <domain> [-d days]" >&2; exit 1; }
DOMAIN="$1"; shift
DAYS=1
while [[ $# -gt 0 ]]; do
case "$1" in
-d) DAYS="$2"; shift 2 ;;
*) shift ;;
esac
done
ZONE_ID=$(cf_resolve_zone "$DOMAIN")
get_time_range "$DAYS"
resp=$(cf_call GET "/zones/$ZONE_ID/analytics/dashboard?since=$SINCE&until=$UNTIL")
cf_check_error "$resp"
echo "=== $DOMAIN 威胁分析(最近 ${DAYS} 天)==="
total=$(echo "$resp" | jq '.result.totals.threats.all')
echo "总威胁数: $total"
echo ""
echo "=== 威胁类型 ==="
echo "$resp" | jq -r '.result.totals.threats.type | to_entries | sort_by(-.value) | .[] | "\(.key): \(.value)"'
echo ""
echo "=== 威胁来源国 ==="
echo "$resp" | jq -r '.result.totals.threats.country | to_entries | sort_by(-.value) | .[0:10][] | "\(.key): \(.value)"'
;;
*) usage ;;
esac