Rsyslog : ver 8
LogAnalyzer : ver 4.1.3

[Server] - Rsyslog

Rsyslog 설치

wget 패키지 설치 (없는경우만)
# If not exist wget
$ yum install -y wget
$ yum update
Rsyslog 설치
# Install Rsyslog
$ wget http://rpms.adiscon.com/v8-stable/rsyslog.repo
$ mv rsyslog.repo /etc/yum.repos.d/rsyslog.repo
$ yum install -y rsyslog
$ systemctl enable rsyslog
Rsyslog-mysql 설치
# Install rsyslog-mysql
$ yum install -y rsyslog rsyslog-mysql

Mysql 설치 및 rsyslog-DB 세팅

MySQL 설치
# Install MySQL
$ wget http://repo.mysql.com/mysql-community-release-el7-5.noarch.rpm
$ sudo rpm -ivh mysql-community-release-el7-5.noarch.rpm
$ yum update
$ yum install -y mysql-server
$ systemctl start mysqld
MySQL 초기 설정
# Setting MySQL
$ mysql_secure_installation
Rsyslog Database 덤프
# Import rsyslog-mysql dump
$ mysql -u root -p < /usr/share/doc/rsyslog-mysql-x.x.x/createDB.sql/
Rsyslog용 계정 생성
# Create the user to access the database
$ mysql -u root -p
mysql> GRANT ALL ON Syslog.* TO 'rsyslog'@'localhost' IDENTIFIED BY 'Password'; #<-
mysql> FLUSH PRIVILEGES;
mysql> exit

Rsyslog 세팅

설정파일 편집기로 실행
$ vi /etc/rsyslog.conf
 설정파일에 MySQL 모듈/템플릿 추가
# Load the MySQL Module
$template SQLWithProcessID,"insert into SystemEvents (Message, Facility, FromHost, Priority, DeviceReportedTime, ReceivedAt, InfoUnitID, SysLogTag, ProcessID) values ('%msg%', %syslogfacility%, '%HOSTNAME%', %syslogpriority%, '%timereported:::date-mysql%', '%timegenerated:::date-mysql%', %iut%, '%syslogtag:R,ERE,1,FIELD:([a-zA-Z\/]+)(\[[0-9]{1,5}\])*:--end%', '%syslogtag:R,ERE,1,BLANK:\[([0-9]{1,5})\]--end%')",sql
module(load="ommysql")
action(type="ommysql"
server="localhost"
serverport="3306"
db="Syslog"
uid="rsyslog"
pwd="password" #<-
template="SQLWithProcessID")
 설정파일에서 UDP 통신을 위한 포트 설정 주석 제거
# Provides UDP syslog reception
# for parameters see http://www.rsyslog.com/doc/imudp.html
module(load="imudp") # needs to be done just once
input(type="imudp" port="514")
설정파일에 룰 수정
local1 은 httpd
local2 는 nginx
local3 는 python
local4 는 php
로 정의해서 쓰기로 함.
message파일 에 저장하지 않으려면 local1.!*  처럼 추가로 등록한 속성에 대해서 예외처리 걸어줘야함
#### RULES ####
...
*.emerg :omusrmsg:*
...
# Custom - tez
$template tmplmsg, "/var/log/remote/%hostname%/%programname%.log"
$template tmplhttpd, "/var/log/remote/%hostname%/httpd.log"
$template tmplhttpdaccess, "/var/log/remote/%hostname%/httpd-access.log"
$template tmplhttpderror, "/var/log/remote/%hostname%/httpd-error.log"
$template tmplnginx, "/var/log/remote/%hostname%/nginx/nginx.log"
$template tmplnginxaccess, "/var/log/remote/%hostname%/nginx/nginx-access.log"
$template tmplnginxerror, "/var/log/remote/%hostname%/nginx/nginx-error.log"
$template tmplpython, "/var/log/remote/%hostname%/%programname%.log"
$template tmplphp, "/var/log/remote/%hostname%/%programname%.log"
$template tmplauth, "/var/log/remote/%hostname%/secure/%programname%.log"
$template tmplmail, "/var/log/remote/%hostname%/maillog/%programname%.log"
$template tmplcron, "/var/log/remote/%hostname%/cron/%programname%.log"
$template tmplspooler, "/var/log/remote/%hostname%/spooler/%programname%.log"
$template tmplboot, "/var/log/remote/%hostname%/boot/%programname%.log"
*.info;local1.!*;local2.!*;local3.!*;local4.!*;mail.none;authpriv.none;cron.none ?tmplmsg #httpd.info(access)
authpriv.*      ?tmplauth
mail.*         ?tmplmail
cron.*         ?tmplcron
uucp,news.crit ?tmplspooler
local7.*        ?tmplboot
local1.*;local1.!=info;local1.!=error ?tmplhttpd
local1.info                          ?tmplhttpdaccess
local1.error                         ?tmplhttpderror

