it-swarm-ko.tech

Apache 로그를 구문 분석하는 데 유용한 awk 및 grep 스크립트가 있습니까?

로그 분석기를 사용할 수 있지만, 현재 발생하는 상황을 확인하기 위해 최근 웹 로그를 구문 분석해야하는 경우가 종종 있습니다.

때로는 특정 파일을 요청하는 상위 10 IP를 파악하는 것과 같은 일을합니다.

cat foo.log | grep request_to_file_foo | awk '{print $1}' |  sort -n | uniq -c | sort -rn | head

툴박스에 무엇이 있습니까?

70
deadprogrammer

Awk만으로 Apache 로그 파일로 거의 모든 작업을 수행 할 수 있습니다. 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

Shell 명령의 일부 또는 awk 스크립트 자체에서 결과를 순서대로 가져 오기 위해 sort를 통해 출력을 파이프 할 수도 있습니다.

awk -F'[ "]+' '$7 == "/" { ipcount[$1]++ }
    END { for (i in ipcount) {
        printf "%15s - %d\n", i, ipcount[i] | sort } }' logfile.log

후자는 다른 정보를 인쇄하기 위해 awk 스크립트를 확장하기로 결정한 경우 유용합니다. 모두 당신이 찾고자하는 문제입니다. 이것들은 당신이 관심있는 무엇이든을위한 출발점으로 작용해야합니다.

54
Mark

내가 상상할 수없는 이유로 다른 사람이 본 적이없는 것 중 하나는 Apache 로그 파일 형식을 실제로 중요한 정보가 포함 된보다 쉽게 ​​구문 분석 가능한 버전으로 변경하는 것입니다.

예를 들어, HTTP 기본 인증을 사용하지 않으므로 해당 필드를 기록 할 필요가 없습니다. I am 각 요청을 처리하는 데 걸리는 시간에 관심이 있으므로 추가 할 것입니다. 한 프로젝트의 경우 서버가 요청보다 느린 요청을 처리하는 경우 (로드 밸런서에서) 알고 싶습니다. 우리는 다시 프록시하는 서버의 이름을 기록합니다.

다음은 한 서버의 Apache 구성에서 발췌 한 것입니다.

# 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에 소비해야합니까?

24
Dan Udey

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;
16
Vihang D

최근 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

소스

6
anoopjohn

액세스 로그의 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

그들은 내가 가장 좋아하는 "한 라이너"중 일부입니다 :)

5
f4nt

여기 내 'sed'예에서는 기본 형식의 Apache 로그를 읽고 자동 처리를 위해 더 편리한 것으로 변환합니다. 전체 행은 정규식으로 정의되고 변수는 '#'을 구분 기호로 사용하여 출력에 저장 및 기록됩니다.

입력의 단순화 된 표기법은 다음과 같습니다. % 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'

정규 표현식의 힘을 느껴보십시오 :-)

3
Kris

일반적인 질문 목록을 작성하면이 질문에 대한 답변을 얻을 수 있습니다. 가장 일반적인 질문은 다음과 같습니다.

  • 왜 적중률이 변경 되었습니까?
  • 전체 응답 시간이 왜 증가합니까? '.

활성 및 최근 완료된 요청에 대한 적중률 및 대략적인 응답 시간에 대해 서버 상태 페이지 (mod_status를 통해)를 모니터링하여 이러한 변경 사항을 알 수 있습니다 (거대한 데이터 더미가 누락되었지만 샘플이 충분하다는 것을 잘 알고 있음).

다음 LogFormat 지시문을 사용합니다 (% T는 정말 유용합니다)

LogFormat "%h %l %u %t \"%r\" %>s %b 
    \"%{Referer}i\" \"%{User-Agent}i\" %T" custom

원인-결과와 가장 먼저 일어난 일을 찾고 있습니다. 일반적으로 내 로그의 특정 패턴 하위 집합에 대한 것이므로 주어진 패턴/정규 표현식에 대해 다음을 알아야합니다.

  • 주어진 패턴 (ip 주소 또는 cgi 문자열 또는 매개 변수 등)에 대한 간격 (분 또는 시간) 당 적중 횟수
  • 대략적인 응답 시간 히스토그램 (% T 매개 변수 사용)

나는 일반적으로 가치가있을 정도로 복잡해지기 때문에 Perl을 사용합니다.


Perl 이외의 예는 200이 아닌 상태 코드에 대한 분당 quickie 적중률입니다.

tail -9000 access_log | grep -v '" 200 ' | cut -d: -f2,3 | uniq -c

따옴표-200-공백이 http 상태 코드와 만 일치한다고 가정하고 그렙으로 부정 행위를합니다 .... awk 또는 Perl을 사용하여 필드를 분리 할 수 ​​있습니다. 정확하지 않을 수 있음을 명심하십시오.


Perl에서보다 복잡한 예는 패턴의 적중률 변화를 시각화하는 것입니다.

