如何用Shell常用工具实现带时间戳记录的输出监控程序?
用Shell工具实现二进制输出监控与时间戳记录
完全可以用Shell常用工具(bash、dd、date、sleep)实现这个需求,以下是具体解决方案:
核心逻辑
- 透明转发应用的二进制输出到stdout,同时监控输出状态
- 首次收到输出时记录起始时间戳,启动后台定时器验证是否持续输出满3秒,满足则写入日志
- 每次收到新输出时重置静默定时器,当静默超过5秒时记录结束时间戳
- 用陷阱处理确保脚本退出时清理后台进程,避免残留
监控脚本实现
保存以下内容为monitor脚本,赋予执行权限:
#!/bin/bash # 可配置参数 MIN_ACTIVE=3 # 触发记录的最小持续输出时长(秒) SILENCE_THRESH=5 # 判定输出结束的静默时长(秒) LOG_DEST="${MONITOR_LOG:-/dev/stderr}" # 日志输出位置,默认stderr,可通过环境变量指定 # 状态追踪变量 start_epoch="" timer_pid="" # 退出清理函数 cleanup() { [ -n "$timer_pid" ] && kill "$timer_pid" 2>/dev/null # 若存在未收尾的输出周期,补录结束时间 [ -n "$start_epoch" ] && echo "End: $(date +'%d.%m - %H:%M:%S')" >> "$LOG_DEST" exit 0 } # 绑定退出信号处理 trap cleanup EXIT INT TERM # 主循环:持续读取并转发输入 while true; do # 读取二进制数据块(1k大小可根据实际调整) block=$(dd bs=1k count=1 2>/dev/null || true) if [ -n "$block" ]; then # 转发数据到stdout,确保二进制内容不被篡改 printf "%s" "$block" if [ -z "$start_epoch" ]; then # 首次收到输出,记录起始时间戳的epoch值 start_epoch=$(date +'%s') # 启动后台定时器:验证是否持续输出满MIN_ACTIVE秒 ( sleep "$MIN_ACTIVE" # 若start_epoch仍存在,说明输出持续足够久,写入开始日志 [ -n "$start_epoch" ] && echo "Start: $(date -d "@$start_epoch" +'%d.%m - %H:%M:%S')" >> "$LOG_DEST" ) & timer_pid=$! else # 已有活跃周期,先杀掉之前的静默定时器 [ -n "$timer_pid" ] && kill "$timer_pid" 2>/dev/null fi # 启动新的静默定时器:检测是否超过SILENCE_THRESH秒无输出 ( sleep "$SILENCE_THRESH" # 若start_epoch仍存在,说明已静默足够久,写入结束日志并重置状态 if [ -n "$start_epoch" ]; then echo "End: $(date +'%d.%m - %H:%M:%S')" >> "$LOG_DEST" start_epoch="" fi ) & timer_pid=$! else # 无输入时短暂休眠,避免空循环占用CPU sleep 0.1 fi done
使用方法
- 给脚本添加执行权限:
chmod +x monitor - 按需求调用(日志默认输出到stderr):
app | ./monitor > out - 若要将日志输出到指定文件,设置环境变量:
MONITOR_LOG=output.log app | ./monitor > out
关键细节说明
- 使用
dd读取二进制数据块,避免read命令的文本行限制,确保二进制内容完整转发 - 用
date +'%s'记录起始时间的epoch值,确保后续生成的开始时间戳是实际输出启动的时刻,而非满足3秒后的时间 - 后台定时器用子进程实现,通过
kill命令重置定时器,确保5秒内的新输出被视为同一周期 - 陷阱处理
EXIT、INT、TERM信号,确保脚本退出时清理后台进程,同时补录未结束的输出周期
内容的提问来源于stack exchange,提问作者programings
相关产品推荐
相关产品推荐

