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>
116 lines
4.2 KiB
Bash
Executable file
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
|