특히 Perl에 익숙하지 않은 경우 아래 스크립트에서 씹을 것이 많습니다.

  • stdin을 읽으므로 로그의 일부를 사용하고 꼬리 (특히 tail -f와 함께)를 사용하고 greps 및 기타 필터링을 사용하거나 사용하지 않고 ...
  • 정규식 해킹 및 Date :: Manip 사용으로 Epoch 타임 스탬프 추출
  • 응답 시간이나 기타 임의의 데이터를 추출하기 위해 약간만 수정할 수 있습니다.

코드는 다음과 같습니다.

#!/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

  • 로드 밸런서 뒤에 여러 개의 아파치가있는 경우 모든 로그를 가져 오는 'mergelog'
  • 웹알 라이저 (또는 awstats 또는 기타 일반적인 분석기).
3
ericslaw

이미지를 핫 링크하는 사람 :

awk -F\" '($2 ~ /\.(jpg|gif)/ && $4 !~ /^http:\/\/www\.mydomain\.com/){print $4}' access_log | sort | uniq -c | sort
2
rkthkr

나는 파일을 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>

2
Michael Steinfeld

Sed 또는 awk는 아니지만 Apache 및 icecast 로그 파일을 처리하는 데 유용한 두 가지가 있습니다.

AWStats 에는 logresolvemerge.pl 이라는 매우 유용한 스크립트가 있습니다.이 스크립트는 여러 개의 압축 또는 압축되지 않은 로그 파일을 결합하고 중복을 제거하며 타임 스탬프별로 정렬합니다. 또한 DNS 조회를 수행하고 멀티 스레드를 실행하도록 구성 할 수 있습니다. awstats는 현재 데이터베이스보다 오래된 타임 스탬프가있는 로그 라인을 추가 할 수 없기 때문에 awstats와 함께 사용할 때 특히 유용합니다. 따라서 모든 항목을 순서대로 추가해야하지만 logresolvemerge에서 척 everything을 사용하면 매우 쉽습니다. pl 그리고 그것은 모두 멋지게 나타납니다.

sed와 awk는 일반적으로 문자열로 취급하기 때문에 날짜 처리가 매우 나쁩니다. awk에는 시간과 날짜 기능이 있지만 그다지 많지 않습니다. 예를 들어 파일에서 정확한 타임 스탬프가 발생하지 않는 경우 (두 타임 스탬프 사이의 행 범위를 추출하는 것은 어렵습니다)-Chris의 예에는 정확히이 문제가 있습니다. 이를 처리하기 위해 a PHP script 라는 로그 파일 타임 스탬프 범위를보고하고 원하는 날짜 또는 시간 형식을 사용하여 타임 스탬프 범위별로 청크를 추출 할 수 있습니다. (로그 파일의 타임 스탬프 형식과 일치 할 필요는 없습니다).

이 주제를 유지하기 위해 다음과 같은 유용한 어 키즘이 있습니다. Apache 또는 icecast 로그에서 제공되는 총 바이트 수를 가져옵니다.

cat access.log | awk '{ sum += $10 } END { print sum }'

Icecast 로그에서 연결된 총 시간 (초)을 가져옵니다.

cat access.log | awk '{ sum += $13 } END { print sum }'
1
Synchro

내가 대부분의 시간을 할애하는 것은 시간을 기준으로 로그 섹션을 읽는 것이므로 관심있는 기간을 꺼내기 위해 sed를 사용하여 다음 스크립트를 작성했습니다. 내가 온 모든 로그 파일에서 작동합니다. 보관 된 로그도 처리 할 수 ​​있습니다.

 #!/bin/bash 
 #이 스크립트는 두 값 사이의 줄 집합을 반환해야합니다. 주된 목적은 두 번 사이 로그 파일을 검색하는 것입니다. 
 # 스크립트 사용법 : logship.sh "start" "stop"파일 
 
 # 파일에 날짜 범위에 "/"가 포함 된 경우 다음 두 줄은 이스케이프 문자를 추가하여 해당 항목을 검색 할 수 있습니다. 문자 
 start = $ (echo "$ 1"| sed 's/\ // \\\ // g') 
 stop = $ (echo "$ 2"| sed 's/\//\\\//g')

zipped=$(echo "$ 3"| grep -c "gz $") # 파일이 압축되었는지 여부를 나타냅니다 
 
 if [ "$ zipped"== "1"]; # 파일이 압축 된 경우 sed 
 전에 zcat을 통해 전달하십시오. zcat $ 3 | sed -n "/$start/,/$stop/p";
else
 sed -n"/ $ start /,/$ stop/p "$ 3; # 압축되지 않은 경우 sed 
 fi 
를 실행하십시오.
1
Chris

이 오래된 스레드를 복구하면 큰 로그 파일을 위해 asql을 포기한 후 서버 오류에서도 솔루션을 다시 찾았습니다 .wtop here 에 대해 발견했습니다. 매우 유연하고 강력한 통계를 기록하고 통계를 얻습니다 (공식 N은 공식적으로 here

0
aseques