로그 분석기를 사용할 수 있지만, 현재 발생하는 상황을 확인하기 위해 최근 웹 로그를 구문 분석해야하는 경우가 종종 있습니다.
때로는 특정 파일을 요청하는 상위 10 IP를 파악하는 것과 같은 일을합니다.
cat foo.log | grep request_to_file_foo | awk '{print $1}' | sort -n | uniq -c | sort -rn | head
툴박스에 무엇이 있습니까?
로그 분석기를 사용할 수 있지만, 현재 발생하는 상황을 확인하기 위해 최근 웹 로그를 구문 분석해야하는 경우가 종종 있습니다.
때로는 특정 파일을 요청하는 상위 10 IP를 파악하는 것과 같은 일을합니다.
cat foo.log | grep request_to_file_foo | awk '{print $1}' | sort -n | uniq -c | sort -rn | head
툴박스에 무엇이 있습니까?
답변:
awk만으로 아파치 로그 파일로 거의 모든 것을 할 수 있습니다. Apache 로그 파일은 기본적으로 공백으로 구분되며 따옴표가없는 것으로 가장하고 열 번호로 관심있는 정보에 액세스 할 수 있습니다. 이 분류가 유일한 시간은 결합 된 로그 형식이 있고 사용자 에이전트에 관심이있는 경우에만 따옴표 ( ")를 구분 기호로 사용하고 별도의 awk 명령을 실행해야합니다. 다음은 IP의 IP를 보여줍니다. 조회수를 기준으로 색인 페이지를 요청하는 모든 사용자 :
awk -F'[ "]+' '$7 == "/" { ipcount[$1]++ }
END { for (i in ipcount) {
printf "%15s - %d\n", i, ipcount[i] } }' logfile.log
요청한 URL은 $ 7입니다. 처음에 원하는 조건을 추가 할 수 있습니다. '$ 7 == "/"를 원하는 정보로 바꾸십시오.
(ipcount [$ 1] ++)에서 $ 1을 바꾸면 다른 기준으로 결과를 그룹화 할 수 있습니다. 7 달러를 사용하면 액세스 한 페이지와 빈도가 표시됩니다. 물론 처음에 조건을 바꾸고 싶을 것입니다. 다음은 특정 IP에서 사용자가 액세스 한 페이지를 보여줍니다.
awk -F'[ "]+' '$1 == "1.2.3.4" { pagecount[$7]++ }
END { for (i in pagecount) {
printf "%15s - %d\n", i, pagecount[i] } }' logfile.log
쉘 명령의 일부 또는 awk 스크립트 자체에서 결과를 순서대로 가져 오기 위해 sort를 통해 출력을 파이프 할 수도 있습니다.
awk -F'[ "]+' '$7 == "/" { ipcount[$1]++ }
END { for (i in ipcount) {
printf "%15s - %d\n", i, ipcount[i] | sort } }' logfile.log
후자는 다른 정보를 인쇄하기 위해 awk 스크립트를 확장하기로 결정한 경우 유용합니다. 모두 당신이 찾고자하는 문제입니다. 이것들은 당신이 관심있는 무엇이든을위한 출발점으로 작용해야합니다.
내가 상상할 수없는 이유로 다른 사람이 본 적이없는 것 중 하나는 Apache 로그 파일 형식을 실제로 중요한 정보가 포함 된보다 쉽게 구문 분석 가능한 버전으로 변경하는 것입니다.
예를 들어 HTTP 기본 인증을 사용하지 않으므로 해당 필드를 기록 할 필요가 없습니다. 나는 오전 각 요청에 봉사하는 데 걸리는 시간에 관심이, 그래서 우리는에 그것을 추가 할 것입니다. 하나 개의 프로젝트를 위해, 우리는 또한 모든 서버가 느린 다른 사람보다 요청을 처리하는 경우 (우리의 부하 분산에) 알고 싶은, 그래서 우리는 이름을 기록 프록시하는 서버의
다음은 한 서버의 아파치 구성에서 발췌 한 것입니다.
# We don't want to log bots, they're our friends
BrowserMatch Pingdom.com robot
# Custom log format, for testing
#
# date proto ipaddr status time req referer user-agent
LogFormat "%{%F %T}t %p %a %>s %D %r %{Referer}i %{User-agent}i" standard
CustomLog /var/log/apache2/access.log standard env=!robot
실제로 알 수없는 것은 각 필드 사이에 리터럴 탭 문자 (\ t)라는 것입니다. 이것은 파이썬에서 일부 분석을 원한다면 200이 아닌 상태를 표시 할 수 있다는 것을 의미합니다.
for line in file("access.log"):
line = line.split("\t")
if line[3] != "200":
print line
또는 '핫 링크 이미지는 누구입니까?' 그것은 될 것이다
if line[6] in ("","-") and "/images" in line[5]:
액세스 로그의 IP 수에 대한 이전 예 :
grep -o "[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}" logfile | sort -n | uniq -c | sort -n
다음과 같이됩니다 :
cut -f 3 log | uniq -c | sort -n
읽기 쉽고 이해하기 쉽고 계산 비용이 훨씬 적게 드는 (정규식 없음) 9GB 로그에서 소요 시간이 크게 달라집니다. 이것이 REALLY 깔끔해지면 사용자 에이전트에 대해 동일한 작업을 수행하려는 것입니다. 로그가 공백으로 구분 된 경우 정규식 일치 또는 문자열 검색을 직접 수행해야합니다. 이 형식을 사용하면 간단합니다.
cut -f 8 log | uniq -c | sort -n
위와 정확히 동일합니다. 실제로, 원하는 요약은 본질적으로 동일합니다.
왜 지구상에서 시스템의 CPU를 awk와 grep에 소비하면 cut이 원하는 크기만큼 빠르게 처리 할 수 있습니까?
cut -f 3 log | uniq -c | sort -n
사용자 에이전트가 cut -f 8 log | uniq -c | sort -n
됩니다.
awk와 grep은 잊어 버리세요. asql을 확인하십시오 . 로그 파일을 쿼리하기 위해 sql과 같은 구문을 사용할 수 있는데 왜 읽을 수없는 스크립트를 작성해야합니까? 예 :
asql v0.6 - type 'help' for help.
asql> load /home/skx/hg/engaging/logs/access.log
Loading: /home/skx/hg/engaging/logs/access.log
sasql> select COUNT(id) FROM logs
46
asql> alias hits SELECT COUNT(id) FROM logs
ALIAS hits SELECT COUNT(id) FROM logs
asql> alias ips SELECT DISTINCT(source) FROM logs;
ALIAS ips SELECT DISTINCT(source) FROM logs;
asql> hits
46
asql> alias
ALIAS hits SELECT COUNT(id) FROM logs
ALIAS ips SELECT DISTINCT(source) FROM logs;
최근 N 개의 로그 항목에서 상위 URL, 상위 리퍼러 및 상위 사용자 에이전트를 찾는 스크립트는 다음과 같습니다.
#!/bin/bash
# Usage
# ls-httpd type count
# Eg:
# ls-httpd url 1000
# will find top URLs in the last 1000 access log entries
# ls-httpd ip 1000
# will find top IPs in the last 1000 access log entries
# ls-httpd agent 1000
# will find top user agents in the last 1000 access log entries
type=$1
length=$2
if [ "$3" == "" ]; then
log_file="/var/log/httpd/example.com-access_log"
else
log_file="$3"
fi
if [ "$type" = "ip" ]; then
tail -n $length $log_file | grep -o "[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}" | sort -n | uniq -c | sort -n
elif [ "$type" = "agent" ]; then
tail -n $length $log_file | awk -F\" '{print $6}'| sort -n | uniq -c | sort -n
elif [ "$type" = "url" ]; then
tail -n $length $log_file | awk -F\" '{print $2}'| sort -n | uniq -c | sort -n
fi
액세스 로그의 IP 수 :
cat log | grep -o "[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}" | sort -n | uniq -c | sort -n
조금 추악하지만 작동합니다. 또한 netstat와 함께 다음을 사용합니다 (활성 연결을 보려면).
netstat -an | awk '{print $5}' | grep -o "[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}" | egrep -v "(`for i in \`ip addr | grep inet |grep eth0 | cut -d/ -f1 | awk '{print $2}'\`;do echo -n "$i|"| sed 's/\./\\\./g;';done`127\.|0\.0\.0)" | sort -n | uniq -c | sort -n
그들은 내가 좋아하는 "한 라이너"중 일부입니다 :)
일반적인 질문 목록을 작성하면이 질문에 대한 답변을 얻을 수 있습니다. 가장 일반적인 질문은 다음과 같습니다.
활성 및 최근 완료된 요청에 대한 적중률 및 대략적인 응답 시간에 대해 서버 상태 페이지 (mod_status를 통해)를 모니터링하여 이러한 변경 사항을 알 수 있습니다 (거대한 데이터 더미가 누락되었지만 샘플은 충분하다는 것을 잘 알고 있음).
다음 LogFormat 지시문을 사용합니다 (% T가 정말 유용합니다)
LogFormat "%h %l %u %t \"%r\" %>s %b
\"%{Referer}i\" \"%{User-Agent}i\" %T" custom
원인-결과와 가장 먼저 일어난 일을 찾고 있습니다. 일반적으로 내 로그의 특정 패턴 하위 집합에 대한 것이므로 주어진 패턴 / 정규 표현식에 대해 다음을 알아야합니다.
나는 일반적으로 가치가있을만큼 복잡해지기 때문에 펄을 사용합니다.
펄이 아닌 예제는 200이 아닌 상태 코드에 대한 분당 quickie hitrate입니다.
tail -9000 access_log | grep -v '" 200 ' | cut -d: -f2,3 | uniq -c
따옴표-공간 -200- 공간이 http 상태 코드와 만 일치한다고 가정하고 그 grep을 사용하여 부정 행위하고 있습니다 .... awk 또는 perl을 사용하여 필드를 분리 할 수 있습니다.
펄에서보다 복잡한 예는 패턴의 적중률 변화를 시각화하는 것입니다.
펄에 익숙하지 않은 경우 아래 스크립트에서 씹을 것이 많습니다.
코드는 다음과 같습니다.
#!/usr/bin/perl
# script to show changes in hitrates for any regex pattern
# results displayed with arbitrary intervals
# and ascii indication of frequency
# gaps are also displayed properly
use Date::Manip;
use POSIX qw(strftime);
$pattern=shift || ".";
$ival=shift || 60;
$tick=shift || 10;
$minb=undef;
while (<>){
next unless /$pattern/;
$stamp="$1 $2" if m[(../.../....):(..:..:..)];
$epoch = UnixDate(ParseDate($stamp),"%s");
$bucket= int($epoch/$ival)*$ival;
$minb=$bucket if $bucket<$minb || !defined($minb);
$maxb=$bucket if $bucket>$maxb;
$count{$bucket}++;
}
# loop thru the min/max range to expose any gaps
for($t=$minb;$t<=$maxb;$t+=$ival){
printf "%s %s %4d %s\n",
$t,
strftime("%m/%d/%Y %H:%M:%S",localtime($t)),
$count{$t}+0,
substr("x"x100,0,$count{$t}/$tick
);
}
표준 측정 항목 만 처리하려면 Checkout
여기 내 'sed'예는 아파치 로그의 기본 형식을 읽고 자동 처리를 위해 더 편리한 것으로 변환합니다. 전체 행은 정규식으로 정의되고 변수는 '#'을 구분 기호로 사용하여 출력에 저장 및 기록됩니다.
입력의 단순화 된 표기법은 다음과 같습니다. % s % s % s [% s] "% s"% s % s "% s" "% s"
입력 줄 예 : xx.xx.xx.xx--[29 / Mar / 2011 : 12 : 33 : 02 +0200] "GET /index.html HTTP / 1.0"200 9443 "-" "Mozilla / 4.0"
출력 행 예 : xx.xx.xx.xx #-#-# 29 / Mar / 2011 : 12 : 33 : 02 + 0200 # GET /index.html HTTP / 1.0 # 200 # 9443 #-# Mozilla / 4.0
cat access.log | \
sed 's/^\(.*\) \(.*\) \(.*\) \[\(.*\)\] \"\(.*\)\" \(.*\) \(.*\) \"\(.*\)\" \"\(.*\)\"$/\1#\2#\3#\4#\5#\6#\7#\8#\9/g'
정규 표현식의 힘을 느껴보십시오 :-)
나는 파일을 tailing 또는 cat'ing하여 awk를 많이 사용합니다. 매일 밤마다 각 서버에 대한 웹 보고서를 제공합니다. 로그 파일과 LogFormat에 따라 작동하도록 하나의 라이너 중 일부를 편집해야합니다.
다음은 간단한 예입니다.
404/500 상태 코드만으로 서버의 로그를 조정하려면 다음을 수행하십시오.
# $6 is the status code in my log file
tail -f ${APACHE_LOG} | awk '$8 ~ /(404|500)/ {print $6}'
<스닙>
echo ""
#echo "Hits by source IP:"
echo "======================================================================"
awk '{print $2}' "$1" | grep -ivE "(127.0.0.1|192.168.100.)" | sort | uniq -c | sort -rn | head -25
echo ""
echo ""
#echo "The 25 most popular pages:"
echo "======================================================================"
awk '{print $6}' "$1" | grep -ivE '(mod_status|favico|crossdomain|alive.txt)' | grep -ivE '(.gif|.jpg|.png)' | \
sed 's/\/$//g' | sort | \
uniq -c | sort -rn | head -25
echo ""
echo ""
echo "The 25 most popular pages (no js or css):"
echo "======================================================================"
awk '{print $6}' "$1" | grep -ivE '(mod_status|favico|crossdomain|alive.txt)' | grep -ivE '(.gif|.jpg|.png|.js|.css)' | \
sed 's/\/$//g' | sort | \
uniq -c | sort -rn | head -25
echo ""
#echo "The 25 most common referrer URLs:"
echo "======================================================================"
awk '{print $11}' "$1" | \
grep -vE "(^"-"$|/www.$host|/$host)" | \
sort | uniq -c | sort -rn | head -25
echo ""
#echo "Longest running requests"
echo "======================================================================"
awk '{print $10,$6}' "$1" | grep -ivE '(.gif|.jpg|.png|.css|.js)' | awk '{secs=0.000001*$1;req=$2;printf("%.2f minutes req time for %s\n", secs / 60,req )}' | sort -rn | head -50
exit 0
</ snip>
내가 대부분의 시간을 할애하는 것은 시간을 기준으로 로그 섹션을 읽는 것이므로 관심있는 기간을 꺼내기 위해 sed를 사용하여 다음 스크립트를 작성했습니다. 내가 온 모든 로그 파일에서 작동합니다. 보관 된 로그도 처리 할 수 있습니다.
#! / bin / bash #이 스크립트는 두 값 사이의 줄 집합을 반환해야합니다. 주된 목적은 두 번 사이의 로그 파일을 검색하는 것입니다. # 스크립트 사용법 : logship.sh "start" "stop"파일 # 파일에 날짜 범위에 "/"가 포함 된 경우 다음 두 줄은 이스케이프 문자를 추가하여 해당 문자를 검색 할 수 있도록합니다. start = $ (에코 "$ 1"| sed 's / \ // \\\ // g') stop = $ (에코 "$ 2"| sed 's / \ // \\\ // g') zipped = $ (echo "$ 3"| grep -c "gz $") # 파일이 압축되어 있는지 여부를 나타냅니다 [ "$ zipped"== "1"]이면; # 파일이 압축 된 경우 sed 전에 zcat을 통해 전달하십시오. zcat $ 3 | sed -n "/ $ start /, / $ stop / p"; 그밖에 sed -n "/ $ start /, / $ stop / p"$ 3; # 압축되지 않은 경우 sed를 실행하십시오. fi
sed 또는 awk가 아니지만 아파치 및 아이스 캐스트 로그 파일을 처리하는 데 유용한 두 가지가 있습니다.
AWStats 에는 logresolvemerge.pl 이라는 매우 유용한 스크립트가 있습니다.이 스크립트 는 여러 압축 또는 압축되지 않은 로그 파일을 결합하고 듀피를 제거하며 타임 스탬프별로 정렬합니다. 또한 DNS 조회를 수행하고 멀티 스레드를 실행하도록 구성 할 수 있습니다. awstats와 함께 사용할 때 특히 유용합니다. awstats는 현재 데이터베이스보다 오래된 타임 스탬프가있는 로그 라인을 추가 할 수 없으므로 모든 항목을 순서대로 추가해야하지만 logresolvemerge.pl에서 모든 항목 을 처리하기 만하면 매우 간단합니다 .
sed와 awk는 일반적으로 문자열로 취급하기 때문에 날짜 처리가 매우 나쁩니다. awk에는 시간과 날짜 기능이 있지만 그다지 많지 않습니다. 예를 들어 파일에서 정확한 타임 스탬프가 발생하지 않으면 (두 타임 스탬프 사이의 행 범위를 추출하는 것은 어렵습니다) 값이 크더라도 Chris의 예에는 정확히이 문제가 있습니다. 이를 처리하기 위해 로그 파일 타임 스탬프 범위를보고하고 원하는 날짜 또는 시간 형식을 사용하여 타임 스탬프 범위별로 청크를 추출 할 수 있는 PHP 스크립트 를 작성했습니다 (로그 파일의 타임 스탬프 형식과 일치하지 않아도 됨).
이 주제를 유지하기 위해 다음과 같은 유용한 어 키즘이 있습니다. 아파치 또는 아이스 캐스트 로그에서 제공되는 총 바이트 수를 가져옵니다.
cat access.log | awk '{ sum += $10 } END { print sum }'
icecast 로그에서 연결된 총 시간 (초)을 가져옵니다.
cat access.log | awk '{ sum += $13 } END { print sum }'