에루샤
erusya
Back-end Developer
Web Geek/Otaku
에루샤 프로필 이미지
개발

Nginx 로그 포맷 수정하는 법 (log_format)

Nginx를 사용한다면 기본적으로 /var/log/nginx/access.log 와 error.log 에 웹 서버의 로그가 기록이된다.
물론 그냥 나둬도 그냥저냥 로깅용으로 사용할 수 있는데 특수 목적에 맞게 로그의 포맷을 적절히 수정해서 쓰면 추후 모니터링/관리할때 매우 편하다.

그래서 나도 나한테 필요한 로그포맷을 이것저것 시도해보았고, 시도해보는 과정에서 사용했던 여러 변수나 포맷, 사용예시등을 정리해보려고 한다.

통상적인 접근요청이나 분석용 로그는 access.log에 쌓이므로 여기서는 access.log에 초점을 맞추어 이야기해보겠다.


로그포맷과 변수

log_format combined '$remote_addr - $remote_user [$time_local] '
                    '"$request" $status $body_bytes_sent '
                    '"$http_referer" "$http_user_agent"';Copy

로그포맷은 위의 기본 형태를 띄고있다.
nginx.conf 설정에 없더라도 기본적으로 위 형태의 로그가 access.log에 쌓이게된다.

위에서 사용된 각각의 변수는 아래와 같은 뜻을 가지고있다.

변수명설명실제 데이터 예시
$remote_addr클라이언트 IP 주소123.123.123.123
$remote_user사용자가 HTTP Basic Auth를 통해 로그인했을때 이름admin, - 등
$time_local요청이 기록된 시간26/Feb/2025:14:05:32 +0000
$request요청 방식 및 URIGET /index.html HTTP/1.1
$statusHTTP 응답 코드200, 404, 500 등
$body_bytes_sent클라이언트로 전송된 응답 바이트 크기12,345
$http_referer요청을 보낸 이전 페이지https://google.com, - 등
$http_user_agent클라이언트의 User-AgentMozilla/5.0 (iPhone; CPU iPhone OS 16_7 like Mac OS X)

변수명을 보자면 서버가 클라이언트로 요청을 받은 기록에 대한 일반적인 내용이 적혀있음을 알 수 있다.
일반적으로 로그로써의 가치를 가진다면 요청자의 요청내용과 정보등이 충분히 담겨있으면 된다.

위의 변수명 말고도 추가로 사용할 수 있는 변수가 꽤 많다.
다음으로는 그런 변수들에 대해서 일괄적으로 알아보자. 자주 쓰이거나 유용한 변수는 주황색으로 추가 표기 해두겠다.

기본적인 클라이언트 및 요청 관련 변수

변수명설명실제 데이터 예시
$remote_addr클라이언트 IP 주소123.123.123.123
$remote_port클라이언트 포트 번호80, 443 등
$remote_user사용자가 HTTP Basic Auth를 통해 로그인했을때 이름admin, - 등
$time_local로컬 타임존의 요청 시간26/Feb/2025:15:20:45 +0000
$time_iso8601ISO 8601 형식의 요청 시간2025-02-26T15:20:45+00:00
$msec요청 시간을 초 단위로 출력1708882295.123
$request_time요청이 처리되는 데 걸린 시간(초 단위)0.034
$request_length요청의 바이트 크기2345
$request요청 라인GET /index.html HTTP/1.1
$request_method요청 방식GET, POST, PUT 등
$request_uri요청된 URI/index.html?query=123
$query_string요청의 쿼리 문자열query=123
$uri요청된 URI에서 query_string을 제외한 경로/index.html
$document_uri$uri 와 동일/index.html
$document_root현재 요청을 처리하는 루트 디렉토리/
$realpath_root$document_root의 실제 경로/var/www/web
$server_protocol요청된 프로토콜HTTP/1.1, HTTP/2.0 등
$server_name요청된 서버 이름(Host 헤더에서 가져옴)web
$server_addr서버의 IP 주소111.111.111.111
$server_port요청이 들어온 서버의 포트 번호80, 443 등
$scheme요청된 프로토콜http, https
$httpshttps인지 아닌지 판단하는 값on, null(빈값)

