← 中文资源

简体中文版本

Tail 流式日志跟随过滤

用 tail -F 流式跟随增长的日志并按模式过滤:行缓冲防整段堆积、ANSI 颜色分级渲染、信号处理干净停流。

阅读英文原文

示例说明

tail -f 只跟一个 inode,日志轮转重建文件后就傻等旧句柄;-F 会重新打开同名文件继续跟——生产日志必然轮转,这是硬区别。grep 默认按块缓冲,流式场景必须 –line-buffered:每行即时通过,延迟从分钟级降到毫秒。整个链路 tail | grep | while 组成数据流管道,每段都流式化才不积压。

技术要点

  • -F 跟随轮转重建的文件
  • 行缓冲让过滤延迟降到毫秒级
  • 信号陷阱保证子进程一并停止

代码解读

stream_logs 的三段管道:tail 带五十行历史起步、grep 按扩展正则过滤、while 循环按行分色渲染——ERROR 红、WARN 黄、Traceback 紫,肉眼分级。主循环的 running 标志由 INT TERM 陷阱翻转,kill -0 探测管道存活性,退出时杀掉后台管道并 wait 回收,不留孤儿 tail。

使用建议

多文件跟随直接给 tail 传多个路径,输出带文件名头。复杂过滤换 awk 或落 jq。生产排障建议配合 timestamps 与上下文行选项。

代码示例

#!/usr/bin/env bash
set -euo pipefail

readonly LOG_FILE="${1:-/var/log/app/application.log}"
readonly PATTERNS='ERROR|WARN|Traceback'

running=true
on_term() { running=false; }
trap on_term INT TERM

stream_logs() {
  # -F 处理轮转:文件被重建后继续跟随
  tail -F --lines=50 "${LOG_FILE}" 2>/dev/null \
    | grep --line-buffered -E "${PATTERNS}" \
    | while IFS= read -r line; do
        case "$line" in
          *ERROR*)     printf '\033[31m%s\033[0m\n' "$line" ;;
          *WARN*)      printf '\033[33m%s\033[0m\n' "$line" ;;
          *Traceback*) printf '\033[35m%s\033[0m\n' "$line" ;;
        esac
      done
}

[[ -f "${LOG_FILE}" ]] || { echo "日志文件不存在: ${LOG_FILE}" >&2; exit 1; }

echo "跟随 ${LOG_FILE} 中的 ${PATTERNS},Ctrl-C 退出"
stream_logs &

readonly TAIL_PID=$!
while $running; do
  sleep 1
  kill -0 "${TAIL_PID}" 2>/dev/null || running=false
done

kill "${TAIL_PID}" 2>/dev/null || true
wait "${TAIL_PID}" 2>/dev/null || true
echo "日志流已停止"