로그 파일에서 마지막으로 업데이트된 기록을 찾아야 합니다.

로그 파일에서 마지막으로 업데이트된 기록을 찾아야 합니다.

매일 같은 파일에 기록이 추가되는 로그 파일이 있는데 특정 날짜에 얼마나 많은 기록이 추가되었는지 확실하지 않습니다. 파일에 추가된 마지막 레코드를 인쇄해야 합니다.

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사라진 다음 길이가 0인 상태로 다시 시작합니다.

$ 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))))

관련 정보