응답 관련 변수

변수명설명실제 데이터 예시
$statusHTTP 응답 코드200, 404, 500 등
$body_bytes_sent실제 클라이언트에게 전송된 바이트 크기12,345
$bytes_sent응답된 전체 크기12,567
$content_length응답 헤더의 Content-Length 값200
$content_type응답의 Content-Type 값text/html, image/png 등

HTTP 헤더 관련 변수

변수명설명실제 데이터 예시
$http_hostHost 헤더 값example.com
$http_refererReferer 헤더 값https://google.com
$http_user_agentUser-Agent 헤더 값Mozilla/5.0 (Windows NT 10.0; Win64; x64)
$http_cookieCookie 헤더 값sessionid=abc123; theme=dark
$http_acceptAccept 헤더 값 (지원하는 MIME 타입)text/html,application/xhtml+xml
$http_accept_languageAccept-Language 헤더 값 (언어 설정)en-US,en;q=0.9,ko;q=0.8
$http_accept_encodingAccept-Encoding 헤더 값 (압축 형식)gzip, deflate, br 등
$http_connectionConnection 헤더 값 (keep-alive, close 등)keep-alive
$http_cache_controlCache-Control 헤더 값max-age=0
$sent_http_content_length응답의 Content-Length 값200
$sent_http_content_type응답의 Content-Type 값text/html, image/png 등
$sent_http_location리디렉션 시 Location 헤더 값https://example.com

SSL/TLS 관련 변수

변수명설명실제 데이터 예시
$ssl_protocol SSL/TLS 프로토콜TLSv1.2, TLSv1.3 등
$ssl_cipher사용된 SSL 암호화 방식ECDHE-RSA-AES128-GCM-SHA256
$ssl_session_idSSL 세션 ID3D7A6B4F34D97D08A23E1234567890AB
ssl_client_cert클라이언트의 SSL 인증서- (없을수도 있음)

캐시 및 프록시 관련 변수

변수명설명실제 데이터 예시
$upstream_cache_statusHIT, MISS, BYPASS 등 캐시 상태HIT 등
$upstream_addr요청이 전달된 업스트림 서버 주소192.168.1.20:8080
$upstream_status업스트림 서버의 응답 코드200, 500등
$upstream_response_time업스트림의 응답 시간(초)0.123
$upstream_connect_time업스트림의 서버와의 연결시간(초)0.015
$upstream_header_time업스트림 헤더 수신 시간0.050

쿠키 및 특정 요청 정보 변수

변수명설명실제 데이터 예시
$cookie_<name>특정 쿠키값$cookie_sessionid = abc123
$arg_<name>특정 쿼리 문자열 값$arg_userid = 123
$is_args요청 URI에 ? 포함 여부? 또는 빈값

정~~~말 변수가 많다.
여기서 이제 우리가 해야할것은 목적에 맞게 로그 포맷을 짜깁기해서 응용해보는 정도이다.


커스텀 로그 포맷 예제

간결한 로그 포맷

log_format minimal '$time_iso8601 | $request | $status | $remote_addr | $body_bytes_sent Byte';
access_log /var/log/nginx/access.log minimal;

# Example
2025-02-26T15:32:01+00:00 | GET /index.html HTTP/1.1 | 200 | 192.168.1.10 | 12543 Byte
2025-02-26T15:32:02+00:00 | GET /style.css HTTP/2.0 | 200 | 203.0.113.5 | 8765 Byte
2025-02-26T15:32:03+00:00 | POST /api/login HTTP/1.1 | 401 | 45.77.33.20 | 512 ByteCopy

로그파일을 간단하게 보려할때 적용해볼만한 내용, 핵심정보만 빠르게 보며 가독성을 대폭 늘린 방식의 로그이다.

JSON 로그 형식 포맷 (access.json)

