로그 파일에서 줄이 변경되면 메일 보내기, 메일에 대한 tail -f 파이핑이 작동하지 않음

로그 파일에서 줄이 변경되면 메일 보내기, 메일에 대한 tail -f 파이핑이 작동하지 않음

트래픽이 거의 없는 nginx access.log가 있으므로 액세스할 때마다 이메일을 받고 싶습니다. 나는 노력했다

tail -f access.log | cat

이것은 작동합니다. 그래서 테일 파이핑을 사용해도 괜찮을 것 같습니다.

다음에서는 아무 일도 일어나지 않습니다.

tail -f access.log | mail -s "Dateizugriff" <Destinationaddress>

어느 것도 아니다

tail -f access.log | grep --line-buffered '.*' | mail -s "Dateizugriff" <Destinationaddress>

...도 아니다

stdbuf -oL -eL  tail -f access.log | mail -s "Dateizugriff" <Destinationaddress>

물론 작동합니다

echo "test" | mail -s "Dateizugriff" <Destinationaddress>

일하다.

그런 다음 xargs를 시도했습니다.

tail -f access.log | xargs -I % mail -s "Dateizugriff" <Destinationaddress>

이제 한 줄에 하나의 이메일을 받았지만 내용이 없습니다.

tail -f access.log | xargs -I % | echo "%" |  mail -s "Dateizugriff" <Destinationaddress>

작동하지 않습니다. 아무 일도하지. 다음도 작동하지 않습니다.

tail -f access.log | xargs |  mail -s "Dateizugriff" <Destinationaddress>

그렇다면 작동하게 만드는 비결은 무엇입니까?

답변1

문제는 tail -f가 절대 종료되지 않는다는 것입니다. 단지 입력을 영원히 기다릴 뿐입니다. 따라서 파이프는 계속 열려 있고 메시지는 EOF를 수신하지 않으며 메시지가 "완료"될 때까지 기다립니다. 이는 결코 불가능합니다.

파이프에 다른 프로세스를 추가하는 것은 프로세스 중 적어도 하나가 종료되어 파이프를 파괴하지 않는 한 도움이 되지 않습니다.

로그에 추가된 각 줄을 별도의 메시지로 표시하려면 다음을 사용할 수 있습니다.

tail -f access.log | head -n 1 | mail -s "Dateizugriff" <user@domain>

Head는 한 줄을 읽은 후 종료되고, tail은 SIGPIPE를 수신한 후 종료되며, mail은 EOF를 수신한 후 계속해서 이메일을 보냅니다.

로그 항목이 여러 줄일 수 있지만 항상 마지막 줄을 식별할 수 있는 경우 sed 및 aq 조건을 사용하여 파이프를 끊을 수 있습니다.

첫 번째 단점은 메일 프로세스가 다음 줄이 도착할 때까지 기다리면서 영원히 중단된다는 것입니다.

두 번째 단점은 매번 프로세스가 완료되었음을 인식하고 전체 프로세스를 다시 시작해야 한다는 것입니다.

개인적으로 저는 휴면(약 60초)을 포함하여 루프 내에서 추가된 줄을 찾으려고 반복적으로 시도하는 쉘 루프를 작성합니다. 파일 크기가 증가할 때 -f 없이 tail을 실행할 수 있으므로 정지되지 않습니다.

반복하기 전에 nLine을 현재 줄 번호로 초기화합니다. 리디렉션은 wc가 파일 이름과 개수를 보고하는 것을 방지하기 때문에 중요합니다.

nLine="$( wc -l < access.log )"

while : ; do
    NEW=$( tail -n +$(( 1 + nLine )) access.log )
    [[ "${#NEW}" -gt 0 ]] && {
        echo "${NEW}" | mail ....
        nLine=$(( nLine + $( wc -l <<<${NEW} ) ))
    }
    sleep 60
done

답변2

아마도 시스템이 재부팅될 때마다 이 "모니터링" 프로세스가 자동으로 시작되기를 원할 것이기 때문에systemd이를 수행하는 합리적인 방법입니다.

monitor_nginx_access.path이는 다음 내용이 포함된 파일을 작성한다는 의미입니다.

[Unit]
Description=Alert admin about access

[Path]
PathChanged=/absolute/path/to/access.log

그리고제공하다동일한 이름으로 monitor_nginx_access.service기본적으로 마법을 수행하는 쉘 스크립트 주위의 래퍼가 포함되어 있습니다.

[Unit]
Description=Send mail when access log changes

[Service]
ExecStart=/absolute/path/to/mailscript.sh

두 파일 모두 다음 위치에 배치됩니다./etc/systemd/시스템또는 설치에 관리자 정의 단위가 필요한 systemd경우 (맨 페이지 참조).

그러면 mailscript.sh다음과 같은 내용이 포함 됩니다.

#!/bin/bash
MAILLINES=5  # how many of the last lines of access.log to mail
...

tail -n "$MAILLINES" /absolute/path/to/access.log | mail -s <your arguments here>

답변3

이 답변을 확인하십시오.https://stackoverflow.com/a/4657782/12332118 나는 그것을 테스트했고 그것은 나에게 효과적입니다. systemd를 사용하지 않고도 필요한 작업을 정확하게 수행합니다.

답변4

Max Müller가 연결한 것처럼 다음과 같이 할 수 있습니다.

tail -f access.log | grep --line-buffered GET | 
while read line 
do 
echo $line | mail -s New Access <Destinationaddress>
done

또는 내 솔루션을 한 줄로 사용하려는 경우

tail -f access.log | awk -W interactive '/GET/{system("echo "$0" | mail -s \"New Access\" <Destinationaddress>")}'

관련 정보