local2.*;local2.!=info;local2.!=error ?tmplnginx
local2.info                            ?tmplnginxaccess
local2.error                           ?tmplnginxerror

local3.* ?tmplpython
local4.* ?tmplphp
rsyslog 재시작
$ systemctl restart rsyslog
!! 만약 firewall / iptables / selinux 사용하는 경우 udp514 포트를 열어주자

Logrotate 설정


/etc/logroate.conf
/etc/logrotate.d/*
/etc/logrotate.d/rsyslog_remote 생성해서 템플릿으로 경로를 바꾼 로그들도 관리되게 해주자  
# >$ /etc/logrotate.conf
...
#weekly
daily
...
#rotate 4
rotate 5
...
copytruncate
...
# >$ /etc/logrotate.d/rsyslog_remote
#/var/log/remote/*.log
/var/log/remote/*/*.log
/var/log/remote/*/*/*.log
{
mail dev@tez.kr # optional
daily
rotate 5
dateext
missingok
ifempty
copytruncate
create 0600 root root
sharedscripts
postrotate
     /bin/kill -HUP `cat /var/run/syslogd.pid 2> /dev/null` 2> /dev/null || true
endscript
}
메일 전송을 위한 패키지 설치/설정
$ yum install mailx ncompress
# >$ vi /etc/postfix/main.cf
...
message_size_limit = 20480000
$ systemctl restart postfix

[Server] - LogAnalyzer

아파치 설치, 실행 (설치 안된 경우만)

