로그에 텍스트가 나타날 때 로그를 따르고 명령을 실행하는 가장 좋은 방법


54

서버가 작동 할 때 특정 텍스트 줄을 로그 파일에 출력하는 서버 로그가 있습니다. 서버가 가동되면 명령을 실행하고 싶으므로 다음과 같이하십시오.

tail -f /path/to/serverLog | grep "server is up" ...(now, e.g., wget on server)?

가장 좋은 방법은 무엇입니까?


3
반드시 사용하는 tail -F회전 로그 처리 - 즉 my.log전체되고으로 이동 my.log.1하고 프로세스는 새로운 생성my.log
SG

답변:


34

간단한 방법은 어색합니다.

tail -f /path/to/serverLog | awk '
                    /Printer is on fire!/ { system("shutdown -h now") }
                    /new USB high speed/  { system("echo \"New USB\" | mail admin") }'

그리고 둘 다 커널 로그의 실제 메시지입니다. Perl은 이것에 사용하기에 조금 더 우아 할 수도 있고 꼬리의 필요성을 대체 할 수도 있습니다. 펄을 사용한다면 다음과 같이 보일 것이다 :

open(my $fd, "<", "/path/to/serverLog") or die "Can't open log";
while(1) {
    if(eof $fd) {
        sleep 1;
        $fd->clearerr;
        next;
    }
    my $line = <$fd>;
    chomp($line);
    if($line =~ /Printer is on fire!/) {
        system("shutdown -h now");
    } elsif($line =~ /new USB high speed/) {
        system("echo \"New USB\" | mail admin");
    }
}

나는 awk한 줄로 짧고 쉽게 할 수 있는 솔루션을 좋아합니다 . 그러나 실행하려는 명령에 따옴표가있는 경우 약간 번거로울 수 있습니다. 파이프 라인 및 복합 명령을 사용하여 간단한 한 줄 솔루션을 허용하지만 결과 명령을 전달할 필요는 없습니다. 문자열로?
jonderry

1
@jon awk를 스크립트로 쓸 수 있습니다. 스크립트의 첫 줄로 "#! / usr / bin awk -f"를 사용하십시오. 이것은 내 예제에서 외부 작은 따옴표가 필요하지 않으며 system()명령 내에서 사용하기 위해 자유롭게 사용할 수 있습니다 .
penguin359

@ penguin359, True, 그러나 여전히 명령 줄에서 수행하는 것이 흥미로울 것입니다. 필자의 경우, 예측할 수없는 많은 일을 포함하여 다양한 일을하고 싶기 때문에 서버를 시작하고 한 줄로 모든 작업을 수행하는 것이 편리합니다.
jonderry

나는 그것이 얼마나 견고한 지 모르지만 대안을 찾았습니다.tail -f /path/to/serverLog | grep "server is up" | head -1 && do_some_command
jonderry

@ jon 그것은 그렇게 머리를 사용하여 약간 깨지기 쉬운 것 같습니다. 더 중요한 것은 내 예제처럼 반복 할 수 없다는 것입니다. "server is up"이 로그의 마지막 10 줄에 있으면 명령이 실행되고 즉시 종료됩니다. 다시 시작하면 "server is"를 포함하지 않는 10 개의 라인이 로그에 추가되지 않은 한 대부분의 경우 실행되고 다시 종료됩니다. 더 잘 작동 할 수있는 수정은 tail -n 0 -f /path/to/serverLog 파일의 마지막 0 줄을 읽은 다음 더 많은 줄이 인쇄 될 때까지 기다리는 것입니다.
penguin359

16

당신은 단지 하나의 가능성을 찾고 사용하는 쉘에 주로 머물 것이 아니라 원하는 경우 awk또는 perl, 당신은 뭔가를 할 수 있습니다 :

tail -F /path/to/serverLog | 
grep --line-buffered 'server is up' | 
while read ; do my_command ; done

... 로그 파일에 my_command" server is up "이 나타날 때마다 실행 됩니다 . 여러 가능성을 위해을 삭제하고을 grep대신 사용할 수 case있습니다 while.

수도 -Ftail로그 파일의 회전을 감시하도록 지시 합니다. , 현재 파일 이름이 바뀌고 동일한 이름을 가진 다른 파일이 대신 사용되면 tail새 파일로 전환됩니다.

--line-buffered옵션은 grep모든 줄마다 버퍼를 플러시하도록 지시 합니다. 그렇지 않으면, my_command로그에 적당한 크기의 선이 있다고 가정하여 적시에 도달하지 못할 수 있습니다.


2
나는이 답변을 정말로 좋아하지만 처음에는 효과가 없었습니다. 에 --line-buffered옵션 을 추가해야 grep하거나 그렇지 않으면 라인 사이에서 출력을 플러시해야합니다. 그렇지 않으면 그냥 멈추고 my_command도달하지 않습니다. 원하는 경우 ack, 그것은이 --flush플래그를; 원하는 경우로 ag감싸보십시오 stdbuf. stackoverflow.com/questions/28982518/…
doctaphred

