apache log analysis script ( sed, awk ) 아파치 Access Log 분석 스크립트
아파치 Access Log 분석 스크립트
목표
- 날짜 시각 URI 횟수
- 20160116 00 /MainAction.do?ActionName=RefreshSesseion 101
- 날짜 시각 IP 횟수
- 20160116 00 10.10.10.10 5
필요 데이터 이해(공백 기준 구분)
아래는 아파치의 기본 access.log 이다.
10.10.10.10 - - [05/Jan/2016:00:00:31 +0900] "GET /MainAction.do?ActionName=RefreshSesseion&fake=9779425681 HTTP/1. 200 13
다음은 AWK를 통하여 잘라내고자 하는 데이터이다.($1: 공백에 의해 구분되는 첫번째 컬럼)
$1 IP 10.10.10.10
$4 시각 [16/Jan/2016:00:00:31
$7 URI /MainAction.do?ActionName=RefreshSesseion&fake=9779425681
$9 응답코드 200
$10 응답데이터바이트
중간 목표 포맷
10.10.10.10 16/Jan/2016:00 /MainAction.do?ActionName=RefreshSesseion 200
수행절차
- 데이터 필터링
- 불필요한 데이터를 미리 제거한다.여기서는 테스트,모니터링용 주소 제외
- 사용자 호출 중심으로 필터링한다 여기서는 .do ( 각종 img등 제외)
- 주소 단순화
- 세부 파라메터는 제거한다.(.do?action=abc&data=b ==> .do?action=abc )
- 데이터 단순화 및 저장
- IP, 날짜시각, URI, 응답코드
- 날짜 시각 URI 횟수
- 저장한 파일 읽기
- AWK 수행
- 배열구분자 지정
- 각 줄에 대하여 count[날짜시각,주소]++
- 출력
- 연월일 시각 URI 횟수
해설
파이프 및 regexp를 사용한 필터링, awk를 사용한 테이블 구성
- ".do?" 만 출력하기 ( grep "\.do\?")
- testapp가 있는 줄은 제외하기(grep -v testapp)
- &로 시작해서 공백을 만날때까지를 null스트링으로 치환하기.
- 새로운 포맷으로저장
- 10.10.10.10 16/Jan/2016:00 /MainAction.do?ActionName=RefreshSesseion 200
- 첫번째 컬럼, 네번째컬럼의 두번째글자부터("["제외), 7번째컬럼(URI), 9번째컬럼
- 생략(아래 awk 참조)
- Jan을01로, Feb를 02로 Mar를 03으로 치환하기
- sed -e 's/Jan/01/g' -e 's/Feb/02/g' -e 's/Mar/03/g
- 16/Jan/2016:00 /MainAction.do?ActionName=RefreshSesseion 20==>16/01/2016:00 /MainAction.do?ActionName=RefreshSesseion 20
- 날짜필드를 구분하여 dt 배열에, 연:시를 구분하여 yh에, 분리한 것을 출력하기.
- awk '{split($1, dt, "/"); split(dt[3], yh, ":"); print yh[1] dt[2] dt[1],yh[2],$2,$3}'
grep ( regexp를 이용한 검색 )
grep "\.do\?" | grep -v testapp
.do?가 있는 줄을 찾아 출력하고 , testapp 가 있는 줄을 제외하라
"패턴"이 있는 줄을 찾아 출력하라
cat data.txt | grep 패턴
grep 패턴 data.txt
grep "패턴" data.txt
sed ( regexp를 이용한 내용편집 )
cat access.log | sed 's/&[^ ]*//g'
sed 's/A/B/g'
s/A/B/g : A패턴을 찾아서 B로 바꾸는데 보이는대로 모두 바꿔라(g)
&로 시작하되 공백이 아닌([^ ]) 글자들(*) ==> &sdfasdf
[A-Za-z0-9 ] ==> 대문자,소문자,숫자,공백
* ==> 앞의 글자가 0개 이상 ( + 는 1개 이상 )
// ==> 바꿀 글자가 없음 ==> s/A//g ==> A패턴을 찾아서 지워라
응용
Jan을 01로, Feb를 02로 변경하라.(2개이상의 규칙적용하기)
cat report1.txt | sed -e 's/Jan/01/g' -e 's/Feb/02/g' -e 's/Mar/03/g'
system.config 파일에서 postgress를 모두 sqlite로 "변경하여 다시 저장하라."
sed -i 's/postgress/sqlite/g' system.config
awk ( regexp를 이용한 검색, 텍스트의 테이블화 )
10.10.10.10 - - [05/Jan/2016:00:00:31 +0900] "GET /MainAction.do?ActionName=RefreshSesseion&fake=9779425681 HTTP/1. 200 13
cat access.log | awk '{ print $1, substr($4,2), $7, $9 }' 10.10.10.10 16/Jan/2016:00 /MainAction.do?ActionName=RefreshSesseion 200패턴1
awk '{행마다수행하는내용}'
awk 'BEGIN{초기화내용}{행마다수행하는내용}END{모든행을 처리하고 마지막에 하는내용}'
awk -f awkfile
awkfile
BEGIN{
초기화내용
}
[condition 1]{
행마다수행하는내용
}
[condition 2]{
행마다수행하는내용
}
END{
모든행을 처리하고 마지막에 하는내용
}
아래는 2차원배열의 처리 방법에 대한 예시이다.
for(i in count){for(j in count[i]){printf("%s ", count[i][j]);}} 가 수행되지 않아 아래와 같이 함.
BEGIN{
SUBSEP="@" # 배열간 구분자 다시 지정 ( 나중에 @를 공백으로 치환하기 위해 )
}{
count[substr($2,1,14),$3]+=1; # count[일월년,URI] 배열에 출현횟수저장
}END{
for(i in count){ # count 배열의 일월년@URI 을 i 라는 키로 해서 for loop
split(count[i], row); # 각 줄(일월년)의 컬럼을 잘라서 row 배열로 만들기
for(j in row) # row 배열에 대하여
{print i, row[j] } # 일월년@URI 갯수 형태로 출력
}
}
16/01/2016:00 /MainAction.do?ActionName=RefreshSesseion 20
{
split($1, dt, "/"); # $1필드를 "/"를 구분자로 쪼개어 dt 배열에 넣기
split(dt[3], yh, ":"); # dt[3] 필드를 ":" 로 구분하여 yh배열에 넣기
#이제 연 월 일 시각이 쪼개어졌으므로 순서를 변경하여 출력한다
print yh[1] dt[2] dt[1], yh[2], $2, $3 # 연월일 시 URI 갯수
}
원문
#기초작업cat access*.log | grep "\.do\?" | grep -v testapp \
| grep -v "\/monitoring" | grep -v balancer-manager \
| sed 's/&[^ ]*//g' \
| awk '{ print $1, substr($4,2), $7, $9 }' > report1.txt
sed -e 's/[\/]/ /g' -e 's/:/ /g' | awk '{print $4, $3=="Jan"?"01":($3=="Feb"?"02":"03"),$2,$5,$6,$1,$8}'
# 날짜시각 함수 횟수
cat report1.txt | awk '\
BEGIN{SUBSEP="@"}\
{count[substr($2,1,14),$3]+=1;}\
END{\
for(i in count){\
split(count[i], row);\
for(j in row)\
{print i, row[j] }\
}\
}' | sed "s/@/ /g" \
|sed -e 's/Jan/01/g' -e 's/Feb/02/g' -e 's/Mar/03/g' \
|awk '{split($1, dt, "/"); split(dt[3], yh, ":"); print yh[1] dt[2] dt[1],yh[2],$2,$3}'\
| sort > report2.txt
# 날짜 ip 횟수
cat report1.txt | awk '\
BEGIN{SUBSEP="@"}\
{count[substr($2,1,14),$1]+=1;}\
END{\
for(i in count){\
split(count[i], row);\
for(j in row)\
{print i, row[j] }\
}\
}' | sed "s/@/ /g" \
|sed -e 's/Jan/01/g' -e 's/Feb/02/g' -e 's/Mar/03/g' \
|awk '{split($1, dt, "/"); split(dt[3], yh, ":"); print yh[1] dt[2] dt[1],yh[2],$2,$3}'\
| sort > report3.txt
참고
http://sunshowers.tistory.com/32
댓글