log_format json '{"time":"$time_iso8601",'
                '"client_ip":"$remote_addr",'
                '"method":"$request_method",'
                '"uri":"$request_uri",'
                '"protocol":"$server_protocol",'
                '"status":"$status",'
                '"bytes_sent":"$body_bytes_sent",'
                '"referer":"$http_referer",'
                '"user_agent":"$http_user_agent"}';
access_log /var/log/nginx/access.json json;

# Example
{"time":"2025-02-26T15:30:44+00:00","client_ip":"192.168.1.10","method":"GET",
"uri":"/index.html","protocol":"HTTP/2.0","status":"200","bytes_sent":"12543",
"referer":"https://google.com","user_agent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64)"}
{"time":"2025-02-26T15:31:10+00:00","client_ip":"203.0.113.5","method":"POST",
"uri":"/api/login","protocol":"HTTP/1.1","status":"401","bytes_sent":"512",
"referer":"https://example.com","user_agent":"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7)"}Copy

로그내용을 추출해 바로 의미있는 정보로 사용하려한다면 위에처럼 JSON 형식으로 로그를 출력해도 될것이다.
그러면 ELK 스택과 함께 사용할때 더욱 유용한 정보로 로그 데이터를 이용할 수 있을것이다.

SSL/TLS 정보 로그 포맷

log_format ssl_log '$remote_addr - $remote_user [$time_iso8601] '
                   '"$request" $status $body_bytes_sent '
                   '"$http_referer" "$http_user_agent" '
                   '"$ssl_protocol" "$ssl_cipher"';
access_log /var/log/nginx/access.log ssl_log;

# Example
192.168.1.10 - admin [2025-02-26T15:35:22+00:00] "GET /secure HTTP/2.0" 200 2048
"https://example.com" "Mozilla/5.0 (Windows NT 10.0; Win64; x64)"
"TLSv1.3" "ECDHE-RSA-AES128-GCM-SHA256"
203.0.113.5 - - [2025-02-26T15:36:05+00:00] "POST /api/login HTTP/1.1" 401 512
"https://example.com" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7)"
"TLSv1.2" "AES256-GCM-SHA384"Copy

보안 프로토콜에 민감하다면 위에 처럼 SSL 정보 로그 포맷을 구현해도 될것이다.


조건부 로그

이렇게 로그 포맷에 의해 정의된 내용은 모든 웹서버 접근 요청에 대해서 기록을 남기게 된다.
근데 이런 기록이 단순히 페이지를 요청하는 기록뿐만이 아니라 정적 컨텐츠, 그러니까 이미지 파일, 스타일, 스크립트, 텍스트파일도 전부 위에 해당하는 기록이 남는다.

보통 우리가 웹 로그 요청을 분석할때는 고유 페이지의 요청에 대한 기록만 얻고싶어하는 경우가 많고, 나조차도 그런 이유로 이 로그 포맷을 다듬는 도중이었다.

그래서 관련된 조건부 로그에 대해알아보니 아래와 같은 형식으로 조건부 로깅을 할 수 있다는걸 알게되었다.

map $variable $loggable {
    condition 1;
    default 0;
}

access_log /path/to/access.log format if=$loggable;Copy

condition에 적절한 조건식을 넣어 로깅이 필요한 경우에는 1, 필요가 없는경우에는 0을 반환하게 만들고 이를 access_log 끝에 조건 파라미터로 호출하면 된다.

map $request_uri $loggable {
    ~*\.(css|js|gif|jpg|jpeg|png|svg|ico|woff2|ttf|eot|mp4|webm|ogg|webmanifest|json|map)$  0;
    default 1;
}

log_format main '$time_iso8601 | $request | $status | $remote_addr | $body_bytes_sent Byte';
access_log /var/log/nginx/access.log main if=$loggable;Copy

위에 예시처럼 나는 정적 컨텐츠의 확장자를 분석해 매칭되는 확장자가 있는경우에 0을 반환하게 하고 매칭되는게 없을때는 1을 반환하게해 정적 콘텐츠를 제외한 요청만 로그가 되도록 조율해서 사용중이다.