# Install and Start Httpd (Apache2)
$ yum install -y httpd
$ systemctl start httpd
$ systemctl enable httpd
아파치 실행 후 브라우저로 확인 ( http://server-ip/ )

PHP 설치, 실행

# Install php
$yum install -y php php-mysql php-gd
# Create phpinfo page
$ nano /var/www/html/test.php
<?php
phpinfo();
?>
# Restart Apache Service
$ systemctl restart httpd
http://server-ip/test.php 로 접속하여 php정보 확인

LogAnalyzer 설치

다운로드
$ wget http://download.adiscon.com/loganalyzer/loganalyzer-4.1.3.tar.gz
압축해제
$ tar zxvf loganalyzer-4.1.3.tar.gz
Apache에 LogAnalyrzer 설치파일 복사
cp -r loganalyzer-4.1.3/src/ /var/www/html/loganalyzer
cp -r loganalyzer-4.1.3/contrib/* /var/www/html/loganalyzer/
권한 수정
  • 하위버전에서는 configure, secure 파일만 수정하면 되지만 권한 문제가 발생하는 경우가 종종있어서 폴더 전체에 권한 설정을 해준다.
$ cd /var/www/html/loganalyzer/
$ chmod +x configure.sh secure.sh
# If permission error occurred
$ chown apache:apache -R /var/www/html/loganalyzer/
$ find . -type f -exec chmod 0644 {} \;
$ find . -type d -exec chmod 0755 {} \;
$ chcon -t httpd_sys_content_t /var/www/html/loganalyzer -R
$ chcon -t httpd_sys_rw_content_t /var/www/html/loganalyzer -R
configure.sh 실행 -> 빈 config.php 파일을 쓰기권한으로 생성해준다
$ ./configure.sh
# If permission error occurred
$ cd /var/www/html/loganalyzer
$ touch config.php
$ chown apache:apache config.php
$ chmod 777 config.php
설치
  • http://server-ip/loganalyzer 접속
  • Step 1
    • next
  • Step 2
    • next
    • permission 문제 발생시 위에있는 권한관련 처리
  • Step 3
    • Enable User Database -> Yes
    • DB 관련 정보 입력
      • DatabaseName : Syslog
    • Require user to be logged in -> YES
  • Step 4
    • next
  • Step 5
    • next
  • Step 6
    •  계정 생성
    • next
  • Step 7
    • Source Type -> MySQL native
    • Select View -> Syslog Fields
    • DB 정보 입력
      • Database Name -> Syslog
      • Table Name -> SystemEvents (대소문자 구분!!)
  • Step 8
    • next


[Client]

Rsyslog 설치

wget 패키지 설치 (없는경우만)
# If not exist wget
$ yum install -y wget
$ yum update
Rsyslog 설치
# Install rsyslog-mysql
$ yum install -y rsyslog rsyslog-mysql

Rsyslog 세팅

설정파일 편집기로 실행
$ vi /etc/rsyslog.conf
설정파일에 rsyslog server 정보 추가
  • apache log 전송을 위해 local1 룰 추가
  • 모든 로그를 로그서버로 전송
local1 은 httpd
local2 는 nginx
local3 는 python
local4 는 php
로 정의해서 쓰기로 함.
message파일 에 저장하지 않으려면 local1.!*  처럼 추가로 등록한 속성에 대해서 예외처리 걸어줘야함
#### RULES ####
...
#*.info;mail.none;authpriv.none;cron.none /var/log/messages
*.info;local1.!*;local2.!*;local3.!*;local4.!*;mail.none;authpriv.none;cron.none /var/log/messages
...
# for Custom log
local1.*;local1.!=info;local1.!=error /var/log/httpd
local1.info /var/log/httpd-access
local1.error /var/log/httpd-error
local2.* /var/log/nginx
local3.* /var/log/python
local4.* /var/log/php
...
#*.* @@remote-host:514
*.* @x.x.x.x:514 # <- log server ip
rsyslog 재시작
$ systemctl restart rsyslog

Apache 세팅

apache log 를 syslog로 전달하기 위한 작업
  • httpd.conf 수정
    • ErrorLog랑 CustomLog 추가
# >$ vi /usr/local/apache2/conf/httpd.conf
...
SetEnvIfNoCase Request_URI "\.(jpg|jpeg|png|gif|bmp|css|ico|js|swf)$" exceptlist
...
#ErrorLog "logs/error_log"
ErrorLogFormat "%t %a [%v] \"%{User-Agent}i\" [%-l] %7F: %E: %M"
ErrorLog "|/usr/bin/logger -p local1.error -t httpd"
...
#CustomLog "logs/access_log" common
LogFormat "%h %l %u %t \"%v%U\" \"%r\" %>s %b \"%{User-Agent}i\" **%Tsec/%Dmsec**" combinedTez
CustomLog "|/usr/bin/logger -p local1.info -t httpd" combinedTez env=!exceptlist
  • httpd-vhost.conf 수정
    • 위의 설정을 하고 이곳에 로그를 주석처리해야 rsyslog에서 설정한 로그로 저장된다.
...
<VirtualHost *:80>
...
#ErrorLog "logs/tez.kr-error_log"
#CustomLog "logs/tez.kr-access_log" common
...
</VirtualHost>


Nginx 세팅

nginx log 를 syslog로 전달하기 위한 작업 (nginx >= 1.7.1)
  • nginx.conf 수정
    • error_log, access_log 추가
# >$ vi /etc/nginx/nginx.conf
...
#error_log /var/log/nginx/error.log;
error_log syslog:server=unix:/dev/log,facility=local2,tag=nginx,severity=error;
...
http {
...
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';
#access_log /var/log/nginx/access.log main;
access_log syslog:server=unix:/dev/log,facility=local2,tag=nginx,severity=info main;
...
}
...
  • vhost.conf 확인
    • vhost안에 log 설정하는 부분이 있으면 빼주자

Logrotate 설정


logrotate 설정을 변경해준다
  • 하루단위로 백업, 3일 단위로 rotate, mail 
# >$ vi /etc/logrotate.conf
# see "man logrotate" for details
# rotate log files weekly
daily
# keep 4 weeks worth of backlogs
rotate 3
...
logrotate -> syslog 설정을 변경해준다
  • 하루단위로 백업, 3일 단위로 rotate, mail 
# >$ vi /etc/logrotate.d/syslog
/var/log/cron
/var/log/maillog
/var/log/messages
/var/log/secure
/var/log/spooler
/var/log/httpd
/var/log/httpd-access
/var/log/httpd-error
/var/log/nginx
/var/log/python
/var/log/php
/var/log/shopadmin_server_production.log # <-
/var/log/shopadmin_server_development.log # <-
/var/log/shopadmin_call_server_production.log # <-
/var/log/shopadmin_call_server_development.log # <-
/var/log/riderapp_server_production.log # <-
/var/log/riderapp_server_development.log # <-
/var/log/push_server_production.log # <-
/var/log/push_server_development.log # <-
/var/log/stat_push_server_production.log # <-
/var/log/stat_push_server_development.log # <-
/var/log/stat_shopadmin_call_server_production.log # <-
/var/log/stat_shopadmin_call_server_development.log # <-
{
daily
rotate 3
dateext
missingok
ifempty
copytruncate
create 0600 root root
sharedscripts
postrotate
    /bin/kill -HUP `cat /var/run/syslogd.pid 2> /dev/null` 2> /dev/null || true
endscript
}
강제로 logrotate 실행
$ logrotate -f /etc/logrotate.d/syslog
logrotate debug 모드 (실제 실행될거 테스트)
$ logrotate -d /etc/logrotate.d/syslog





개발 언어별 syslog 사용 방법

Python

formatter를 수정하여 커스터마이징 로거 생성
  • Option1 
    • 이걸 사용하면 경로, 함수이름, 호출 라인을 측정할 수 있다. 하지만 기존에 사용하는 로그는 함께 동작하지 않음
    • 사용법은 Common.getLogger.info(메시지) 형태로 사용, info 위치에는 error, crit 등 타입이 들어감
  • Option2 : 
    • 이걸 사용하면 syslog 와 함께 내부 로그도 같이 작동한다. 하지만 경로, 함수이름, 호출 라인은 없이 메시지만 가능
    • 사용법은 Common.infoLog(메시지) 형태로 사용, info 위치에는 error, crit 등 타입이 들어감
import logging
import logging.handlers
# Init logger for other class
externalLogger = logging.getLogger('external')
externalLogger.setLevel(logging.DEBUG)
externalHandler = logging.handlers.SysLogHandler(address='/dev/log',facility='local3')
externalHandler.formatter = logging.Formatter(' : [%(levelname)s] %(pathname)s - %(funcName)s line:%(lineno)d message:%(message)s')
externalLogger.addHandler(externalHandler)
# Init logger for Common class
internalLogger = logging.getLogger('internal')
internalLogger.setLevel(logging.DEBUG)
internalHandler = logging.handlers.SysLogHandler(address='/dev/log',facility='local3')
internalHandler.formatter = logging.Formatter(' : [%(levelname)s] %(message)s')
internalLogger.addHandler(internalHandler)
# Option 1 - Common.getLogger.info(message) // <- enable pathname, funcname, lineno
def getLogger(externalCall=True):
if externalCall is True:
return externalLogger
else:
return internalLogger
# Option2 - Common.xxxxLog(message) // <- just message
def infoLog(message):
getLogger(False).info(message)
log(message)
def errorLog(message):
getLogger(False).error(message)
log(message)
def criticalLog(message):
getLogger(False).critical(message)
log(message)
사용 예제
import Common
# Option 1
Common.getLogger().info('Tez Full log teset')
Common.getLogger().critical('Tez Full log teset')
Common.getLogger().error('Tez Full log teset')
# Option 2
Common.infoLog('tez info')
Common.errorLog('tez error')
Common.critical('tez critical')
!!! 공용 class를 만들어서 사용할 경우 pathname, funcName, lineno 등을 고려하자

PHP

<?php
openlog('', LOG_CONS | LOG_NDELAY, LOG_LOCAL4);
syslog(LOG_DEBUG, 'Php degug!');
syslog(LOG_INFO, 'php info');
syslog(LOG_ERR, 'php err');
syslog(LOG_CRIT, 'php crit');
closelog();
?>
사용예제
// Debug Log
openlog(PROJECT_NAME, LOG_CONS | LOG_NDELAY, LOG_LOCAL4);
syslog(LOG_DEBUG, "$log_str");
closelog();
// Error Log
openlog(PROJECT_NAME, LOG_CONS | LOG_NDELAY, LOG_LOCAL4);
if (isset($_SERVER['HTTP_USER_AGENT']) && isset($_SERVER['REMOTE_ADDR'])) {
syslog(LOG_ERR, "{$log_str} {$_SERVER['REMOTE_ADDR']} ({$_SERVER['HTTP_USER_AGENT']})");
}
else {
syslog(LOG_ERR, "{$log_str}");
}
closelog();
CodeIgniter는 config.php 에서 log_threshold 값을 2이상으로 줘야 debug 로그가 보인다
0: logging x
1: error log
2: debug log
3: info log

백업 및 데이터 정리

Log 데이터 백업

매일 주기적으로 cron.daily 에 등록하여 AWS S3 로 데이터 저장
# /etc/cron.daily/syslog_to_s3.sh
s3cmd sync --recursive /var/log/remote/ s3://tez-syslog/logs/

MySQL 데이터 정리

매일 주기적으로 DB 에서 3일이 지난 데이터는 삭제
DB가 계속 쌓이면 Loganalyzer를 확인할때 갱신속도가 엄청나게 느려지고 서버 용량이 금방 고갈난다
# /etc/cron.daily/delete_old_db_datas.sh
mysql --login-path=dumpusr Syslog -e "delete from SystemEvents where ReceivedAt < date_add(date_format( now() , '%Y-%m-%d %k:%i:%s'), interval -3 day) ORDER BY ID ASC"
삭제하는 쿼리를 돌리면 데이터 양에 따라서 속도가 느리고 cpu부하가 심하게 걸리는데, 이걸 방지하기 위해 ReceivedAt 필드에 Index를 걸어주자.



속성별 저장 위치

Remote Server

[ApacheLog]
  • 기존 사용 경로에 저장안됨
  • /var/log/httpd
  • /var/log/httpd-access
  • /var/log/httpd-error
[Nginx]
  • /var/log/nginx

[PhpLog]
  • 기존 사용 경로에 저장됨
  • /var/log/php

[PythonLog]
  • 기존 사용 경로에 저장됨
  • /var/log/php

Log Server

  • /var/log/remote/[host]/[program]


반응형