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

수행절차

  1. 데이터 필터링
    1. 불필요한 데이터를 미리 제거한다.여기서는 테스트,모니터링용 주소 제외
    2. 사용자 호출 중심으로 필터링한다 여기서는 .do ( 각종 img등 제외)
  2. 주소 단순화 
    1. 세부 파라메터는 제거한다.(.do?action=abc&data=b ==> .do?action=abc )
  3. 데이터 단순화 및 저장
    1. IP, 날짜시각, URI, 응답코드
  4. 날짜 시각 URI 횟수
    1. 저장한 파일 읽기
    2. AWK 수행
      1. 배열구분자 지정
      2. 각 줄에 대하여 count[날짜시각,주소]++
      3. 출력
        1. 연월일 시각 URI 횟수

해설

파이프 및 regexp를 사용한 필터링, awk를 사용한 테이블 구성

  1. ".do?" 만 출력하기 ( grep "\.do\?")
  2. testapp가 있는 줄은 제외하기(grep -v testapp)
  3. &로 시작해서 공백을 만날때까지를 null스트링으로 치환하기.
  4. 새로운 포맷으로저장
    1. 10.10.10.10 16/Jan/2016:00 /MainAction.do?ActionName=RefreshSesseion 200
    2. 첫번째 컬럼, 네번째컬럼의 두번째글자부터("["제외), 7번째컬럼(URI), 9번째컬럼 
  5. 생략(아래 awk 참조)
  6. Jan을01로, Feb를 02로 Mar를 03으로 치환하기
    1. sed -e 's/Jan/01/g' -e 's/Feb/02/g' -e 's/Mar/03/g
    2. 16/Jan/2016:00 /MainAction.do?ActionName=RefreshSesseion 20
      ==>
      16/01/2016:00 /MainAction.do?ActionName=RefreshSesseion 20
  7. 날짜필드를 구분하여 dt 배열에, 연:시를 구분하여 yh에, 분리한 것을 출력하기.
    1. 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

    awk '{split($1, dt, "/"); split(dt[3], yh, ":"); print yh[1] dt[2] dt[1],yh[2],$2,$3}'

    {
      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

    댓글

    이 블로그의 인기 게시물

    4,5,6 띠 저항의 색띠를 읽는 법(띠저항 값)

    수지에서 인천공항 리무진 버스 (인천공항버스정보)(2022년3월업데이트)

    수지에서 김포공항 리무진 버스 ( 2022년 3월 업데이트 )