scripts/old/ctc/ids.sh
2023-06-05 23:04:30 +08:00

1152 lines
62 KiB
Bash
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#!/bin/bash
# 功能实现根据requestID以及IP获得完整的链路日志信息
# 依赖文件ips.sh
# 存在问题:
# 静态-点播-直播
# 1. 10:00:04 - 10:15:33 - 10:29:01 - 10:30:01 - 10:45:28 - 10:59:55
# 2. 一个小时前 | 两个小时前 | 三个小时前 | 四个小时前 | 八个小时前 | 两天前
# 3. 00:00:00前后
# 各个层级HIT/MISS情况
# - MISS MISS | MISS HIT | HIT MISS | HIT HIT
# 直播特殊验证项
# 拉流-合并回源 | 推流 | 转推 | 转码
#=======================================================================================
# 功能:捕获 Ctrl + C 将后台进程全部终止
# 入参bg_pids, progress_pid
# 出参None
function onCtrlC () {
exec 3>&2 # 3 is now a copy of 2
exec 2> /dev/null # 2 now points to /dev/null
kill ${bg_pids} ${progress_pid} >/dev/null 2>&1
sleep 1 # sleep to wait for process to die
exec 2>&3 # restore stderr to saved
exec 3>&- # close saved version
echo -e "${c_bir}IDS!\n${c_e}"
echo -e "${c_bir}[IDS-100] Ctrl+C is captured, exiting...\n${c_e}"
exit 100
}
#=======================================================================================
# 功能:捕获 `exit` 退出指令,并计算脚本实际运行时间
# 入参TS
# 出参None
function onExit () {
local te=`date +%s`
echo -e "${c_bib}Start Time: $(date -d@$((ts-0)) +'%Y-%m-%d %H:%M:%S')"
echo -e "${c_bib}End Time : `date +'%Y-%m-%d %H:%M:%S'`"
echo -e "${c_bib}Duration : $((te-ts)) seconds\n${c_e}"
}
#=======================================================================================
# 功能检查输入的时间范围是否符合格式要求14天内不能是未来时间10位数字
# 入参time_range
# 出参current, year, month, day, hour, time_range
function time_check() {
# 如果入参 time_range 的值是空,或者说函数没有入参
if [[ $time_range == '' ]]; then
time_range=`date +%Y%m%d%H`
year=${time_range:0:4}
month=${time_range:4:2}
day=${time_range:6:2}
hour=${time_range:8:2}
current='yes'
return 0
fi
# 检查入参是否正确:长度,表示的时间范围等
[[ ! $time_range =~ ^[0-9]{10}$ ]] && { echo -e "${c_br}[IDS-101] 请输入正确的时间格式,退出...\n${c_e}"; exit 101; }
# 验证入参是10天以内的时间范围
now=`date +%s`
# 准备工作,后续要用
year=${time_range:0:4}
month=${time_range:4:2}
day=${time_range:6:2}
hour=${time_range:8:2}
# 将入参转换为秒
previous=`date -d "$year-$month-$day $hour:00:00" +"%s"`
# 计算当前时间 - 入参时间
let range_s=now-previous
let range_d=range_s/86400
# 如果是14天以外的入参时间则不可查
[[ $range_d -gt 10 ]] && { echo -e "${c_br}[IDS-102] 只能查找最近10天以内的日志记录退出...\n${c_e}"; exit 102; }
# 判断 time_range 是否是当前时间,并用 current 来标识,默认是当前,即 current = yes
[[ $time_range == `date +%Y%m%d%H` ]] && current='yes' || current='no'
}
#=======================================================================================
# 功能:等待后台进程结束时,输出进度条
# 入参bg_pids, level
# 出参None
function progress() {
length=75
ratio=1
# ps -p pidlist命令的作用是列出pidlist里面所有pid的运行状态已经结束的pid将不会被列出每个pid一行
while [[ "$(ps -p ${bg_pids} | wc -l)" -ne 1 ]]; do
mark='>'
progress_bar=''
# 小于ratio的部分填充'>'大于ratio的部分填充' '必须是空格不然ratio重新变成1的时候没有变化
for i in $(seq 1 $length); do
if [[ $i -gt $ratio ]]; then
mark=' '
fi
progress_bar="${progress_bar}${mark}"
done
echo -ne "${c_bic}Collecting $level Data: ${progress_bar}\r${c_e}"
ratio=$((ratio+1))
if [[ $ratio -gt $length ]]; then
ratio=1
fi
sleep 1
done
}
#=======================================================================================
# 功能适用于旧版本的reqID获取$label_en和$time_range
# 入参None
# 出参time_range, label_en, edge
function node_time_old() {
echo -e "${c_bg}请输入request ID所在节点信息支持边缘RIP/VIP/中英文节点名:${c_e}"
# 60s时间接收输入要查询的节点
read -t 60 edge
# 判断60s内无输入则自动退出
[[ $? -ne 0 ]] && { echo -e "${c_br}[IDS-103] 60s内无任何输入退出...\n${c_e}"; exit 103; }
# 判断输入的边缘节点信息是空,则自动退出
[[ $edge == '' ]] && { echo -e "${c_br}[IDS-104] 请输入正确的边缘节点信息,退出...\n${c_e}"; exit 104; }
# 判断边缘节点信息是否在天翼平台
ips $edge > ips.log 2>&1
[[ $? -ne 0 ]] && { cat ips.log; echo -e "${c_br}[IDS-105]${c_e}"; exit 105; } || cd $trash
label_en=`cat ips.log | grep -Eo '(ct|cu|cm|bgp|ctbgp|cmbgp|cubgp|as|eu|sa|na|cbn|cern)_[a-z]{2,3}_[a-z]{2,20}[0-9]{1,2}_(c|e|n)[0-9]{0,2}' | sort | uniq`
# 输入中文节点名的情况下,可能会得到两个边缘节点,需要手动确认是哪个
number=`echo $label_en | awk '{print NF}'`
[[ $label_en == '' ]] && { echo -e "${c_br}[IDS-106] 请确认输入的 $edge 是边缘节点,退出...\n${c_e}"; exit 106; }
if [[ $number -gt 1 ]]; then
echo $label_en | awk '{for(i=1;i<=NF;i++) print " -", $i}'
echo -e "${c_bp}输入的 $edge 边缘节点中有两个组,请确认具体是哪个:${c_e}"
read -t 60 label_en_input
# 判断60s内无输入则自动退出
[[ $? -ne 0 ]] && { echo -e "${c_br}[IDS-107] 60s内无任何输入退出...\n${c_e}"; exit 107; }
# 判断输入信息是否是正确的
echo $label_en | grep -wq $label_en_input
[[ $? -ne 0 ]] && { echo -e "${c_br}[IDS-108] 需要从如上选择正确的边缘节点信息,请重新运行,退出...\n${c_e}"; exit 108; }
label_en=$label_en_input
fi
# 60s时间接收输入要查询的时间
echo -e "${c_bg}请输入要查询的reqID生成时间格式为yyyymmddHH(默认当前 - $(date +%Y%m%d%H)): ${c_e} "
read -t 60 time_range
[[ $? -ne 0 ]] && { echo -e "${c_br}[IDS-109] 60s内无任何输入退出...\n${c_e}"; exit 109; }
}
#=======================================================================================
# 功能适用于新版本的reqID获取label_en和time_range
# 入参None
# 出参time_range, label_en, edge
function node_time_new() {
ts_hex=`echo $req_id | awk -F '_' '{print $1}'`
ts_hex=`printf "%d" "0x$ts_hex"`
time_range=`date -d @$ts_hex +'%Y%m%d%H'`
ts=`date -d @$ts_hex +'%Y-%m-%d %H:%M:%S'`
# 根据中间部分的信息找出label_en
edge=`echo $req_id | awk -F '_' '{print $2}'`
edge=`echo $edge | awk -F '-' '{print $1"-"$2"-ca"$3}'`
ping -c 4 -q $edge > ping.log
if [[ $? -eq 0 ]]; then
rip=`cat ping.log | grep -Eo "([0-9]{1,3}\.){3}[0-9]{1,3}"`
# 获取$label_en
ips $rip > ips.log 2>&1
[[ $? -ne 0 ]] && { cat ips.log; echo -e "${c_br}[IDS-110]${c_e}"; exit 110; } || cd $trash
label_en=`cat ips.log | grep -Eo '(ct|cu|cm|bgp|ctbgp|cmbgp|cubgp|as|eu|sa|na|cbn|cern)_[a-z]{2,3}_[a-z]{2,20}[0-9]{1,2}_(e)[0-9]{0,2}' | sort | uniq`
else
echo -e "${c_br}[IDS-111] 本地到边缘缓存主机$edge的网络无法ping通,需要检查下服务器是否宕机,或者检查下${edge}是否是天翼的节点...${c_e}"
exit 111
fi
echo -e "${c_bib}将在$rip($label_en)上查找$ts时间点的日志,如果时间靠近${c_bir}整点${c_bib},有可能会因日志切割导致无法正确查询...${c_e}"
}
#=======================================================================================
# 功能:获取 prod_type - 产品类型
# 入参None
# 出参TS, prod_type
function prod_type_inp() {
# 60s时间接收输入要查询的类型
echo -e "1. 静态/下载/点播/全站(default - v03/ov06)"
echo -e "2. 直播(ACC1/2/3)"
echo -e "3. 安全"
echo -e "4. quic"
echo -e "5. L1/L2/L3/L4/L5/L6/L7(e.g. 查询L3则输入5.3)"
echo -e "${c_bg}请输入要查询的业务类型(目前仅支持1/2/5) ${c_e}"
read -t 60 prod_type
[[ $? -ne 0 ]] && { echo -e "${c_br}[IDS-112] 60s内无任何输入退出...\n${c_e}"; exit 112; }
[[ $prod_type == '' ]] && prod_type='1'
ts=`date +%s` # 开始计时
}
#=======================================================================================
# 功能CDN的NG访问日志处理静态/点播/下载/全站/L1-7
# 入参rip_list, bg_pids, current, year, month, day, hour, req_id
# 出参access_$rip
function cdn_log_access() {
# 根据业务类型,指定前缀
[[ $prod_type == '1' ]] && prefix=''
[[ $prod_type == '5.1' ]] && prefix='L1_'
[[ $prod_type == '5.2' ]] && prefix='L2_'
[[ $prod_type == '5.3' ]] && prefix='L3_'
[[ $prod_type == '5.4' ]] && prefix='L4_'
[[ $prod_type == '5.5' ]] && prefix='L5_'
[[ $prod_type == '5.6' ]] && prefix='L6_'
[[ $prod_type == '5.7' ]] && prefix='L7_'
# 如果time_range是当前时间
if [[ $current == 'yes' ]]; then
# ssh 进每一个rip搜索core_access.log设定ssh连接超时时长为CT*${time_range}*表示包含time_range就要进行搜索
# 把搜索的结果放进access_$rip文件所有的ssh命令都后台执行并将它们的PID存入bg_pids
for rip in $rip_list; do
ssh -o ConnectTimeout=$CT $rip "
cat $cdn_access_log/${prefix}core_access.log | grep $req_id;
cat $cdn_access_log/${prefix}core_access.log_*${time_range}* | grep $req_id" > access_${rip} 2>&1 &
bg_pids=$bg_pids' '$(jobs -p | tail -1)
done
# 如果time_range不是当前时间
else
# 简单粗暴地,分别过滤回滚文件和未归档两部分日志文件
for rip in $rip_list; do
ssh -o ConnectTimeout=$CT $rip "
cat $cdn_access_log/${prefix}core_access.log_*${time_range}* | grep $req_id;
zcat $cdn_access_log/$year$month$day/${prefix}core_access.log_*${time_range}* | grep $req_id" > access_${rip} 2>&1 &
bg_pids=$bg_pids' '$(jobs -p | tail -1)
done
fi
}
#=======================================================================================
# 功能CDN的ATS回源日志处理静态/点播/下载/全站/L1-7
# 入参rip_list, bg_pids, current, year, month, day, hour, req_id
# 出参origin_$rip
function cdn_log_origin() {
# 如果time_range是当前时间
if [[ $current == 'yes' ]]; then
# ssh 进每一个rip搜索origin.log设定ssh连接超时时长为CT
# 把搜索的结果放进origin_$rip文件所有的ssh命令都后台执行并将它们的PID存入bg_pids
for rip in $rip_list; do
ssh -o ConnectTimeout=$CT $rip "
cat $cdn_origin_log/origin.log | grep $req_id;
cat $cdn_origin_log/origin.log_*${time_range}* | grep $req_id" > origin_${rip} 2>&1 &
bg_pids=$bg_pids' '$(jobs -p | tail -1)
done
# 如果time_range不是当前时间
else
# 简单粗暴地,分别过滤回滚文件和未归档两部分日志文件
for rip in $rip_list; do
ssh -o ConnectTimeout=$CT $rip "
cat $cdn_origin_log/origin.log_*${time_range}* | grep $req_id;
zcat $cdn_origin_log/$year$month$day/origin.log_*${time_range}* | grep $req_id" > origin_${rip} 2>&1 &
bg_pids=$bg_pids' '$(jobs -p | tail -1)
done
fi
}
#=======================================================================================
# 功能搜索处理每一层级的CDN日志静态/点播/下载/全站/L1-7
# 入参level, label_en, current, year, month, day, hour
# 出参upstream, port, upstream_and_port
function cdn_log_proc() {
# -------------------------------------------------------------------------
# 获取 rip 列表,并初始化 bg_pids 数组
rip_list=`cat $data/ip.group | grep $label_en | awk '{print $1}' | sort | uniq`
bg_pids=''
# access日志/home/log/cluster_gateway_log/core_access.log
cdn_log_access "$rip_list" "$bg_pids" "$current" "$year" "$month" "$day" "$hour" "$req_id"
# origin日志/home/log/trafficserver/origin.log
cdn_log_origin "$rip_list" "$bg_pids" "$current" "$year" "$month" "$day" "$hour" "$req_id"
# 动态进度条
progress "${bg_pids}" $level &
progress_pid=$(jobs -p | tail -1)
# 等待所有 bg_pids 存储的后台进程执行完毕
wait
echo -ne "${c_bic}$level Data collected.${c_e}"
echo -ne " "
# -------------------------------------------------------------------------
# 处理上述生成的rip中拿到的access和origin日志筛选出包含req_id的行
# 初始化access.log和origin.log -- 处理单个rip上生成的access/origin日志匹配req_id
# 如果找到则将对应的rip和日志内容用追加到相应日志尾部以"为分隔rip作为日志的最后一个字段
log_merge $rip_list $req_id
# -------------------------------------------------------------------------
# 可以根据当前文件夹下的图片cdnlog_search_logic.jpg来理解
# 如果找到了access日志则过滤打印输出并将access_flg重置
if [[ $access_flg -eq 1 ]]; then
# v03版本第5个字段是日志打印时间戳
cat access.log | sort -t'"' -n -k5 > log && mv log access.log
# 按时间排序,打印找到的所有日志内容
cat access.log | while read line; do
access_ip=`echo $line | awk -F'"' '{print $NF}'`
echo -e "${c_by}\n$level NG Log: searching $label_en ...... $access_ip${c_e}"
# 将匹配"*的右边最短路径删除也就是将之前追加到最末尾的rip删掉
out=${line%\"*}
log_format "$out"
done
access_flg=0
# 如果找到了origin日志则过滤打印输出并将origin_flg重置
if [[ $origin_flg -eq 1 ]]; then
# ov06版本第43个字段是回源开始时间戳
cat origin.log | sort -t'"' -n -k43 > log && mv log origin.log
cat origin.log | while read line; do
origin_ip=`echo $line | awk -F'"' '{print $NF}'`
echo -e "${c_by}\n$level ATS Log: searching $label_en ...... $origin_ip${c_e}"
# 将匹配"*的右边最短路径删除也就是将之前追加到最末尾的rip删掉
out=${line%\"*}
log_format "$out"
done
origin_flg=0
# 如果origin日志找到了则从origin日志中获取upstream和port
upstream_and_port=`cat origin.log | awk -F '"' '{print $8":"$9}' | sort | uniq`
uap=$upstream_and_port
for nhi in $upstream_and_port; do
upstream=`echo $nhi | awk -F ':' '{print $1}'`
port=`echo $nhi | awk -F ':' '{print $2}'`
ips $upstream > ips.log 2>&1
# 如果upstream是天翼的IP则输出如下
if [[ $? -eq 0 ]]; then
echo -e "${c_bp}\n[ATS-$level]: 从origin日志查询到$req_id的回上层地址是$nhi(CTC IP),继续查询...${c_e}"
cd $trash
# 如果upstream不是天翼的IP则输出如下
else
echo -e "${c_br}\n[ATS-$level]: 从origin日志查询到$req_id的回源地址$nhi不是天翼的IP可能是ATS回源了${c_e}"
echo -e "${c_bp}请确认${c_bc}$nhi${c_bp}是否是源站IP。\n${c_e}"
uap=`echo $uap | sed -n "s/$nhi//p"`
fi
done
[[ $uap == '' ]] && { echo -e "${c_bg}[IDS-113] 所有IP均已处理完毕退出...${c_e}"; exit 113; } || { upstream_and_port=$uap; cd $trash; }
# 如果没有找到origin日志则从access日志获取upstream和port并用ips脚本检测查询upstream是否是天翼的IP
else
# 如果没有找到origin日志则判断是否缓存了
# MISS from hb-wuhan13-ca26, MISS from fj-quanzhou6-ca16 -- ct_fj_quanzhou6_e1
hit=`echo $label_en | awk -F'_' '{print "HIT from", $2"-"$3}'`
cat access.log | grep -iq "$hit"
[[ $? -eq 0 ]] && { echo -e "${c_bp}\n[IDS-114] [Access-$level]: 边缘已经命中缓存,搜索结束...${c_e}\n"; exit 114; }
# 如果不是缓存住了从access日志获取回上层信息
uap_28=`cat access.log | tail -1 | awk -F '"' '{print $28}'`
uap_24=`cat access.log | tail -1 | awk -F '"' '{print $24}'`
if [[ $uap_28 == '' || $uap_28 == '-' ]]; then
if [[ $uap_24 == '' || $uap_24 == '-' ]]; then
echo -e "${c_br}\n[IDS-115] [Access-$level]: 没有找到origin日志也找不到$req_id的回上层地址,无法继续查询,退出...${c_e}"
exit 115
else
upstream_and_port=$uap_24
fi
else
upstream_and_port=$uap_28
fi
# WARNING: 此处没有考虑当uap_24有多个后端代理的情况
# 判断是否是天翼云 IP
upstream_and_port=`echo $upstream_and_port | tr ',' ' '`
uap=$upstream_and_port
for nhi in $upstream_and_port; do
upstream=`echo $nhi | awk -F ':' '{print $1}'`
port=`echo $nhi | awk -F ':' '{print $2}'`
ips $upstream > ips.log 2>&1
# 如果upstream是天翼的IP则输出如下
if [[ $? -eq 0 ]]; then
echo -e "${c_bp}\n[NG-$level]: 从access日志查询到$req_id的回上层地址是$nhi(CTC IP),继续查询...${c_e}"
cd $trash
# 如果upstream不是天翼的IP则输出如下
else
echo -ne "${c_br}\n[NG-$level]: 从access日志查询到$req_id的回源地址$nhi不是天翼的IP可能是NG直接回源了。${c_e}"
echo -e "${c_br}或者查询access主机上的error日志看是否是ats因自身或源站故障导致无法应答${c_e}"
echo -e "${c_bp}请确认${c_bc}$nhi${c_bp}是否是源站IP。${c_e}"
uap=`echo $uap | sed -n "s/$nhi//p"`
fi
done
[[ $uap == '' ]] && { echo -e "${c_bg}[IDS-116] 所有IP均已处理完毕退出...${c_e}"; exit 116; } || { upstream_and_port=$uap; cd $trash; }
fi
# 如果没有找到access日志则要判断当前是在哪个层级边缘-一层父-二层父
else
# 如果是一层父或者是二层父再找一下origin日志是否存在
if [[ $level == 'Center' || $level == 'Nation' ]]; then
# 如果origin日志有找到记录则打印出来
if [[ $origin_flg -eq 1 ]]; then
cat origin.log | sort -t'"' -n -k43 > log && mv log origin.log
cat origin.log | while read line; do
origin_ip=`echo $line | awk -F'"' '{print $NF}'`
echo -e "${c_by}\n$level ATS Log: searching $label_en ...... $origin_ip${c_e}"
out=${line%\"*}
log_format "$out"
done
origin_flg=0
# 如果origin日志找到了则从origin日志中获取upstream和port
upstream_and_port=`cat origin.log | awk -F '"' '{print $8":"$9}' | sort | uniq`
uap=$upstream_and_port
for nhi in $upstream_and_port; do
upstream=`echo $nhi | awk -F ':' '{print $1}'`
port=`echo $nhi | awk -F ':' '{print $2}'`
ips $upstream > ips.log 2>&1
# 如果upstream是天翼的IP则输出如下
if [[ $? -eq 0 ]]; then
echo -e "${c_bp}\n[ATS-$level]: 从origin日志查询到$req_id的回上层地址是$nhi(CTC IP),继续查询...${c_e}"
cd $trash
# 如果upstream不是天翼的IP则输出如下
else
echo -e "${c_br}\n[ATS-$level]: 从origin日志查询到$req_id的回源地址$nhi不是天翼的IP可能是ATS回源了${c_e}"
echo -e "${c_bp}请确认${c_bc}$nhi${c_bp}是否是源站IP。\n${c_e}"
uap=`echo $uap | sed -n "s/$nhi//p"`
fi
done
[[ $uap == '' ]] && { echo -e "${c_bg}[IDS-117] 所有IP均已处理完毕退出...${c_e}"; exit 117; } || { upstream_and_port=$uap; cd $trash; }
# 如果origin日志也有找到记录
else
echo -e "${c_br}\n[IDS-118] [NG-ATS-$level]: 很奇怪从上层NG/ATS日志查询到$req_id的回源地址是$upstream_and_port(CTC IP)却找不到access/origin日志。可以检查一下父层对应日志是否已经被删除或者查询的日志时间是否是靠近整点例如22:59:01由于日志切割机制基于本工具的逻辑这样的日志有可能会漏掉如是这种情况请更换访问日志重新查询。\n${c_e}"
exit 118
fi
# 如果边缘机器上就找不到 NG 日志
else
echo -e "\n${c_br}[IDS-119] [NG-$level]: 无法在$label_en($edge)上找到$req_id请确认输入的request ID访问时间或者节点信息是准确的。\n${c_e}"
exit 119
fi
fi
}
#=======================================================================================
# 功能:分层级查询日志链
# 入参level, cdn_log_proc
# 出参None
function cdn_log_search() {
# 1. 搜索边缘日志
level="Edge" && cdn_log_proc $level
# 脚本运行到此处说明边缘access或者origin日志已经找到upstream_and_port也已经获得且一定是天翼IP
for nhi_e in $upstream_and_port; do
upstream=`echo $nhi_e | awk -F ':' '{print $1}'`
port=`echo $nhi_e | awk -F ':' '{print $2}'`
ips $upstream > ips.log 2>&1 && cd $trash
# 获取下一层级的 label_en这里依赖ips工具输出的格式
label_en=`cat ips.log | grep "所属资源池" | awk -F '(' '{print $2}' | awk -F ')' '{print $1}'`
width=`tput cols` && echo
for i in `seq $width`; do
echo -ne "${c_bb}=${c_e}"
done
echo -e "${c_bb}\nNext Hop IP: $nhi_e\n${c_e}"
# 2. 搜索一层父日志
level="Center" && cdn_log_proc $level
# 脚本运行到此处说明边缘access或者origin日志已经找到upstream_and_port也已经获得且一定是天翼IP
for nhi_c in $upstream_and_port; do
upstream=`echo $nhi_c | awk -F ':' '{print $1}'`
port=`echo $nhi_c | awk -F ':' '{print $2}'`
ips $upstream > ips.log 2>&1 && cd $trash
# 获取下一层级的 label_en这里依赖ips工具输出的格式
label_en=`cat ips.log | grep "所属资源池" | awk -F '(' '{print $2}' | awk -F ')' '{print $1}'`
width=`tput cols` && echo
for i in `seq $width`; do
echo -ne "${c_bb}=${c_e}"
done
echo -e "${c_bb}\nNext Hop IP: $nhi_c\n${c_e}"
# 3. 搜索二层父日志
level="Nation" && cdn_log_proc $level
# 脚本运行到此处说明边缘access或者origin日志已经找到upstream_and_port也已经获得且一定是天翼IP
for nhi_n in $upstream_and_port; do
upstream=`echo $nhi_n | awk -F ':' '{print $1}'`
port=`echo $nhi_n | awk -F ':' '{print $2}'`
ips $upstream > ips.log 2>&1 && cd $trash
# 获取下一层级的 label_en这里依赖ips工具输出的格式
label_en=`cat ips.log | grep "所属资源池" | awk -F '(' '{print $2}' | awk -F ')' '{print $1}'`
width=`tput cols` && echo
for i in `seq $width`; do
echo -ne "${c_bb}=${c_e}"
done
echo -e "${c_bb}\nNext Hop IP: $nhi_n\n${c_e}"
# 4. 未知层级 -- 容错作用
level="Unknown" && cdn_log_proc $level
# 脚本运行到此处说明边缘access或者origin日志已经找到upstream_and_port也已经获得且一定是天翼IP
for nhi_u in $upstream_and_port; do
upstream=`echo $nhi_u | awk -F ':' '{print $1}'`
port=`echo $nhi_u | awk -F ':' '{print $2}'`
ips $upstream > ips.log 2>&1 && cd $trash
# 获取下一层级的 label_en这里依赖ips工具输出的格式
label_en=`cat ips.log | grep "所属资源池" | awk -F '(' '{print $2}' | awk -F ')' '{print $1}'`
width=`tput cols` && echo
for i in `seq $width`; do
echo -ne "${c_bb}=${c_e}"
done
echo -e "${c_bb}\nNext Hop IP: $nhi_u\n${c_e}"
done
done
done
done
}
#=======================================================================================
# 功能:直播业务访问日志处理 -- all: flv, hls, rtmp
# 入参rip_list, bg_pids, current, year, month, day, hour, req_id, rbplus
# 出参access_$rip
function live_log_access() {
# 如果time_range是当前时间则搜索当前文件夹下的对应日志以及回滚日志
if [[ $current == 'yes' ]]; then
# ssh 进每一个rip搜索uni_access.log和uni_access.log_${time_range}*设定ssh连接超时时长 CT
# 把搜索的结果放进access_$rip文件所有的ssh命令都后台执行并将它们的PID存入$bg_pids
for rip in $rip_list; do
ssh -o ConnectTimeout=$CT $rip "
cat $livelog/uni_access.log* | grep $req_id" > access_${rip} 2>&1 &
bg_pids=$bg_pids' '$(jobs -p | tail -1)
done
# 如果time_range不是当前时间则搜索当前文件夹下的回滚日志以及目录下的归档日志
else
# 简单粗暴地,分别过滤回滚文件和未归档两部分日志文件,因为归档文件是奇数小时命名,所以过滤
for rip in $rip_list; do
ssh -o ConnectTimeout=$CT $rip "
cat $livelog/uni_access.log* | grep $req_id;
zcat $livelog/$dirpath/uni_access.log_${rbplus}* | grep $req_id;
zcat $livelog/$dirpath/uni_access.log_${rb}* | grep $req_id;
zcat $livelog/$dirpath/uni_access.log_${rbminus}* | grep $req_id" > access_${rip} 2>&1 &
bg_pids=$bg_pids' '$(jobs -p | tail -1)
done
fi
}
#=======================================================================================
# 功能:直播业务回源日志处理 -- flv/hls
# 入参rip_list, bg_pids, current, year, month, day, hour, req_id, rbplus
# 出参origin_$rip
function live_log_origin() {
# 如果time_range是当前时间则搜索当前文件夹下的对应日志以及回滚日志
if [[ $current == 'yes' ]]; then
# ssh进每一个 rip搜索uni_origin.log和uni_origin.log_${time_range}*设定ssh连接超时时长CT
# 把搜索的结果放进origin_$rip/ats_$rip文件所有的ssh命令都后台执行并将它们的PID存入$bg_pids
# 因为hls业务走的是点播逻辑是从ATS回源的所以为了后续方便处理直接两种情况都获取一下也不会多用多少时间
for rip in $rip_list; do
ssh -o ConnectTimeout=$CT $rip "
cat $livelog/uni_origin.log* | grep $req_id" > origin_${rip} 2>&1 &
bg_pids=$bg_pids' '$(jobs -p | tail -1)
# for hls
ssh -o ConnectTimeout=$CT $rip "
cat $liveatslog/origin.log* | grep $req_id" > ats_${rip} 2>&1 &
bg_pids=$bg_pids' '$(jobs -p | tail -1)
done
# 如果time_range不是当前时间则搜索当前文件夹下的回滚日志以及目录下的归档日志
else
# 简单粗暴地,分别过滤回滚文件和未归档两部分日志文件,因为归档文件是奇数小时命名,所以过滤
for rip in $rip_list; do
ssh -o ConnectTimeout=$CT $rip "
cat $livelog/uni_origin.log* | grep $req_id;
zcat $livelog/$dirpath/uni_origin.log_${rbplus}* | grep $req_id;
zcat $livelog/$dirpath/uni_origin.log_${rb}* | grep $req_id;
zcat $livelog/$dirpath/uni_origin.log_${rbminus}* | grep $req_id" > origin_${rip} 2>&1 &
bg_pids=$bg_pids' '$(jobs -p | tail -1)
# for hls
ssh -o ConnectTimeout=$CT $rip "
cat $liveatslog/origin.log* | grep $req_id;
zcat $liveatslog/$dirpath_ats/origin.log_${rb_ats_minus}* | grep $req_id
zcat $liveatslog/$dirpath_ats/origin.log_${rb_ats}* | grep $req_id
zcat $liveatslog/$dirpath_ats/origin.log_${rb_ats_plus}* | grep $req_id" > ats_${rip} 2>&1 &
bg_pids=$bg_pids' '$(jobs -p | tail -1)
done
fi
}
#=======================================================================================
# 功能区分直播日志格式因为不同格式上层IP以及HIT/MISS字段位置不同内部回源IP&端口位置也不同
# 功能判断是否是hls业务 | flv业务的回上层IP&端口 | hls业务的回上层IP&端口
# 入参:--ishls, --uapflv, --uaphls, access.log, origin.log
# 出参HOM, log_v, upstream, upstream_and_port, port, ishls
function log_version() {
opt=$1
log=$2
log_v=`tail -1 $log | awk -F '"' '{print $1}'`
log_v=${log_v:${#log_v}-1:1}
# 根据不同的日志版本从uni_access日志种获取回源端口进而判断是hls业务还是其他
if [[ $opt == '--ishls' ]]; then
if [[ $log_v == '1' ]]; then
upstream=`tail -1 $log | awk -F '"' '{print $30}' | awk -F':' '{print $1}'`
port=`tail -1 $log | awk -F '"' '{print $30}' | awk -F':' '{print $2}'`
elif [[ $log_v == '2' ]]; then
upstream=`tail -1 $log | awk -F '"' '{print $32}' | awk -F':' '{print $1}'`
port=`tail -1 $log | awk -F '"' '{print $32}' | awk -F':' '{print $2}'`
elif [[ $log_v == '3' ]]; then
upstream=`tail -1 $log | awk -F '"' '{print $7}'`
port=`tail -1 $log | awk -F '"' '{print $8}'`
else
echo -e "\n${c_br}[IDS-120] 未知的日志格式请联系fanmf11@chinatelecom.cn反馈...${c_e}"
exit 120
fi
[[ $port == '8080' ]] && ishls=1 || ishls=0
# 如果是flv业务根据不同的日志版本从uni_origin日志中获取回上层IP以及端口
elif [[ $opt == '--uapflv' ]]; then
if [[ $log_v == '1' ]]; then
upstream=`tail -1 $log | awk -F '"' '{print $8}' | awk -F':' '{print $1}'`
port=`tail -1 $log | awk -F '"' '{print $8}' | awk -F':' '{print $2}'`
HOM=`tail -1 $log | awk -F '"' '{print $29}'`
elif [[ $log_v == '2' ]]; then
upstream=`tail -1 $log | awk -F '"' '{print $8}'`
port=`tail -1 $log | awk -F '"' '{print $9}'`
HOM=`tail -1 $log | awk -F '"' '{print $31}'`
elif [[ $log_v == '3' ]]; then
upstream=`tail -1 $log | awk -F '"' '{print $10}'`
port=`tail -1 $log | awk -F '"' '{print $11}'`
HOM=`tail -1 $log | awk -F '"' '{print $29}'`
else
echo -e "\n${c_br}[IDS-121] 未知的日志格式请联系fanmf11@chinatelecom.cn反馈...${c_e}"
exit 121
fi
if [[ $HOM == 'HIT' ]]; then
echo -e "\n${c_big}[IDS-122] $level $log Log: 请求在该层命中,退出...${c_e}"
exit 122
fi
# 如果是hls业务日志是ov06版本的回上层IP以及端口是固定位置
elif [[ $opt == '--uaphls' ]]; then
upstream=`cat origin.log | tail -1 | awk -F '"' '{print $8}'`
port=`cat origin.log | tail -1 | awk -F '"' '{print $9}'`
upstream_and_port=${upstream}":"${port}
fi
}
#=======================================================================================
# 功能处理CDN直播的access和origin日志
# 入参access_$rip, origin_$rip, rip_list, req_id
# 出参access.log, origin.log
function log_merge() {
# 处理上述生成的rip中拿到的access和origin日志筛选出包含req_id的行
# 初始化access.log和origin.log -- 处理单个rip上生成的access/origin日志匹配req_id
# 如果找到则将对应的rip和日志内容用追加到相应日志尾部以"为分隔rip作为日志的最后一个字段
> access.log && > origin.log
for rip in $rip_list; do
cat access_$rip | grep -q $req_id
# access和origin日志的处理方式一致由于一个访问可能在边缘机器上出现多次 -- 合并回源
# 所以要检查每一个rip的日志凡是匹配到的都记录到access.log和origin.log
if [[ $? -eq 0 ]]; then
access_flg=1
cat access_$rip | grep $req_id > log
cat log | while read line; do
echo -n $line >> access.log
echo '"'$rip >> access.log
done
fi
cat origin_$rip | grep -q $req_id
if [[ $? -eq 0 ]]; then
origin_flg=1
cat origin_$rip | grep $req_id > log
cat log | while read line; do
echo -n $line >> origin.log
echo '"'$rip >> origin.log
done
fi
# 检查是否有 ssh 连接失败的情况,有的话,打印出来
cat access.log | grep -iq 'Connection timed out during banner exchange'
[[ $? -eq 0 ]] && { echo -e "${c_br}[NG-$level] SSH Connection Failed:${c_e}"; echo $rip; }
cat origin.log | grep -iq 'Connection timed out during banner exchange'
[[ $? -eq 0 ]] && { echo -e "${c_br}[ATS-$level] SSH Connection Failed:${c_e}"; echo $rip; }
done
}
#=======================================================================================
# 功能获取直播网关日志搜索处理每一层级的live日志
# 入参level, label_en, current, year, month, day, hour
# 出参upstream, upstream_port
function live_log_proc() {
# 获取 rip 列表,并初始化 bg_pids 数组
rip_list=`cat $data/ip.group | grep $label_en | awk '{print $1}' | sort | uniq`
bg_pids=''
dirpath="$year-$month-$day"
dirpath_ats="$year$month$day"
rb="$year-$month-$day-$hour"
rb_ats="$year$month$day$hour"
# 直播归档日志规则:偶数小时的日志归档到相邻较大的奇数小时命名的日志中
# 所以如果是过去时间hour 是偶数,则加一,如果是奇数,则保持
# 这里奇数的时候设置成"KEEP"字符串,为的是简化搜索逻辑,避免更多的判断分支
let clock=`echo "obase=10; $hour" | bc`
hourplus=`printf "%02d" $((clock+1))`
hourminus=`printf "%02d" $((clock-1))`
# [[ $((clock%2)) -eq 1 ]] && rbplus=$rb || rbplus="$year-$month-$day-$hourplus"
rbplus="$year-$month-$day-$hourplus"
rbminus="$year-$month-$day-$hourminus"
rb_ats_minus="$year$month$day$hourminus"
rb_ats_plus="$year$month$day$hourplus"
# access日志/home/log/cluster_live_log/uni_access.log
live_log_access "$rip_list" "$bg_pids" "$current" "$year" "$month" "$day" "$hour" "$req_id" $rbplus
# origin日志/home/log/cluster_live_log/uni_origin.log
live_log_origin "$rip_list" "$bg_pids" "$current" "$year" "$month" "$day" "$hour" "$req_id" $rbplus
# 动态进度条
progress "${bg_pids}" $level &
progress_pid=$(jobs -p | tail -1)
# 等待所有 bg_pids 存储的后台进程执行完毕
wait
echo -ne "${c_bic}$level Data collected.${c_e}"
echo -ne " "
# -------------------------------------------------------------------------
# 处理上述生成的rip中拿到的access和origin日志筛选出包含req_id的行
# 初始化access.log和origin.log -- 处理单个rip上生成的access/origin日志匹配req_id
# 如果找到则将对应的rip和日志内容用追加到相应日志尾部以"为分隔rip作为日志的最后一个字段
log_merge $rip_list $req_id
# 判断是否是hls或者ts业务
if [[ $access_flg -eq 1 ]]; then
cat access.log | sort -t'"' -n -k2 -k6 > log && mv log access.log
log_version --ishls access.log
if [[ $ishls -eq 1 ]]; then
for rip in $rip_list; do
cp ats_$rip origin_$rip
done
# 重新做一次日志整理
log_merge $rip_list $req_id
fi
fi
# 如果是hls或者ts业务
if [[ $ishls -eq 1 ]]; then
# 如果找到了access日志则过滤打印输出并将access_flg重置
if [[ $access_flg -eq 1 ]]; then
cat access.log | sort -t'"' -n -k2 -k6 > log && mv log access.log
# 按时间排序,打印找到的所有日志内容
cat access.log | while read line; do
access_ip=`echo $line | awk -F'"' '{print $NF}'`
echo -e "${c_big}\n$level Access Log:${c_by} searching $label_en ...... $access_ip${c_e}"
out=${line%\"*}
log_format "$out"
done
access_flg=0
log_version --uapflv access.log
# 找到了origin日志则过滤打印输出并将origin_flg重置
if [[ $origin_flg -eq 1 ]]; then
cat origin.log | sort -t'"' -n -k43 > log && mv log origin.log
cat origin.log | while read line; do
origin_ip=`echo $line | awk -F'"' '{print $NF}'`
echo -e "${c_big}\n$level Origin Log:${c_by} searching $label_en ...... $origin_ip${c_e}"
out=${line%\"*}
log_format "$out"
done
origin_flg=0
log_version --uaphls origin.log
# 没有找到origin日志
else
echo -e "\n${c_br}[IDS-123] [Origin-$level]: 很奇怪Access未命中也无法在$label_en上找到$req_id请联系fanmf11@chinatelecom.cn排查未知的场景。\n${c_e}"
exit 123
fi
# 如果边缘Access没有找到request id对应的日志信息
else
echo -e "\n${c_br}[IDS-124] [ACCESS-$level]: 无法在$label_en($edge)上找到$req_id请确认输入的request ID访问时间或者节点信息是准确的。\n${c_e}"
exit 124
fi
# 如果不是hls而是rtmp或者flv业务
else
# 如果找到了access日志则过滤打印输出并将access_flg重置
if [[ $access_flg -eq 1 ]]; then
cat access.log | sort -t'"' -n -k2 -k6 > log && mv log access.log
# 按时间排序,打印找到的所有日志内容
cat access.log | while read line; do
access_ip=`echo $line | awk -F'"' '{print $NF}'`
echo -e "${c_big}\n$level Access Log:${c_by} searching $label_en ...... $access_ip${c_e}"
out=${line%\"*}
log_format "$out"
done
access_flg=0
log_version --uapflv access.log
# 找到了origin日志则过滤打印输出并将origin_flg重置
if [[ $origin_flg -eq 1 ]]; then
cat origin.log | sort -t'"' -n -k2 -k6 > log && mv log origin.log
cat origin.log | while read line; do
origin_ip=`echo $line | awk -F'"' '{print $NF}'`
echo -e "${c_big}\n$level Origin Log:${c_by} searching $label_en ...... $origin_ip${c_e}"
out=${line%\"*}
log_format "$out"
done
origin_flg=0
# 如果origin日志找到了则从origin日志中获取upstream和port
log_version --uapflv origin.log
# 没有找到origin日志则考虑是不是合并回源导致request id变了针对合并回源的情况需要在合并回源的机器上查找uni_rtmp_monitor.log日志从中拿到relay session id在过滤error.log匹配relay session和字符'request_id'
else
echo -e "\n${c_bib}稍等,正在处理其他信息,可能需要一些时间...${c_e}"
# 要取按时间排序的最后一条日志,如果有合并回源,则合并到该节点了
merge_ip=`cat access.log | tail -1 | awk -F'"' '{print $NF}'`
# echo merge ip = $merge_ip
# 找到relay session id
ssh -o ConnectTimeout=$CT $merge_ip "
cat $livelog/uni_rtmp_monitor.log* | grep $req_id;
zcat $livelog/$dirpath/uni_rtmp_monitor.log_${rbplus}* | grep $req_id;
zcat $livelog/$dirpath/uni_rtmp_monitor.log_${rb}* | grep $req_id;
zcat $livelog/$dirpath/uni_rtmp_monitor.log_${rbminus}* | grep $req_id;" > monitor.log 2>&1
relay_id=`cat monitor.log | grep $req_id | head -n 1 | awk -F'"' '{print $14}'`
[[ $relay_id == '' ]] && { echo -e "${c_br}[IDS-125] 无法找到relay session需确认uni_rtmp_monitor是否开启或者手动查询...${c_e}"; exit 125; }
# echo relay id = $relay_id
# 找合并回源的request id
ssh -o ConnectTimeout=$CT $merge_ip "
cat $livelog/error.log* | grep $relay_id;
zcat $livelog/$dirpath/error.log_${rbplus}* | grep $relay_id;
zcat $livelog/$dirpath/error.log_${rb}* | grep $relay_id;
zcat $livelog/$dirpath/error.log_${rbminus}* | grep $relay_id" > error.log 2>&1
cat error.log | grep 'request_id' | head -n 1 > log && mv log error.log
[[ `cat error.log | wc -l` -eq 0 ]] && { echo -e "${c_br}[IDS-126] 无法找到合并回源记录,退出...${c_e}"; exit 126; }
req_id_new=`cat error.log | awk '{for(i=1;i<=NF;i++) print $i}' | grep -E "^request_id" | tr -d '"' | awk -F ':' '{print $2}'`
# echo request id = $req_id_new
if [[ $req_id_new == $req_id ]]; then
upper_inner=`cat error.log | awk '{for(i=1;i<=NF;i++) print $i}' | grep -E "^peer:" | tr -d '"' | awk -F ':' '{print $2}'`
if [[ $upper_inner == 'unix' ]]; then
merger_ip=$merge_ip
flg=1
else
ips -m $merge_ip > inner_ip.log
merge_ip=`cat inner_ip.log | grep -w "$upper_inner" | awk '{print $1}'`
fi
# echo upper_inner = $upper_inner
# echo merge_ip = $merge_ip
ssh -o ConnectTimeout=$CT $merge_ip "
cat $livelog/error.log* | grep $req_id;
zcat $livelog/$dirpath/error.log_${rbplus}* | grep $req_id;
zcat $livelog/$dirpath/error.log_${rb}* | grep $req_id;
zcat $livelog/$dirpath/error.log_${rbminus}* | grep $req_id;" > error.new 2>&1
cat error.new | grep -E "found dummy_session:.* is already pulling" | head -n 1 > log && mv log error.new
[[ `cat error.new | wc -l` -eq 0 ]] && { echo -e "${c_br}[IDS-127] 无法找到合并回源记录,退出...${c_e}"; exit 127; }
relay_id=`cat error.new | awk '{for(i=1;i<=NF;i++) print $i}' | grep -E "^dummy_session" | awk -F ':' '{print $2}' | tr -d '"'`
# echo relay id new = $relay_id
ssh -o ConnectTimeout=$CT $merge_ip "
cat $livelog/error.log* | grep $relay_id;
zcat $livelog/$dirpath/error.log_${rbplus}* | grep $relay_id;
zcat $livelog/$dirpath/error.log_${rb}* | grep $relay_id;
zcat $livelog/$dirpath/error.log_${rbminus}* | grep $relay_id;" > error.relay 2>&1
cat error.relay | grep -E "ngx_rtmp_pull_create_task.*request_id" | sort | head -n 1 > log && mv log error.relay
[[ `cat error.relay | wc -l` -eq 0 ]] && { echo -e "${c_br}[IDS-128] 无法找到合并回源记录,退出...${c_e}"; exit 128; }
req_id=`cat error.relay | awk '{for(i=1;i<=NF;i++) print $i}' | grep -E "^request_id" | tr -d '"' | awk -F ':' '{print $2}'`
else
req_id=$req_id_new
fi
# echo request id = $req_id
# echo merge_ip = $merge_ip
# 继续在 merge ip 上查找新的 request id 对应的 Origin 日志其实应该是在rip_list里查询
live_log_origin "$rip_list" "$bg_pids" "$current" "$year" "$month" "$day" "$hour" "$req_id" $rbplus
wait
log_merge $rip_list $req_id
cat origin.log | grep -q $req_id
# 判断是否找到新的 request id 相关日志
if [[ $? -eq 0 ]]; then
echo -e "${c_bib}找到了合并回源新的 request id: $req_id - 后续将使用该 ID 继续搜索${c_e}"
cat origin.log | grep $req_id | sort -t'"' -n -k2 -k6 > log && mv log origin.log
cat origin.log | while read line; do
echo -e "${c_big}\n$level Origin Log:${c_by} searching $label_en ...... $merge_ip${c_e}"
out=${line}
log_format "$out"
done
origin_flg=0
# 如果 Origin 日志找到了,则从日志中获取 upstream ip 和 port
log_version --uapflv origin.log
# 没找到,则输出提示信息
else
echo -e "${c_bp}\n[IDS-129] [ORIGIN-$level]: 回上层IP是$upstream:$port在uni_origin.log中未查询到$req_id,退出...${c_e}"
exit 129
fi
fi
# 如果边缘Access没有找到request id对应的日志信息
else
echo -e "\n${c_br}[IDS-130] [ACCESS-$level]: 无法在$label_en($edge)上找到$req_id请确认输入的request ID访问时间或者节点信息是准确的。\n${c_e}"
exit 130
fi
fi
}
#=======================================================================================
# 功能:分层级查询日志链
# 入参level, live_log_proc
# 出参None
function live_log_search() {
# ----------------------------------------------------------------------------
# 1. 边缘日志搜索处理
level="Edge" && live_log_proc $level
# 脚本运行到此处说明access/origin日志可能都已经找到upstream和prot也已经获得需要检查upstream是否是天翼 IP
ips $upstream > ips.log 2>&1
# 如果不是天翼IP则表示该IP可能是源站地址
[[ $? -ne 0 ]] && { echo -e "${c_bp}\n[IDS-131] 请确认${c_bc} $upstream:$port ${c_bp}是否是源站地址。\n${c_e}"; exit 131; } || cd $trash
# 如果是天翼IP则表示下一层级还会有相关日志所以需要找到下一层级的label_en以及对应的rip
label_en=`cat ips.log | grep "所属资源池" | awk -F '(' '{print $2}' | awk -F ')' '{print $1}'`
width=`tput cols` && echo
for i in `seq $width`; do
echo -ne "${c_bb}=${c_e}"
done
echo -e "\n${c_bb}Next Hop IP: $upstream:$port\n${c_e}"
# ----------------------------------------------------------------------------
# 2. 父层日志搜索处理
level="Center" && live_log_proc $level
# 脚本运行到此处说明access/origin日志可能都已经找到upstream和prot也已经获得需要检查upstream是否是天翼 IP
ips $upstream > ips.log 2>&1
# 如果不是天翼 IP则表示该 IP 可能是源站地址
[[ $? -ne 0 ]] && { echo -e "${c_bp}\n[IDS-132] 请确认${c_bc} $upstream:$port ${c_bp}是否是源站地址。\n${c_e}"; exit 132; } || cd $trash
# 如果是天翼IP则表示下一层级还会有相关日志所以需要找到下一层级的label_en以及对应的rip
label_en=`cat ips.log | grep "所属资源池" | awk -F '(' '{print $2}' | awk -F ')' '{print $1}'`
width=`tput cols` && echo
for i in `seq $width`; do
echo -ne "${c_bb}=${c_e}"
done
echo -e "\n${c_bb}Next Hop IP: $upstream:$port\n${c_e}"
# ----------------------------------------------------------------------------
# 3. 中心日志搜索处理
level="Nation" && live_log_proc $level
# 脚本运行到此处说明access/origin日志可能都已经找到upstream和prot也已经获得需要检查upstream是否是天翼 IP
ips $upstream > ips.log 2>&1
# 如果不是天翼 IP则表示该 IP 可能是源站地址
[[ $? -ne 0 ]] && { echo -e "${c_bp}\n[IDS-133] 请确认${c_bc} $upstream:$port ${c_bp}是否是源站地址。\n${c_e}"; exit 133; } || cd $trash
# 如果是天翼IP则表示下一层级还会有相关日志所以需要找到下一层级的label_en以及对应的rip
label_en=`cat ips.log | grep "所属资源池" | awk -F '(' '{print $2}' | awk -F ')' '{print $1}'`
width=`tput cols` && echo
for i in `seq $width`; do
echo -ne "${c_bb}=${c_e}"
done
echo -e "\n${c_bb}Next Hop IP: $upstream:$port\n${c_e}"
# ----------------------------------------------------------------------------
# 4. 容错日志搜索处理
level="Unknown" && live_log_proc $level
# 脚本运行到此处说明access/origin日志可能都已经找到upstream和prot也已经获得需要检查upstream是否是天翼 IP
ips $upstream > ips.log 2>&1
# 如果不是天翼 IP则表示该 IP 可能是源站地址
[[ $? -ne 0 ]] && { echo -e "${c_bp}\n[IDS-134] 请确认${c_bc} $upstream:$port ${c_bp}是否是源站地址。\n${c_e}"; exit 134; } || cd $trash
# 如果是天翼IP则表示下一层级还会有相关日志所以需要找到下一层级的label_en以及对应的rip
label_en=`cat ips.log | grep "所属资源池" | awk -F '(' '{print $2}' | awk -F ')' '{print $1}'`
width=`tput cols` && echo
for i in `seq $width`; do
echo -ne "${c_bb}=${c_e}"
done
echo -e "\n${c_bb}Next Hop IP: $upstream:$port\n${c_e}"
}
#=======================================================================================
# 功能:格式化输出日志,使其字段更容易看懂,输入第一个参数是日志全文
# 入参access.log, origin.log, v03, ov06, OUT_ACC1, OUT_ACC2, OUT_ACC3, OUT_ORI1, OUT_ORI2
# 出参:格式化输出
function log_format() {
log=$1
log_v=`echo $log | awk -F '"' '{print $1}'`
log_fs='v03 ov06 OUT_ACC1 OUT_ACC2 OUT_ACC3 IN_ACC1 IN_ACC2 IN_ACC3 OUT_ORI1 OUT_ORI2 OUT_ORI3 IN_ORI1 IN_ORI2 IN_ORI3'
for log_f in $log_fs; do
if [[ $log_v == $log_f ]]; then
eval log_f=\$$log_f
echo $log_f | awk -F '"' '{for(i=1;i<=NF;i++) printf "%s %s\"", "\033[1;3;36m"i"\033[0m", $i} END{print ""}'
fi
done
width=`tput cols`
echo -n " "
for i in `seq $((width-8))`; do
echo -ne "${c_bip}^${c_e}"
done
echo -n " "
echo $log | awk -F '"' '{for(i=1;i<=NF;i++) printf "%s %s\"", "\033[1;3;36m"i"\033[0m", $i} END{print ""}'
}
function logfile() {
if [[ -d $trash ]]; then
echo -e "${c_br}[IDS-135] 对于同一个用户,同一时间只能运行一个实例,请重新运行...${c_e}"
exit 135
else
mkdir -p $trash
cd $trash && cd ..
docs=`ls`
for doc in $docs; do
[[ -f $doc ]] && rm -rf $doc
done
folders=`ls -t`
while [[ `echo $folders | awk '{print NF}'` -gt 29 ]]; do
folder=`ls -t | tail -1`
rm -rf $folder
folders=`ls -t`
done
cd $trash && touch ids
fi
}
# ----------------------------------------------------------------------------
# 自定义颜色显示
c_br='\e[1;31m' # bold red
c_bg='\e[1;32m' # bold green
c_by='\e[1;33m' # bold yellow
c_bb='\e[1;34m' # bold blue
c_bp='\e[1;35m' # bold purple
c_bc='\e[1;36m' # bold cyan
c_bir='\e[1;3;31m' # * bold italic red
c_big='\e[1;3;32m' # bold italic cyan
c_bib='\e[1;3;34m' # * bold italic cyan
c_bip='\e[1;3;35m' # bold italic cyan
c_bic='\e[1;3;36m' # bold italic cyan
c_e='\e[0m' # reset
# some initializing action
TS=`date +%s%N` # *
ts=`date +%s` # *
stty erase '^H' # * 允许回退键删除内容
req_id='' # * 接收入参
year=0 # * year
month=0 # * month
day=0 # * day
hour=0 # * hour
label_en='' # * 节点英文标签
number=0 # * label_en 中的行数
label='' # single label name in English
prod_type=1 # * 产品类型
flg=0 # signify if get CTC group successfully, 0 - NG and 1 - OK
access_flg=0 # * 是否在access日志中找到reqid0表示未找到1表示找到了
origin_flg=0 # * 是否在origin日志中找到reqid0表示未找到1表示找到了
time_range='' # * input: the specified time to search logs
range_d=0 # * days between now and time_range
range_s=0 # * seconds between now and time_range
current='yes' # * 判断输入的时间是否是当前时间默认是yes
CT=60 # * ssh connection timeout
bg_pids='' # * pid lists which run in background
cdn_access_log='/home/log/cluster_gateway_log' # *
cdn_origin_log='/home/log/trafficserver' # *
toolbox='/usr/local/script/fanmf11' # *
data='/usr/local/script/fanmf11/data' # *
host=`whoami` # * 判断执行用户
trash="/usr/local/script/fanmf11/trash/$host/$TS" # * 每个用户的临时文件存放处
access_ip='0.0.0.0'
origin_ip='0.0.0.0'
upstream='0.0.0.0'
port='0'
upstream_and_port='0.0.0.0:0'
livelog='/home/log/cluster_live_log'
liveatslog='/home/log/trafficserver'
v03='$version"$timeLocal"$request_id"$httpCode"$timestamp"$respondTime"$rwt_time"$wwt_time"$firstDur"$finalize_error_code"$serverIp"$destPort"$clientIp"$clientPort"$method"$protocol"$channel"$url"$httpVersion"$requestBytes"$sent_http_content_length"$bodyBytes"$body_sent"$upstreamAddr"$upstream_status"$mesc"$status"$upstreamIp"$upstream_http_ctl_server_code"$httpRange"$sent_http_content_range"$fileType"$referer"$Ua"$proxyIp"$content_type"$fft_time"$via"$real_client_ip"$attack_type"$dysta"$request_body_length"$ssl_time"$extra1"$extra2"$extra3"$extra4"$extra5"$extra6"$extra7"$extra8"$extra9"$extra10"$extra11"$extra12"$extra13"$extra14"$extra15"$extra16"$extra17"$extra18"$extra19"$extra20"$extra21"$extra22"$extra23"$extra24"$extra25"$extra26"$extra27"$extra28"$extra29"$extra30"$extra31"$extra32"$extra33"$extra34"$extra35"$extra36"$extra37"$extra38"$extra39"$extra40"$extra41"$extra42"$extra43"$extra44"$extra45"$extra46"$extra47"$extra48"$extra49"$extra50"$ex1"$ex2"$ex3"$ex4"$ex5"$ex6"$ex7"$ex8"$ex9"$ex10"$ex11"$ex12"$ex13"$ex14"$ex15"$ex16"$ex17"$ex18"$ex19"$ex20"$ex21"$ex22"$ex23"$ex24"$ex25"$ex26"$ex27"$ex28"$ex29"$ex30"$ex31"$ex32"$ex33"$ex34"$ex35"$ex36"$ex37"$ex38"$ex39"$ex40"$ex41"$ex42"$ex43"$ex44"$ex45"$ex46"$ex47"$ex48"$ex49"$ex50'
ov06='$version"$cqtn"$request_id"$sct"$firstDur"$mesc_milisecond"$clientIp"$nhi"$nhp"$httpCode"$pssc"$cquup"$bodyBytes"$sscl"$rwtms"$sec"$Range_cqh"$Content-Range_psh"$If-Modified-Since_psh"$If-Range_psh"$Via_psh"$dqrtt"$dqrcd"$dqnst"$Host_pqh"$pqsn"$cwr"$pls"$X-Forwarded-For_pqh"$requestBytes"$cqhl"$pqhl"$cqhm"$httpVersion"$Referer_pqh"$User-Agent_pqh"$Cookie_pqh"$serverIp"$pqsp"$protocol"$Content-Type_psh"$Last-Modified_psh"$timestamp"$channel"$server_ssh"$cqtx"$sent_http_content_length"$oqup"$oquq"$accid"$extra2"$extra3"$extra4"$extra5"$extra6"$extra7"$extra8"$extra9"$extra10"$extra11"$extra12'
OUT_ACC1='$version"$protocol"$connect_type"$request_from"$requestTime"$timestamp"$respondTime"$clientIpPort"$connect_time"$publish_play_time"$firstDur"$tcpinfo_rtt"$tcpinfo_rttvar"$proxyIp"$method"$channel"$uri"$appName"$stream"$httpVersion"$url"$httpCode"$recvBytes"$bodyBytes"$upstream_bytes_sent"$upstream_bytes_received"$destIpPort"$hostname"$status"$upstreamAddr"$playDur"$remote_user"$referer"$Ua"$fileType"$httpRange"$http_cookie"$connTag"$firstTag"$connect_status"$ex1"$ex2"$ex3"$ex4"$ex5"$ex6"$ex7"$ex8"$ex9"$ex10"$ex11"$ex12"$ex13"$ex14"$ex15"$ex16"$ex17"$ex18"$ex19"$ex20"$ex21"$ex22"$ex23"$ex24"$ex25'
OUT_ACC2='$version"$protocol"$connect_type"$request_from"$requestTime"$timestamp"$respondTime"$clientIp"$clientPort"$connect_time"$publish_play_time"$firstDur"$tcpinfo_rtt"$tcpinfo_rttvar"$proxyIp"$method"$channel"$uri"$appName"$stream"$httpVersion"$url"$httpCode"$recvBytes"$bodyBytes"$upstream_bytes_sent"$upstream_bytes_received"$serverIp"$destPort"$hostname"$status"$upstreamAddr"$playDur"$remote_user"$referer"$Ua"$fileType"$httpRange"$http_cookie"$request_id"$firstTag"$connect_status"$time_local"$server_rip"$rwt_time"$wwt_time"$relay_url"$session_id"$finalize_error_code"$body_bytes_sent"$response_header_len"$request_body_len"$request_header_len"$sent_http_content_length"$upstream_response_time"$sdtfrom"$ext1"$ext2"$ext3"$ext4"$ext5"$ext6"$ext7"$ext8"$ext9"$ext10"$ext11"$ext12"$ext13"$ext14"$ext15"$ext16"$ext17"$ext18"$ext19"$ext20"$ext21"$ext22"$ext23"$ext24"$ext25"$ex1"$ex2"$ex3"$ex4"$ex5"$ex6"$ex7"$ex8"$ex9"$ex10"$ex11"$ex12"$ex13"$ex14"$ex15"$ex16"$ex17"$ex18"$ex19"$ex20"$ex21"$ex22"$ex23"$ex24"$ex25'
OUT_ACC3='$version"$timestamp"$protocol"$connect_type"$request_from"$hostname"$serverIp"$destPort"$requestTime"$clientIp"$clientPort"$method"$url"$uri"$channel"$appName"$stream"$httpVersion"$httpCode"$respondTime"$recvBytes"$bodyBytes"$upstream_bytes_sent"$upstream_bytes_received"$response_header_len"$body_bytes_sent"$request_header_len"$request_body_len"$status"$firstDur"$tcpinfo_rtt"$tcpinfo_rttvar"$proxyIp"$referer"$Ua"$fileType"$httpRange"$http_cookie"$firstTag"$finalize_error_code"$request_id"$ext1"$ext2"$ext3"$ext4"$ext5"$ext6"$ext7"$ext8"$ext9"$ext10"$ext11"$ext12"$ext13"$ext14"$ext15"$ext16"$ext17"$ext18"$ext19"$ext20"$ext21"$ext22"$ext23"$ext24"$ext25"$ex1"$ex2"$ex3"$ex4"$ex5"$ex6"$ex7"$ex8"$ex9"$ex10"$ex11"$ex12"$ex13"$ex14"$ex15"$ex16"$ex17"$ex18"$ex19"$ex20"$ex21"$ex22"$ex23"$ex24"$ex25'
IN_ACC1=$OUT_ACC1 && IN_ORI1=$OUT_ACC1 && OUT_ORI1=$OUT_ACC1
IN_ACC2=$OUT_ACC2 && IN_ORI2=$OUT_ACC2 && OUT_ORI2=$OUT_ACC2
IN_ACC3=$OUT_ACC3 && IN_ORI3=$OUT_ACC3 && OUT_ORI3=$OUT_ACC3
# ----------------------------------------------------------------------------
# 正常退出时触发
trap 'onExit' EXIT
# 捕获Ctrl+C时触发
trap 'onCtrlC' INT
# ----------------------------------------------------------------------------
# 只接收一个入参
if [[ $# -ne 1 ]]; then
echo -e "${c_bc}[IDS-136] 该脚本工具只接收一个参数——request ID作为入参示例如下 ${c_e}"
echo -e "${c_big}1. ids 30b4876065d0be98199db0525530af39 ${c_e}"
echo -e "${c_big}2. ids 63f72079_zj-jiaxing2-13_da2daa84cd2498ae - less than 64bits \n${c_e}"
echo -e "${c_br}注意:对于靠近整点(例如22:59:01)的日志,查询可能遭遇失败,对应情形可更换日志重新查询\n${c_e}"
exit 136
fi
req_id=$1 && logfile
echo $req_id | grep -Eq '_'
# 新款request id
if [[ $? -eq 0 ]]; then
# 获取$label_en, $time_range
node_time_new
# 功能检查输入的时间范围是否符合格式要求14天内不能是未来时间10位数字
# 入参time_range
# 出参current, year, month, day, hour
time_check $time_range
# 功能:获取 prod_type - 产品类型
# 入参None
# 出参TS, prod_type
prod_type_inp
if [[ $prod_type == '1' ]]; then
# 利用$label_en查找日志链
cdn_log_search
elif [[ $prod_type == '2' ]]; then
echo -e "${c_br}[IDS-137] 还未支持,退出...${c_e}"
exit 137
elif [[ $prod_type == '3' ]]; then
echo -e "${c_br}[IDS-138] 还未支持,退出...${c_e}"
exit 138
elif [[ $prod_type == '4' ]]; then
echo -e "${c_br}[IDS-139] 还未支持,退出...${c_e}"
exit 139
elif [[ $prod_type == '5.1' ]]; then
echo -e "${c_br}[IDS-140] 还未支持,退出...${c_e}"
exit 140
elif [[ $prod_type == '5.2' ]]; then
echo -e "${c_br}[IDS-141] 还未支持,退出...${c_e}"
exit 141
elif [[ $prod_type == '5.3' ]]; then
echo -e "${c_br}[IDS-142] 还未支持,退出...${c_e}"
exit 142
elif [[ $prod_type == '5.4' ]]; then
echo -e "${c_br}[IDS-143] 还未支持,退出...${c_e}"
exit 143
elif [[ $prod_type == '5.5' ]]; then
echo -e "${c_br}[IDS-144] 还未支持,退出...${c_e}"
exit 144
elif [[ $prod_type == '5.6' ]]; then
echo -e "${c_br}[IDS-145] 还未支持,退出...${c_e}"
exit 145
elif [[ $prod_type == '5.7' ]]; then
echo -e "${c_br}[IDS-146] 还未支持,退出...${c_e}"
exit 146
else
echo -e "${c_br}[IDS-147] 请按照如上提示,输入正确的产品类型序号,退出...${c_e}"
exit 147
fi
# 老款request id
else
# 功能适用于旧版本的reqID获取$label_en和$time_range
# 入参None
# 出参time_range, label_en, edge
node_time_old
# 功能检查输入的时间范围是否符合格式要求14天内不能是未来时间10位数字
# 入参time_range
# 出参current, year, month, day, hour
time_check $time_range
# 功能:获取 prod_type - 产品类型
# 入参None
# 出参TS, prod_type
prod_type_inp
if [[ $prod_type == '1' ]]; then
# 功能:分层级查询日志链
# 入参level, cdn_log_proc
# 出参None
cdn_log_search
elif [[ $prod_type == '2' ]]; then
live_log_search
elif [[ $prod_type == '3' ]]; then
echo -e "${c_br}[IDS-148] 还未支持,退出...${c_e}"
exit 148
elif [[ $prod_type == '5.1' ]]; then
cdn_log_search
elif [[ $prod_type == '5.2' ]]; then
cdn_log_search
elif [[ $prod_type == '5.3' ]]; then
cdn_log_search
elif [[ $prod_type == '5.4' ]]; then
cdn_log_search
elif [[ $prod_type == '5.5' ]]; then
cdn_log_search
elif [[ $prod_type == '5.6' ]]; then
cdn_log_search
elif [[ $prod_type == '5.7' ]]; then
cdn_log_search
else
echo -e "${c_br}[IDS-149] 请按照如上提示,输入正确的产品类型序号,退出...${c_e}"
exit 149
fi
fi