使用parallel命令异步解析大日志文件的脚本问题求助
日志批量排查脚本问题排查与修复
背景信息
日志格式
日志每行格式如下:
[01/18/2024 23:59:58 job100305.mydomain.com dbmy.db18.import 3823039] {"PREFIX":"ZaoBzgriEBMAIglWABgEZg","LEVEL":"info","MESSAGE":"received\n"} [01/18/2024 23:59:58 job100129.mydomain.com db.db5.my-route 2423585] {"ELAPSED":"0.036","PREFIX":"ZaoBzgriFH4AJIMBAALvAw","LEVEL":"info","MESSAGE":"finished in 0.036\n","ROUTINGKEY":"mydomain11016.Interface.DistributeManager.InboundDistributor.RemotePutMessageBatch"}
日志文件命名规则
按小时拆分,单个文件约4TB:
mylog-2024-01-19_00001 mylog-2024-01-19_00002 ... mylog-2024-01-19_00023
集群配置
可无密码访问dev1.mydomain.com至dev10.mydomain.com共10台服务器,家目录下sshloginfile配置每台服务器运行4线程:
4/ dev1.mydomain.com 4/ dev2.mydomain.com ... 4/ dev10.mydomain.com
需求
编写Shell脚本用parallel异步执行grep,满足:
- 每个日志文件对应一个parallel进程
- 所有结果汇总到单个文件
- 单日日志由同一台dev服务器处理
- 支持解析指定日期范围内的所有日志
- 每台服务器同时运行4线程
问题:自行编写的脚本无输出
用户脚本如下:
#!/bin/bash log_directory="/path/to/log/files" directory start_date="2024-01-19" end_date="2024-01-19" output_file="parsed_logs.txt" for log_file in $(ls $log_directory/mylog-$start_date*); do date_part=$(echo $log_file | grep -oP '\d{4}-\d{2}-\d{2}') if [[ "$date_part" >= "$start_date" && "$date_part" <= "$end_date" ]]; then dev_server=$(grep "$date_part" ~/sshlogins | awk '{print $2}') parallel --sshloginfile ~/sshlogins -S $dev_server -j4 "grep 'your_search_pattern' {} >> $output_file" ::: $log_file fi done echo "Parsing completed. Results are stored in $output_file."
问题排查与修复
1. 语法错误:变量定义冗余
第一行变量定义多了无关的directory,应修正为:
log_directory="/path/to/log/files"
2. 日期-服务器映射逻辑缺失
脚本中用grep "$date_part" ~/sshlogins匹配服务器,但sshloginfile里没有日期信息,无法实现单日日志绑定固定服务器的需求。可以通过日期哈希取模的方式分配:
# 计算日期对应的服务器索引(1-10) date_hash=$(echo "$date_part" | md5sum | cut -c1-2) server_index=$((16#$date_hash % 10 + 1)) dev_server="dev${server_index}.mydomain.com"
3. 远程输出路径错误
原脚本中远程执行grep时直接追加到$output_file,会把结果写到远程服务器的对应路径,而非本地。需要将远程grep的结果传回本地追加:
parallel --sshloginfile ~/sshlogins -S $dev_server -j4 "grep 'your_search_pattern' {}" ::: $log_file >> $output_file
4. 遍历文件方式不可靠
用ls遍历文件会遇到文件名含空格等特殊字符的问题,改用通配符安全遍历:
for log_file in "${log_directory}"/mylog-*; do # 提取日期部分 date_part=$(basename "$log_file" | grep -oP '\d{4}-\d{2}-\d{2}') # ...后续逻辑 done
5. Parallel参数冗余
--sshloginfile已经包含每台服务器的线程数配置,无需重复指定-j4,保持参数一致即可。
修正后的完整脚本
#!/bin/bash log_directory="/path/to/log/files" start_date="2024-01-19" end_date="2024-01-19" output_file="parsed_logs.txt" search_pattern="your_search_pattern" # 清空输出文件(可选,按需保留) > "$output_file" # 遍历所有日志文件 for log_file in "${log_directory}"/mylog-*; do # 提取日期部分 date_part=$(basename "$log_file" | grep -oP '\d{4}-\d{2}-\d{2}') if [[ -z "$date_part" ]]; then continue fi # 判断日期是否在指定范围内 if [[ "$date_part" < "$start_date" || "$date_part" > "$end_date" ]]; then continue fi # 给单日日志分配固定服务器(哈希取模绑定10台机器) date_hash=$(echo "$date_part" | md5sum | cut -c1-2) server_index=$((16#$date_hash % 10 + 1)) dev_server="dev${server_index}.mydomain.com" # 用parallel在指定服务器执行grep,结果追加到本地输出文件 parallel --sshloginfile ~/sshlogins -S "$dev_server" "grep '$search_pattern' {}" ::: "$log_file" >> "$output_file" done echo "Parsing completed. Results are stored in $output_file."
内容的提问来源于stack exchange,提问作者tuxian
相关产品推荐
相关产品推荐

