내 웹 사이트를 방문하는 고유한 방문자가 있을 때마다 내 컴퓨터 스피커에서 경고음을 울리려고 합니다.
약간의 브레인스토밍 후에는 다음 한 줄로 달성할 수 있는 것으로 보입니다.
for e in `ssh me@mymachine "tail -n 1 -f /var/log/apache2/test.log | awk '{print $1}' | uniq"`; do beep; done
그러나 stdin이 열려 있는 한 uniq는 아무 것도 출력하지 않습니다(EOF를 기다리는 것 같습니다). for 루프도 마찬가지입니다. 체인에서 uniq를 제거해도 여전히 출력이 나오지 않는 반면 tail은 파이프를 열어 둡니다.
버퍼링 때문은 아닌 것 같습니다. 이 명령을 실행하는 동안 테스트 파일에 100,000줄 이상을 써도 반대쪽에는 출력이 없습니다.
솔루션의 아름다움(단순성)을 완전히 파괴하지 않고 작동하게 할 수 있는 방법이 있습니까?
고쳐 쓰다
첫 번째 부분을 해결했습니다. uniq는 tail 명령을 접두어로 붙여 차단을 해제합니다 stdbuf -oL -eL
(참조:https://unix.stackexchange.com/a/25378/109296). 루프에서는 작동하지 않습니다.
업데이트 2
제대로 작동했지만 내 사양과 정확히 일치하지 않으며 두 줄이 있습니다.
while [ 1 -eq 1 ]; do ssh root@speedy "stdbuf -oL -eL tail -n 1 -f /var/log/apache2/www.access.log | stdbuf -oL -eL grep 'GET / '"; sleep 60; done > www.log
awk '{print $1}'
이 구성에서는 작동하지 않기 때문에 누락되었습니다(단지 전체 행을 전달함). 이유는 모르겠습니다. 하지만 uniq
그냥 보기에 불과했기 때문에 어차피 별로 쓸모가 없을 것 같았기 때문에 없이도 할 수 있었습니다.
가까운좋습니다. 즉, ip1, ip2, ip1 패턴을 요청하면 ip1이 여전히 두 번 통과하게 됩니다.
uniq -u
예상한 대로 작동하지만 동일한 문제가 있습니다 sort
. stdin이 열려 있는 동안에는 아무것도 출력되지 않습니다( stdbuf -oL
.
이 명령은 기본 URL(/)에 대한 모든 요청을 다른 파일에 기록합니다. 어떤 이유로 파이프나 연결이 중단되면 자동으로 재시도하도록 이것을 루프로 묶고 대기했습니다.
while inotifywait -e modify www.log; do beep -f 250; done
소음을! 버퍼링 없이 한 줄씩 처리하기 위해 bash for 루프를 얻을 수 없으며 while read
동일한 결과로 시도했습니다. 그래서 포기하고 계속했지만 inotifywait
이는 중간 파일이 필요하다는 것을 의미합니다(아마도 명명된 파이프도 작동할 수 있지만 시도하지 않았습니다. 실제로 나에게 차이를 만들지 않습니다).
(복잡성을 추가하지 않고) 순 방문자를 필터링하는 데 도움이 되는 기여에 여전히 감사드립니다.
우리 팀원들이 사무실로 돌아올 때 이것은 큰 놀라움이 될 것입니다 :-)
저는 이 알림 시스템을 확장하여 다양한 오디오를 사용하여 여러 이벤트를 모니터링할 계획입니다. 먼지가 쌓이는 오래된 서버의 경우, 이것은 내가 지금까지 찾은 최고의 작업입니다...
답변1
나는 당신이 달성하려는 것을 이해한다고 생각합니다.
- 웹사이트를 클릭할 때마다 웹 서버에 의해 기록됩니다:
- 액세스가 "고유"한 경우(이를 어떻게 정의합니까?) 항목이 기록되고 소리 알림이 전송됩니다.
비결은 "고유함"을 정의하는 방법입니다. URL, IP 주소, 쿠키를 통해 이루어지나요? awk를 사용하는 접근 방식은 틀림없이 올바른 접근 방식이지만 쉘 이스케이프 규칙이 붙어 있습니다.
여기 여러분의 방법을 결합한 것이 있습니다. 첫째, 이 작업을 수행하려면 웹 서버에 스크립트가 필요합니다. 그렇지 않으면 복잡한 인용 이스케이프 규칙에 빠져들게 됩니다. 둘째, 귀하의 웹 서버가 "공통 로그 형식"을 사용하고 있다고 가정합니다. 솔직히 이런 종류의 작업에는 좋지 않지만 사용할 수 있습니다.
while true; do
ssh root@speedy remote-log-capturing-script
done > unique-visits.log
MAILFILE에 관한 mikeserv의 훌륭한 제안을 사용하십시오. Speedy의 스크립트는 다음과 같아야 합니다.
#!/bin/sh
tail -1f /var/log/apache2/www.access.log |
awk '$(NF-1) == 200' |
grep --line-buffered -o '"GET [^"]*"' |
awk '!url[$1]{ print; url[$1]=1 }'
awk는 항상 라인 버퍼링됩니다. 첫 번째 awk는 캐시 적중이나 404가 아닌 실제 성공적인 적중만 얻도록 보장합니다. grep -o는 입력에서 일치하는 부분(이 경우 URL)만 인쇄합니다. (이것은 GNU grep입니다. 사용하고 있다고 가정합니다. 그렇지 않은 경우 stdbuf 트릭을 사용하십시오.) 다음 awk는 작은 표현식을 사용하여 입력 라인을 조건부로 인쇄합니다. 해당 입력 라인이 이전에 본 적이 없는 경우에만 가능합니다.
Perl을 사용하여 이를 수행하여 분기 내에서 더 많은 복잡성을 달성할 수도 있습니다.
#!/bin/sh
tail -1f /var/log/apache2/www.access.log |
perl -lane '$|=1;' \
-e 'if ($F[$#F-1] eq "200" and ' \
-e ' /\s"GET\s([^"]*)"\s/ and !$url{$1}) { '\
-e ' print $1;$url{$1}=undef; }'
이제 둘 다 고유한 URL만 인쇄합니다. 서로 다른 IP의 두 웹 클라이언트가 동일한 페이지에 액세스하면 어떻게 되나요? 하나의 출력만 얻을 수 있습니다. 이를 변경하려면 Perl을 사용하는 솔루션이 간단합니다. URL에서 키를 수정하면 됩니다.
$url{$F[0],$1}
perl -a를 사용할 때 $F[0]는 awk의 $1과 마찬가지로 입력된 첫 번째 공백으로 구분된 필드, 즉 연결 호스트 이름/IP 주소를 나타냅니다. Perl의 $1은 /\s"GET\s([^"]*)"\s/
URL 자체인 정규식의 첫 번째 일치 하위 표현식을 나타냅니다 . 미스터리는 $F[$#F-1]
입력 라인의 끝에서 두 번째 필드를 의미합니다.
답변2
이것이 JJoao의 간결한 Perl 명령 덕분에 제가 마침내 생각해낸 것입니다:
# 종료 시 모든 것을 종료합니다. 트랩 "kill 0" SIGINT SIGTERM # 종료 시 원격 프로세스가 종료되는지 확인합니다. http://unix.stackexchange.com/questions/103699/kill-process-spawned-by-ssh-when-ssh-dies를 참조하세요. shopt -s huponexit ( while [ 1 -eq 1 ]; do ssh -t -t root@speedy "stdbuf -oL -eL tail -n 1 -f /var/log/apache2/www.access.log | stdbuf -oL -eL grep ' GET / ' | stdbuf -oL -eL perl -naE '($a{$F[0]}++ == 0) $F[0]'"; sleep 60; done > www.log ) & (동시에 inotifywait -e는 www.log를 수정하고 경고음을 실행합니다. -f 250; 완료됨)&