텍스트처리_10 웹 서버 로그 파일에서 특정 상태값만 취득하기

 
  • 출처 : 유닉스 리눅스 쉘스크립트 예제사전_한빛미디어

명령어: awk
키워드: 접속 로그, 로그 해석, 변형
사용처: 아파치 접속 로그에서 스테이터스 404(Not Found) 에러를 반환한 리퀘스트 로그를 가공해서 파일명만 추출하고 싶을 때


실행예제

$ cat access_log
xx.xx.xx.xx - - [06/Jan/2014:05:58:35 +0900] "GET / HTTP/1.1" 200 83 "-" "-"
yy.yy.yy.yy - - [06/Jan/2014:06:01:43 +0900] "GET /index.html HTTP/1.1" 200 304
yy.yy.yy.yy - - [06/Jan/2014:06:01:44 +0900] "GET /title.gif HTTP/1.1" 404 763
yy.yy.yy.yy - - [06/Jan/2014:06:01:44 +0900] "GET /title.gif HTTP/1.1" 200 763

$ ./log-select.sh
$ cat access_log.404
/tittle.gif

스크립트

#!/bin/sh

logfile="access_log"

# 로그 파일이 존재하지 않으면 종료
if [ ! -f "$logfile"]; then  #------------------------------------ 1(if문)
    echo "대상 로그 파일이 존재하지 않습니다: $logfile" >&2
    exit 1
fi

# HTTP 스테이터스를 외부 파일에 출력
awk '$(NF-1)==404 {print $7}' "$logfile" > "${logfile}.404"  # --- 2

   

해설

이 스크립트는 아파치 접속 로그에서 HTTP 스테이터스가 404(Not Found)인 파일을 추출합니다. 추출한 파일 목록은 “(로그 파일명).404”가 파일명인 파일에 출력합니다. HTTP 스테이터스 404(Not Found)인 리퀘스트를 분석하는 것은 링크가 끊긴 페이지를 찾을 때 좋은 방법입니다. 따라서 정기적으로 이런 스크립트로 로그 감시하는 경우가 많습니다.

예제에서는 다음 형식으로 아파치 접속 로그가 출력된다고 가정합니다.

  • 파일 1 아파치 common 형식 로그 예
    192.168.1.1 - - [06/Jan/2014:05:58:35 +0900] "GET /index.html HTTP/1.1" 200 83
    

HTTP 스테이터스 번호는 뒤에서 두 번째 컬럼입닏.ㅏ 따라서 뒤에서 두 번째 컬럼이 404인 로그에서 파일명을 추출합니다. “404”라는 문자열을 단순히 grep하면 menu4040.html 같은 파일명도 추출하게 되므로 특정 컬럼값이 404와 일치하는 줄만 추출합니다.

1에서 우선 로그 파일 존재 여부를 확인합니다. -f 연산자로 대상이 일반 파일인지 확인하는데 부정 연산자 !와 함께 서서 파일이 존재하지 않거나 디렉터리 등이면 에러를 표시하고 종료합니다.

2는 awk 명령어로 로그를 추출하는 처리입니다. awk 명령어 내장 변수 NF를 이해를 위해 설명합니다.

NF는 awk 명령어로 지금 처리하는 줄의 컬럼 수(필드 수)를 가리킵니다. 예를 들어 {print $NF}라고 작성하면 마지막 컬럼을 표시할 수 있습니다. 예제에서는 “$(NF-1)”로 NF에서 1을 뺀 값을 지정하는데 이는 ‘뒤에서부터 두 번째’를 의미합니다. 로그 형식에서 보듯 여기에 HTTP 스테이터스 코드가 들어 있습니다. ‘주의사항’에서 다루지만 HTTP 리퀘스트 부분에 있는 공백 문자는 여러 가지이므로 컬럼을 앞에서부터 세지 않고 뒤에서부터 세서 가능하면 정확한 값을 취득합니다.

변수 NF 사용법을 알았으니 2로 돌아갑니다. awk 명령어에서 액션 { } 앞에 조건식을 지정할 수 있습니다. 이에 따라 컬럼 단위로 grep에 해당하는 동작이 가능ㅎ바니다. “$(NF-1)==404”라고 조건식을 써서 ‘뒤에서부터 두 번째 컬럼이 404일 때’ 즉, ‘HTTP 스테이터스가 404인 리퀘스트’를 지정합니다. 표시할 컬럼은 여기에서는 파일명만 출력하고 싶으므로 7번째 컬럼($7)만 출력합니다.

이렇게 해서 접속 로그에서 404 Not Found인 리퀘스트 파일명만 추출할 수 있습니다. 정기적으로 이런 스크립트를 실행하면 링크가 끊긴 파일을 찾을 수 있습니다.

   

주의사항

  • 웹 서버를 공격할 목적으로 RFC를 위반한 이상한 리퀘스트가 올 때도 있습니다(GET 뒤에 스페이스가 없다든지 등). 이럴 때 스페이스 위치가 다르므로 스크립트에서는 제대로 다루지 못합니다.

  • HTTP 스테이터스로 500번째 에러를 돌려주는 리퀘스트를 취득하려면 다음처럼 작성합니다.

    awk '$(NF-1)>=500 {print $7}'
    

    특히 500번대 에러는 애플리케이션이 문제가 생겼거나 서버가 고부하 상태이거나 하는 이상이 생겼을 때 발생하므로 운영 시 중요한 로그입니다. 따라서 스크립트 등으로 추출해서 애플리케이션 상태를 감시하는데 사용할 수 있습니다.