우리 서비스에서는 로그 수집서버가 따로 구축되어있지 않았다.
따라서 아래와 같은 불편함이 있었다.
애플리케이션 레벨에서 에러가 발생하였을 때 각각 서버에 직접 들어가 로그를 직접 확인해야했다.
예를들어 어드민 서버에서 에러가 발생하였을 경우 Scale Out 된 서버들을 직접 일일히 들어가서 확인해야했다.
또 로그별로 (액세스 로그, 애플리케이션 로그, 에러 로그, 결제 로그 등) 각각 다른 폴더에 위치하고 있어서 확인도 쉽지 않았다.
각각 서버에서 로그를 보관을하니 기본적으로 EBS 볼륨을 크게 생성하여야 했다.
이로 인해 서비스가 새로 생기거나 Scale Out 될 때마다 비용적인 문제도 증가하였다.
ISMS 증적용이나 사내 정보보호 정책등을 위해 로그를 일정 기간동안 보관 및 소산백업을 해야하는데 각각의 서버에서 스크립트 및 Cron을 적용해서 관리적인 측면에서도 좋지 못했다.
위에 이유들로 로그서버를 구축하기로 하였는데 처음 생각한 방법은 ELK 스택을 이용하는거였다.
방식은
이었는데 우리는 Third-Party 솔루션으로 APM을 이용하고 있었기 때문에 로그데이터를 시각화와 분석을 할 필요까지는 없다고 생각했다.
Filebeat와 Logstash로 구현을 한다고해도 Logstash가 가져온 데이터는 ElasticSearch 인덱싱 없이는 확인하기 어려웠다.
따라서 리눅스 시스템에서 로그 메시지를 수집, 저장, 및 전송하는 데 사용되는 시스템 로그 데몬 rsyslog를 사용하여 로그서버를 구성하기로 했다.
rsyslog는 시스템이 동작하면서 발생하는 다양한 종류의 로그들을 rsyslogd 데몬을 통해서 로그파일을 저장하는 역할을 한다.
주로 커널, 데몬, 보안 등의 메시지를 수집하고 저장한다.
보통 시스템(OS)에서 문제가 발생할 때 확인하는 /var/log/messages 파일도 rsyslog를 통해서 저장한다.
rsyslog의 설정 파일은 /etc/rsyslog.conf
에 위치하고있다.
먼저 고민한 부분은 '어떤 방식으로 원하는 로그들을 로그 수집서버로 보내고 각각 애플리케이션 로그를 원하는 디렉토리에 원하는 로그명으로 저장할까?'였다.
그래서 애플리케이션 서버에서는 아래와 같이 로그수집서버로 보낼 로그들을 설정하였다.
input(type="imfile"
File="/path/to/logs/dir/localhost_access_log.*.txt
Tag="access_log"
Facility="local6"
...
input(type="imfile"
File="/path/to/logs/dir/catalina.*.txt
...
이제 애플리케이션 서버로부터 받은 로그들을 로그 수집서버에서는 아래와 같은 방식으로 저장하였다.
$template APPWEBLogs,"/path/to/logs/dir/%PROGRAMNAME%-%$YEAR%%$MONTH%%$DAY%.log"
$template APPWASLogs,"/path/to/logs/dir/%PROGRAMNAME%-%$YEAR%%$MONTH%%$DAY%.log"
...
set $.lcHostName = tolower($hostname);
if ($syslogfacility-text == 'local6') then {
if ($.lcHostName contains 'web' and not ($.lcHostName contains 'was')) then {
if $.lcHostName contains 'app' then {
action(type="omfile" dynaFile="APPWEBLogs" template="myCustomFormat")
} else if $.lcHostName contains 'adin' then {
...
} else if ($.lcHostName contains 'was') then {
if $.lcHostName contains 'app' then {
action(type="omfile" dynaFile="APPWASLogs" template="myCustomFormat")
} else if $.lcHostName contains 'admin' then {
위 if문을 보면 $syslogfacility-text == 'local6'
, template="myCustomFormat"
내용이 있는데 위와같이 설정한 이유는 다음과 같다.
rsyslog는 Facility를 통해 메시지 서비스 종류를 구분한다.
예를들어
다음 template="myCustomFormat"
은 template은 디폴트로 사용할 경우 각 로그가 날라올 때 마다 앞에 너무 쓸데없는 내용이 포함된다.
예를들어 로그서버 이름 외에도 ip주소, 시간(이미 로그에 포함되어 있음)등이 붙어 용량 및 로그를 확인하는데도 어렵게 만들었다.
따라서 로그 템플릿을
template(name="myCustomFormat" type="string" string="<%PRI%>%TIMESTAMP% %HOSTNAME% %syslogtag% %msg%\n")
와 같이 구성하여 정말 필요한 정보만 포함시켰다.
호스트명 같은 경우에는 애플리케이션 로그 서버에서
$LocalHostName WEB-2
와 같이 설정하여 로그를 저장할 때, 로그를 확인할 때 관리 및 사용의 편의성을 높였다.
rsyslog는 tcp, udp를 이용하여 로그를 전송한다.
또한 디폴트 포트번호는 514를 이용한다.
module(load="imudp")
module(load="imtcp")
...
$UDPServerRun 514
$InputTCPServerRun 514
action(type="omfwd" target="{로그서버 ip 주소}" port="514" protocol="tcp" template="myCustomFormat"
따라서 로그수집서버에서 해당하는 보안그룹을 수정해주어여한다.
로그서버를 구축하고 운영중 각각 애플리케이션 서버에 용량이 줄어들지 않고 오히려 늘어나서 이유를 확인해보니 로그들이 /var/log/messages
에 저장되고 있었다.
rsyslogs.conf 파일 하단 디폴트 설정을 보면
*.info;mail.none;authpriv.none;cron.none /var/log/message
같이 설정되어 있는데 로그 Serverity를 info로 보내다보니 /var/log/message에 저장이 되고 있는 것이었다.
따라서 설정을 아래와 같이 수정하였다.
*.info;mail.none;authpriv.none;cron.none;local6.none /var/log/message
또 이미 저장된 메시지들은 awk
, sed
명령어를 통해 삭제하였다.
아직 해결 못했다...
Queue 설정을 제대로 하지 않으니 로그가 100중 1~2 정도가 유실되는 느낌이다.
해결하면 수정하겠다...
나 같은 경우에는 하면서 수많은 시행착오를 겪었는데 디버깅을 통해서 해결을 많이 했다.
rsyslog.conf 파일에
$DebugFile /var/log/rsyslog.debug.log
$DebugLevel 2
를 포함하여 문제가 발생할 경우 어디서 어떻게 문제가 발생하였는지 확인했다.
https://www.rsyslog.com/doc/index.html 해당 사이트에서 도움을 정말 많이 받았다.