(안정철 님에게 책 내용에 대해 발췌하는 것에 대해서 허락을 구하지 못하였습니다. 삭제를 요구하시면 바로 삭제 조취 하겠습니다.)
Session 02. 접속 로그 분석 방법
아파치 웹 서버에서 기본적으로 각 클라이언트의 요청을 기록하는 'access_log'는 이름에서도 느낄 수 있는 것처럼 웹 서버에 접근되는 모든 것을 기록하게 된다. 접속 로그는 방문자 정보를 얻는데 있어서 가장 중요한 역할을 담당하고 있다. 우선, 여러분들이 정보를 가져올 'access_log'는 다음과 같이 TransferLog 지시어를 사용하여 어느 위치에 로그를 남길 것인지 결정을 할 수가 있다.
TransferLog /usr/local/apache/logs/access_log
그 러나 1.3.X 버전부터 사용자 정의 로그 포맷을 지원하고 있다. 대부분의 웹 서버들은 CLF(Common Log Format)로 파일을 생성하고 있으며, 이외에도 ELF(Extended Log Format), 그리고 Combined Log Format이 있다. 몇몇 서버들은 이외의 다른 형식 포멧을 사용학 있지만 CLF와 비슷한 형식을 취하고 있으며, 아파치 웹 서버는 기본적으로 이 포맷 방식을 따르고 있다. 지금 시점에서 여러분들이 사용하는 아파치 웹 서버의 로그 파일 설정은 다음과 같이 이루어져 있을 것이다.
CustomLog /usr/local/apache/access_log common
CLF는 각 클라이언트 요청에 한 라인으로 구성되어져 있고, 공백에 의해 각 필드는 7가지의 정보를 포함하여 구분되어 있다. 기본 포맷은 다음과 같은 형식을 갖추고 있다.
host ident authuser [date and time] request status bytes
첫 번째 필드는 원격지 호스트 주소 정보를 가지고 있다. 이것은 어느 누가 여러분들의 웹 사이트를 방문하였는가를 말해주는 것이다. 기본적으로, 이곳은 원격지 호스트의 정보가 IP 주소로 기입이 된다. 물론 아파치 웹 서버에서 호스트 이름을 찾아 기록할 수 있도록 설정할 수는 있으나, 아파치 1.3.X 버전에서는 성능상의 문제로 호스트 이름 대신 IP 주소로 기록하고 있다.
HostNameLookups off
아 파치 웹 서버는 IP 주소 대신 'HostNameLookups' 지시어를 사용하여 호스트 이름으로 기록을 할 수가 있다. 그러나 이러한 방법의 사용은 결과적으로 서버의 전반적인 성능을 떨어뜨릴 수 있는 요인 중의 하나가 될 수 있으므로 권장하지 않는다.
HostNameLookups on과 같이 사용하면 되며, on 이외에 double을 사용하여 역 방향 이름을 찾아 조회하는데도 사용할 수 있다.
logresolve 프로그램을 이용하여 IP 주소를 도메인으로 변경하는 방법은 아래와 같다.
[Test : /home/apache/bin/]logresolve -s log-stat.txt -c < text_log > new_log
[Test : /home/apache/bin/]more log-stat.txt
logresolve Statistics:
Entries : 500
With name :6
Resolves : 494
- Not found : 21
Cache hits : 472
Cache size : 22
Cache buckets : IP number * host
1 192.168.0.25 : Host not found
10 192.168.0.28 : Host not found
10 192.168.0.126 : Host not found
24 192.168.0.115 : Host not found
48 192.168.0.3 : Host not found
151 192.168.0.239 : Host not found
[Test : /home/apache/bin/]more log-stat.txt
logresolve Statistics:
Entries : 500
With name :6
Resolves : 494
- Not found : 21
Cache hits : 472
Cache size : 22
Cache buckets : IP number * host
1 192.168.0.25 : Host not found
10 192.168.0.28 : Host not found
10 192.168.0.126 : Host not found
24 192.168.0.115 : Host not found
48 192.168.0.3 : Host not found
151 192.168.0.239 : Host not found
두 번째 필드는 대부분의 경우 아무런 정보를 가지고 있지 않다는 '-'로 표시될 것이다. 이것은 방문자를 식별하는 정보를 얻는 경우에 이용되며, 실질적인 인증을 통한 로그인 이름이 아니라 사용자의 이메일 주소 및 식별할 수 있는 정보 등을 의미한다. 이 정보는 'identd'에 또는 브라우저의 직접적인 정보 제공에 의해 기록되어 질 수 있으나, 이러한 기능은 이미 오래 전에 사라져 사용되지 않고 있는 정보로 생각하면 된다.
세 번째 필드 또한 '-'로 표시되는 경우가 많으며, 방문자가 사용자 인증을 통하여 접속한 경우에 사용자의 로그인 이름이 기록된다. 네 번째 필드는 클라이언트가 서버의 자원을 요청한 시각이며, 다섯 번째 필드 "request"에는 요청한 자원이 어떤 것인지를 나타낸다. 주로 웹 서버의 자원을 클라이언트로 가져가기 위해 GET을 사용하며, 그 다음에는 실제적인 문서, 즉 URL을 의미한다. 클라이언트는 '/'를 시작으로 DocumentRoot 디렉토리로 지정한 경로에 기반하여 사용자에게 문서를 보여주게 된다.
URL의 마지막에는 HTTP 프로토콜 버전이 따라오게 되는데, 이 번호는 1.0 또는 1.1이 될 것이다. HTTP/1.0은 초창기의 프로토콜 버전으로 최근의 브라우저는 HTTP/1.1을 지원하고 1.0에 비해 많은 성능개선을 한 HTTP/1.1이 주로 사용되고 있다.
여 섯 번째의 필드는 웹 서버의 상태 코드를 의미하는 것으로서 클라이언트의 요청이 성공적이었는지, 또는 문제 발생이 있었는지를 코드번호로 나타내고 있다. 대부분의 경우에는 성공적인 전송을 의미하는 200번일 것이며, 서버에서 문제가 발생할 시에는 5XX번대로 시작한 에러코드가 기록될 것이다.
마지막인 일곱 번째 필드는 클라이언트에게 전송된 바이트를 나타낸다. 이것은 하루에 얼마나 데이터가 전송되었는가를 알아내고자 할 때 사용될 수 있다.
다음의 예를 살펴보자.
192.168.0.151 - - [01/Mar/2005:23:43:50 +0900] "GET /dist/ HTTP/1.1" 200 11177
192.168.0.151 의 IP 주소에서 요청한 것을 보면 2005년 3월 1일 11시 43분 50초에 Test 센터를 요청하였으며 HTTP/1.1 프로토콜을 사용하였다. 상태 코드는 200을 나타내는 것으로 보아 클라이언트에게 성공적으로 전송되었음을 알 수가 있고 총 11,177bytes가 전송되어졌다. 각 필드에 해당하는 의미를 간단하게 기술해 놓은 CLF(Common Log Format)을 구성하는 각 필드는 다음과 같다.
| 아이템 | 의미 |
|---|---|
| Host | 클라이언트의 호스트 이름이나 IP Address |
| Ident | IdentityCheck가 enable 되어 있고, 클라이언트가 ident에 응답을 보내면 identity 정보를 남기게 되며, 보통은 "- "로 대체된다. |
| Authuser | 인증이 있을 경우 여기에 사용자 이름이 기록되게 되며, 그렇지 않을 경우 "- "로 대체된다. |
| Date | 접속한 시간과 날짜를 나타내며, 포맷은 다음과 같다 : |
| Request | 클라이언트가 요청한 자료 |
| Status | 요청한 것에 대한 서버의 처리 사항으로 상태 코드라 한다. |
| Bytes | 헤더를 제외한 전송된 Byte 양 |
지금까지 기본 로그 포맷에 대하여 알아보았다. 이번에는 'CustomLog' 지시어를 이용한 사용자 정의 로그 포맷에 대해 살펴보고자 한다.
'CustomerLog' 지시어는 'TransferLog'의 기능을 내포하고 마찬가지로 로그 파일이 어느 위치에 저장되어야 할지를 가리키며 추가적으로 저장되는 로그의 포맷을 사용자에 의해 지정을 할 수가 있다. 이전에는 CLF(Common Log Format)이라 불리는 고정된 형식으로만 사용이 가능하였다. 그러나 지금은 CLF 포맷을 여러분들이 원하는 형태 즉, 필요한 정보로 맞춤 정장과도 같이 여러분들의 입맛대로 만들 수가 있는 것이다.
원하는 형태의 로그 파일을 만들기 위해서는 포맷을 지정하여야 하고, 이 역할을 'LogFormat' 지시어가 한다. 다음의 내용을 httpd.conf에서 찾아볼 수가 있을 것이다.
LogFormat "%h %l %u %t \"%r\" %>s %b" common
이 뜻은 인용 부호 "'' 안의 로그 포맷을 "common"의 이름으로 만드는 것이다. 각 문자들이 나타내는 것은 특정 정보를 의미하며, 기술한 순서에 따라 로그 파일에 기록된다. 로그 포맷으로 사용 가능한 변수와 이에 대한 의미는 다음 표와 같다.
| 포맷 | 의미 |
|---|---|
| %a | 원격지 IP 주소 |
| %A | 로컬 IP 주소 |
| %B | HTTP 헤더를 제외하고 전송된 바이트 |
| %b | HTTP 헤더를 제외하고 전송된 바이트. CLF 포맷에서는 전송된 것이 없을 경우 0으로 표시하기 보다는'-'로 표시한다. |
| %{FOOBAR}e | 서버에 의해 지정된 환경변수 |
| %f | 파일 이름 |
| %h | 원격지 호스트 |
| %H | 요청한 프로토콜 |
| %{Foobar}i | Foobar의 내용 : 클라이언트에서 서버로 요청된 헤더라인으로 예를 들자면, Referer 헤더일 경우 %{Referer}i로 사용되어 진다. |
| %l | 원격지 사용자 이름(이것이 사용되어 지기 위해서는 IdentityCheck가 반드시 enable 되어져 있어야 한다.) |
| %m | 요청 방식 |
| %{Foobar}o | 서버에서 응답되는 HTTP 헤더. 예를 들면 : %{Content-Type}o, %{Last-Modified}o |
%p |
요청을 처리하는 서버의 참조적인 포트 |
| %P | 현 요청을 처리하고 있는 아파치 자식 프로세서의 프로세스 ID |
| %q | 쿼리 문자열(쿼리가 있을 경우 "?" 뒤로 쿼리문이 포함되며 그렇지 않을 경우 공백으로 처리된다.) |
| %r | HTTP 메소드를 포함한 요청의 첫 라인 |
| %s | HTTP 상태 코드. 만약 클라이언트의 요청이 내부적인 리다이렉트를 발생시켰을 경우 %s는 초기 요청을 상태 코드를 %>s는 최종 상태 코드를 포함하게 된다. 일반저긍로 %s의 사용 보다는 %>s가 유용하다. |
| %t | 요청한 시간과 날짜(standard english format) |
| %{format}t | strftime() function을 이용한 포맷 형식에 따른 시간 [Day/Month/Year:Hours:Minutes:Seconds Time Zone] |
| %T | 요청을 처리하는데 걸린 시간(초) |
| %u | 인증이 요청된 원격 사용자 이름 |
| %U | 요청된 URL |
| %v | 요청을 처리하는 서버의 참조적인 서버 이름 |
| %V | UseCannoicalName 설정에 따른 서버 이름 |
여기서 많이 쓰이지 않는 'ident'와 'authuser' 필드는 제거하여 로그 파일에 기록되지 않게 할 수도 있으며, 다음과 같이 에이전트와 참조 로그를 한 로그 파일에 만드는 것도 가능하다.
LogFormat "%h %l %u %t \" %r\" %>s %b \" %{Referer}i\" \" %{User-Agent}i\" " combined
이와 같이 로그 포맷에 대해서 알아보았는데, 이외에 다른 방법들은 없을까? 'CustomLog'와 'LogFormat'을 이용한 효율적이고도 다양한 방법들로는 무엇이 있는지 함께 알아보도록 하자.
때 로는 HTTP의 각 상태코드 별로 로그를 취합하여 효율적인 분석이 필요한 경우도 있다. 이럴 경우에는 %와 변수 사이에 HTTP 상태 코드를 집어넣어 해당하는 이벤트가 발생하는 경우에 로그를 남길 수 있다. 예를 들어, 잘못된 링크만을 따로 저장하고 할 때에는
LogFormat %404{Referer}i BrokenLinks
CustomLog /usr/local/apache/logs/broken_links BrokenLinks
와 같이 사용하면 된다. 최근에는 멀티미디어 서비스 및 이미지의 사용이 많아지고 있는 추세로 로그 파일에 많은 양의 데이터가 쌓이고 있다. 이에 대한 해결책으로는 아파치의 'mod_setenvif' 모듈을 이용하는 것으로서 방안을 제시해 주고 있다.
(a) SetEnvIf Request_URI \.gif$ gif-image
(b) CustomLog gif-requests.log common env=gif-image
(c) CustomLog nongif-requests.log common env=!gif-image
(d) LogFormat "%h %l %u %t \" %r\" %>s %b" common
(e) SetEnvIf Request_URI \.gif$ image=gif
(f) SetEnvIf Request_URI \.$ image=jpg
(g) CustomLog logs/access_log common env=!image
(b) CustomLog gif-requests.log common env=gif-image
(c) CustomLog nongif-requests.log common env=!gif-image
(d) LogFormat "%h %l %u %t \" %r\" %>s %b" common
(e) SetEnvIf Request_URI \.gif$ image=gif
(f) SetEnvIf Request_URI \.$ image=jpg
(g) CustomLog logs/access_log common env=!image
(a) - (c) 까지는 gif 이미지를 gif-requests.log에, 그 이외의 것은 nongif-requests.log에 저장 하는 것이며, 나머지 (d) - (g)는 CLF 포맷으로 이미지 파일인 gif를 제외한 로그를 access_log에 남기라는 의미이다.
SetEnvIf Referer www\.test\.net apache_site_referral
www.Test.net 을 통해서 들어오게 되면 apache_site_referral 변수를 설정하여 로그를 남길 수도 있다. 한 가지 주의할 점은 SetEnvIf[NoCase]에 의한 환경 변수의 지정은 CustomLog와 같이 변수를 이용한 저장일 경우에는 CustomLog 지시어 전에 설정되어 있어야 한다.
지금까지 여러 다양한 방법의 사용을 알아보았다. 마지막으로 가상 호스트를 많이 운영하는 분들을 위하여 여러 개의 로그 파일을 하나의 파일로 만드는 방법을 보자.
LogFormat "%v [%A:%p] -> %h %l %u %t \" %r\" %>s %b" virtualhost
CustomLog logs/access_log virtualhost
CustomLog logs/access_log virtualhost
이 것은 기본 로그 포맷 앞에 "canonical name"과 IP 주소, 포트 번호를 나타내는 추가적인 정보가 더 기술되어 있다. 이러한 방식을 통한 운영은 OS 특성상 동시에 파일을 열 수 있는 개수의 제한 등으로 인하여 모든 가상 호스트마다 개별적인 로그 파일을 만들어 줄 수 없을 때 사용할 수가 있다.











::: 사람과 사람의 교감! 人터넷의 첫 시작! 댓글을 달아주세요! :::