나는 이것을 사용하여 이것을 시도했다 do exit ;. 잘 작동하는 것처럼 보였지만 꼬리는 끝나지 않았고 스크립트는 다음 줄로 이동하지 않았습니다. do섹션 에서 꼬리를 막을 수있는 방법이 있습니까?
Machtyn

14

이 질문에 이미 답변 된 것으로 보이지만 더 나은 해결책이 있다고 생각합니다.

그보다는 tail | whatever당신이 정말로 원하는 것이 있다고 생각합니다 swatch. Swatch는 요청한 작업을 수행하고 로그 파일을보고 로그 라인을 기반으로 작업을 실행하도록 명시 적으로 설계된 프로그램입니다. 사용 tail|foo하려면이 작업을 수행하기 위해 터미널을 적극적으로 실행해야합니다. 반면 견본은 데몬으로 실행되며 항상 로그를 감시합니다. 견본은 모든 Linux 배포판에서 사용할 수 있습니다.

나는 당신이 그것을 시도하는 것이 좋습니다. 드라이버의 뒷면에 못을 박을 수 있다고해서 꼭 그래야하는 것은 아닙니다.

내가 찾을 수있는 견본에 대한 최고의 30 초 자습서는 여기에 있습니다 : http://www.campin.net/newlogcheck.html


1
그 튜토리얼은 지금 404입니다 : /
거기서부터

1
WebArchive는 당신의 친구입니다 : web.archive.org/web/20140922041805/http://campin.net/…
Sun

10

multitail이 기능이 기본적으로 제공되는 유틸리티 에 대해서는 아무도 언급하지 않은 것이 이상합니다 . 사용 예 중 하나 :

ping 명령의 출력을 표시하고 시간 초과가 표시되면 현재 로그인 한 모든 사용자에게 메시지를 보냅니다.

multitail -ex timeout "echo timeout | wall" -l "ping 192.168.0.1"

참조 다른 예제multitail사용을.


+1, 나는 multitail이 그런 종류의 닌자 기술을 잃어 버렸다는 것을 몰랐다. 지적 해 주셔서 감사합니다.
Caleb

8

는 스스로 일을 할 수 있습니다

그것이 얼마나 간단하고 읽기 쉬운 지 봅시다 :

mylog() {
    echo >>/path/to/myscriptLog "$@"
}

while read line;do
    case "$line" in
        *"Printer on fire"* )
            mylog Halting immediately
            shutdown -h now
            ;;
        *DHCPREQUEST* )
            [[ "$line" =~ DHCPREQUEST\ for\ ([^\ ]*)\  ]]
            mylog Incomming or refresh for ${BASH_REMATCH[1]}
            $HOME/SomethingWithNewClient ${BASH_REMATCH[1]}
            ;;
        * )
            mylog "untrapped entry: $line"
            ;;
    esac
  done < <(tail -f /path/to/logfile)

bash를 사용하지 않는 동안 regex이것은 매우 빠르게 유지 될 수 있습니다!

그러나 + 는 매우 효율적이고 흥미로운 탠덤입니다.

그러나 고부하 서버 sed의 경우 매우 빠르고 확장 성이 뛰어 나기 때문에 원하는 경우 종종 다음을 사용합니다.

while read event target lost ; do
    case $event in
        NEW )
            ip2int $target intTarget
            ((count[intTarget]++))
        ...

    esac
done < <(tail -f /path/logfile | sed -une '
  s/^.*New incom.*from ip \([0-9.]\+\) .*$/NEW \1/p;
  s/^.*Auth.*ip \([0-9.]\+\) failed./FAIL \1/p;
  ...
')

6

그것이 내가 이것을 시작한 방법이지만 훨씬 더 정교 해졌습니다. 고려해야 할 몇 가지 사항 :

  1. 로그의 꼬리에 이미 "서버가 작동 중"이 포함되어있는 경우
  2. 테일 프로세스가 발견되면 자동으로 종료됩니다.

나는 이것의 라인을 따라 무언가를 사용한다 :

RELEASE=/tmp/${RANDOM}$$
(
  trap 'false' 1
  trap "rm -f ${RELEASE}" 0
  while ! [ -s ${RELEASE} ]; do sleep 3; done
  # You can put code here if you want to do something
  # once the grep succeeds.
) & wait_pid=$!
tail --pid=${wait_pid} -F /path/to/serverLog \
| sed "1,10d" \
| grep "server is up" > ${RELEASE}

파일에 데이터가 tail포함될 때까지 열린 채로 작동 ${RELEASE}합니다.

(가) 번 grep을 성공 :

  1. 출력에 기록 ${RELEASE}되는 것
  2. ${wait_pid}프로세스를 종료 하다
  3. 종료 tail

참고 : 시작시 생성 할 sed줄 수를 실제로 결정하고 해당 번호를 tail제거하는 것이 더 정교 할 수 있습니다 . 그러나 일반적으로 10입니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.