需要在日志文件中查找最后更新的记录

需要在日志文件中查找最后更新的记录

我们有一个日志文件,每天都会将记录附加到同一文件中,我们不确定特定日期附加的记录数。我需要打印最后附加到文件的记录。

cat file.txt, (yesterday file)
Shyam
Raghu
cat file.txt, (today file)
Shyam
Raghu
Ravi

我们可以看到Ravi是文件中最近更新的记录,我只需要打印Ravi。

我尝试过使用tail -f命令,但我也得到了前一天的记录,因为更新的记录是动态的,是否有任何脚本或命令只给我今天更新的记录?

答案1

您可以使用这个 41 行 TXR Lisp 程序作为守护进程来监视日志文件并实时生成带有时间戳的版本。

TXR 具有非常低的依赖性和较小的内存占用,但功能却很多。

首先是演示:

foo我们从一个和bar不存在的状态开始。foo将是没有标记的日志文件。bar将是带有标记的日志文件:

$ rm -f foo bar

我们stamp.tl在后台运行该程序。我没有#!在其中添加(哈希爆炸)行(供读者练习),因此我们使用txr它。这-d意味着它将作为守护进程将自己置于后台:

$ txr stamp.tl -d foo bar

好的,让我们开始制作内容foo

$ echo "first post" >> foo
$ cat foo
first post

发生了什么bar

$ cat bar
2021-08-20 06:40:06 first post

日志行显示在那里并带有时间戳。继续前进:

$ echo "second post" >> foo
$ cat bar
2021-08-20 06:40:06 first post
2021-08-20 06:40:17 second post
$ echo "third post" >> foo
$ cat bar
2021-08-20 06:40:06 first post
2021-08-20 06:40:17 second post
2021-08-20 06:40:24 third post

现在,让我们尝试一下。假设记录日志的软件foo轮换日志。foo消失然后从零长度重新开始:

$ rm foo
$ echo "rotated" >> foo
$ cat foo
rotated

会发生什么bar

$ cat bar
2021-08-20 06:40:06 first post
2021-08-20 06:40:17 second post
2021-08-20 06:40:24 third post
2021-08-20 06:40:49 rotated

rotated正如您所看到的,它很好地捕获了这条线。

当然,真正的解决方案是修复没有时间戳的日志记录的原始软件,但这同时可能只是创可贴解决方案。

代码如下。该程序有三个选项。除了我们使用的上述内容之外-d,它还有一个覆盖目标文件的选项(默认行为是追加)和一个使用完全缓冲进行写入的选项(默认是使用行缓冲)。

请注意,该程序不支持轮换输出日志,因为它只是打开文件并保持打开状态。为了支持外部日志轮转,程序必须在每次写入时打开和关闭文件。否则,实现内部旋转:在这么多行之后,关闭文件,进行旋转重命名,然后重新打开它。

;; Copyright 2021
;; Kaz Kylheku <[email protected]>
;; Vancouver, Canada
;; All rights reserved.
;;
;; Redistribution and use in source and binary forms, with or without
;; modification, are permitted provided that the following conditions are met:
;;
;; 1. Redistributions of source code must retain the above copyright notice,
;;    this list of conditions and the following disclaimer.
;;
;; 2. Redistributions in binary form must reproduce the above copyright notice,
;;    this list of conditions and the following disclaimer in the documentation
;;    and/or other materials provided with the distribution.
;;
;; THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
;; AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
;; IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
;; ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
;; LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
;; CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
;; SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
;; INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
;; CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
;; ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
;; POSSIBILITY OF SUCH DAMAGE.

(defun stamp (infile outfile opts)
  (when (and opts.daemonize
             (not (daemon t nil))) ;; don't chdir
    (put-line "failed to daemonize")
    (exit nil))
  (let* ((line-buf (if opts.fully-buffered "" "l"))
         (write-mode (if opts.overwrite `w@{line-buf}` `a@{line-buf}`)))
    (with-resources ((out (open-file outfile write-mode) (close-stream out))
                     (in (open-tail infile) (close-stream in)))
      (whilet ((line (get-line in)))
        (let ((stamp (time-string-local (time) "%Y-%m-%d %H:%M:%S")))
          (put-line `@stamp @line` out))))))

(define-option-struct prog-opts nil
  (w   overwrite        :bool
       "Overwrite the output file instead of appending.")
  (d   daemonize        :bool
       "Run in the background as a daemon")
  (f   fully-buffered   :bool
       "Writes to the output file are flushed whenever\ \
        an I/O buffer fills up. The default behavior is to\ \
        flush after every line.")
  (nil help    :bool
       "List this help text."))

(defvarl prog-name *load-path*)

(defun usage ()
  (put-line "\nUsage:\n")
  (put-line `  @{prog-name} [ options ] <infile> [ <outfile> ]`))

(let ((o (new prog-opts)))
  o.(getopts *args*)
  (when o.help
    (usage)
    o.(opthelp)
    (exit nil))
  (match-case o.out-args
    ((@infile @outfile) (stamp infile outfile o))
    ((@infile) (stamp infile `@infile.stamped` o))
    (@else (usage) (exit nil))))

相关内容