이런 조건부 방식과 조합해서 쓰면 로그를 더욱 필요에 맞게 수정해서 남길 수 있을것이다.


결론

로그는 평소에는 거의 필요없다가 문제있을때만 들여다 보는 정보로 주로 사용되지만서도 미리미리 필요한 데이터 구조로 저장해두는 작업을 해두면 나중에 문제발생시 훨씬 빠르고 효율적이게 데이터 분석을 할 수 있을 것이다.

나도 디폴트 로그로 두고 가끔가다 크롤러나 봇, 악의적인 접근 분석할때 이용하는데, 이때 일반 사용자 요청이랑 섞여버려서 여간 불편한게 아닐수 없었고, 이를 해결하기위해 로그포맷과 조건을 통해 필요한 정보만 로깅을 하는것으로 접속 모니터링의 효율적인 개선을 이루었다.

여러분도 서버를 손대거나 필요한 로깅 정보가 있으면 이런식으로 한번 로그 구조를 조정해보는것도 나쁘지 않지 않을까 한다.
끝!

레퍼런스

nginx의 로그 포맷 수정하기
nginx의 로그 포맷 수정하기
nginx의 로그 포맷을 기본에서 줄이거나 늘려서 원하는 것처럼 바꾸어보자
https://velog.io/@janghoosa/nginx의-로그-포맷-수정하기
NGINX Access Log: 조건부 로깅 샘플링 요청
NGINX Access Log: 조건부 로깅 샘플링 요청
NGINX Access Log 의 조건부 로깅을 사용하면 특성을 정의한 요청의 하위 집합을 기록 할 수 있습니다. 해당 포스트는 실제 사용 사례를 바탕으로 쓸모없고 불안한 SSL/TLS 암호를 거부하는 방법을 가이드 합니다.
https://nginxstore.com/blog/nginx/nginx-access-log-조건부-로깅-샘플링-요청/?utm_source=chatgpt.com
[WEB/WAS] Nginx log_format 사용 방법
[WEB/WAS] Nginx log_format 사용 방법
log_format은 NGINX에서 로그 출력 형식을 정의하는 지시어입니다. 이를 사용하면 로그 파일에 출력되는 정보의 형식을 커스터마이징할 수 있습니다. log_format 지시어를 사용하는 방법은 다음과 같습니다. http { ... log_format my_log_format '$remote_addr - $remote_user [$time_local] ' '"$request" $status $body_bytes_sent ' '"$http_referer" "$http_user_agent"'; ... } 위의 예제에서 log_format 지시어는 my_log_format이라는 이름을 가지고 있습니다. 이 이름은 해당 로그 출력 형식을 식별하는 데 사용됩니다. 로그 형식 문자열에서 $remote_addr..
https://betwe.tistory.com/entry/WEBWAS-Nginx-logformat-사용-방법?utm_source=chatgpt.com
[Nginx] Json 로그 포맷 설정
[Nginx] Json 로그 포맷 설정
들어가기 앞서, 해당 포스트에선, Nginx 액세스 로그를 Json 형식으로 남기는 방법에 대해서 다뤄보겠습니다. Nginx 기본 로그 포맷 log_format main '$remote_addr - $remote_user [$time_local] "$request" ' '$status $body_bytes_sent "$http_referer" ' '"$http_user_agent" "$http_x_forwarded_for"'; Nginx Json 로그 포맷 설정 아래 코드를 참고해, nginx.conf 파일 내부 http 블락에 원하는 variables로 로그 포맷을 설정하면 됩니다. # Json 로그 포맷 설정 log_format nginxlog_json es..
https://wooono.tistory.com/695?utm_source=chatgpt.com
Configuring Logging | NGINX Documentation
Configuring Logging | NGINX Documentation
Capture detailed information about errors and request processing in log files, either locally or via syslog.
https://docs.nginx.com/nginx/admin-guide/monitoring/logging/?utm_source=chatgpt.com

#Nginx
0 개의 댓글
×