【问题标题】:How to tail -f the latest log file with a given pattern如何尾 -f 具有给定模式的最新日志文件
【发布时间】:2024-01-01 03:41:01
【问题描述】:

我使用一些日志系统,它每小时创建一个日志文件,如下所示:

SoftwareLog.2010-08-01-08
SoftwareLog.2010-08-01-09
SoftwareLog.2010-08-01-10

我正在尝试跟踪给出模式的最新日志文件(例如 SoftwareLog*),我意识到有:

tail -F (tail --follow=name --retry)

但只遵循一个特定的名称 - 这些名称按日期和时间有不同的名称。我试过类似的东西:

tail --follow=name --retry SoftwareLog*(.om[1])  

但通配符语句在传递给 tail 之前已被解析,并且不会在每次 tail 重试时重新执行。

有什么建议吗?

【问题讨论】:

    标签: linux logging zsh tail


    【解决方案1】:

    我认为最简单的解决方案如下:

    tail -f `ls -tr | tail -n 1`
    

    现在,如果您的目录包含其他日志文件,例如“SystemLog”,而您只需要最新的“SoftwareLog”文件,那么您只需包含一个 grep,如下所示:

    tail -f `ls -tr | grep SoftwareLog | tail -n 1`
    

    【讨论】:

    • 或者使用head而不是tail,让事情变得更简单=) ls -t |头-1 | xargs 尾 -F
    • 或者可以使用:tail -f SoftwareLog.`date +'%Y-%m-%d-%H'`
    【解决方案2】:

    [编辑:在快速搜索工具后]

    你可能想试试 multitail - http://www.vanheusden.com/multitail/

    如果您想坚持 Dennis Williamson 的回答(并且我已相应地为他 +1),这里是为您填写的空白。

    在您的 shell 中,运行以下脚本(或者它与 zsh 等效,我在看到 zsh 标记之前在 bash 中进行了处理):

    #!/bin/bash
    
    TARGET_DIR="some/logfiles/"
    SYMLINK_FILE="SoftwareLog.latest"
    SYMLINK_PATH="$TARGET_DIR/$SYMLINK_FILE"
    
    function getLastModifiedFile {
        echo $(ls -t "$TARGET_DIR" | grep -v "$SYMLINK_FILE" | head -1)
    }
    
    function getCurrentlySymlinkedFile {
        if [[ -h $SYMLINK_PATH ]]
        then
            echo $(ls -l $SYMLINK_PATH | awk '{print $NF}')
        else
            echo ""
        fi
    }
    
    symlinkedFile=$(getCurrentlySymlinkedFile)
    while true
    do
        sleep 10
        lastModified=$(getLastModifiedFile)
        if [[ $symlinkedFile != $lastModified ]]
        then
            ln -nsf $lastModified $SYMLINK_PATH
            symlinkedFile=$lastModified
        fi
    done
    

    使用普通方法后台该进程(再次,我不知道 zsh,所以它可能会有所不同)...

    ./updateSymlink.sh 2>&1 > /dev/null

    然后tail -F $SYMLINK_PATH 以便尾部处理符号链接的更改或文件的旋转。

    这有点令人费解,但我不知道用尾巴做这件事的另一种方法。如果其他人知道处理此问题的实用程序,那么让他们向前迈进,因为我也很想亲自看到它 - 默认情况下,像 Jetty 这样的应用程序会以这种方式记录,我总是编写一个在 cron 上运行的符号链接脚本来补偿为它。

    [编辑:从其中一行的末尾删除了错误的“j”。您还有一个错误的变量名称“lastModifiedFile”不存在,您设置的正确名称是“lastModified”]

    【讨论】:

    • 谢谢,我可能不得不这样做。我研究了多尾,但不幸的是它只是交互式的,这意味着我无法将它的输出通过管道传输到其他地方。我会尝试一下,看看我在哪里。问题是我希望它只在尾部运行时运行并在退出时退出,我不知道该怎么做。
    • 谢谢!这基本上是我喜欢的唯一解决方案(我为此搜索了很多)。
    • Neato。编辑以修复第一次对我不起作用的错误。 (因为 getCurrentlySymlinkedFile 正在返回一个空字符串,并且拼写错误的不存在 lastModifiedDate 也被评估为一个空字符串。)
    【解决方案3】:

    我尚未对此进行测试,但一种可能有效的方法是运行一个后台进程,该进程创建并更新指向最新日志文件的符号链接,然后您将使用 tail -f(或 tail -F)符号链接。

    【讨论】:

      【解决方案4】:
      #!/bin/bash
      
      PATTERN="$1"
      
      # Try to make sure sub-shells exit when we do.
      trap "kill -9 -- -$BASHPID" SIGINT SIGTERM EXIT
      
      PID=0
      OLD_FILES=""
      while true; do
        FILES="$(echo $PATTERN)"
        if test "$FILES" != "$OLD_FILES"; then
          if test "$PID" != "0"; then
            kill $PID
            PID=0
          fi
          if test "$FILES" != "$PATTERN" || test -f "$PATTERN"; then
            tail --pid=$$ -n 0 -F $PATTERN &
            PID=$!
          fi
        fi
        OLD_FILES="$FILES"
        sleep 1
      done
      

      然后运行为:tail.sh 'SoftwareLog*'

      如果在检查之间写入日志,脚本将丢失一些日志行。但至少它是一个脚本,不需要符号链接。

      【讨论】:

        【解决方案5】:

        我们每天轮换的日志文件为:/var/log/grails/customer-2020-01-03.logtail 最新的一个,以下命令对我来说很好:

        tail -f /var/log/grails/customer-`date +'%Y-%m-%d'`.log
        

        注意:表达式中+ 符号后没有空格)

        因此,对您而言,以下内容应该有效(如果您位于日志的同一目录中):

        tail -f SoftwareLog.`date +'%Y-%m-%d-%H'`
        

        【讨论】:

          【解决方案6】:

          我相信最简单的方法是将 taillshead 一起使用,试试这样的方法

          tail -f `ls -t SoftwareLog* | head -1`
          

          【讨论】: