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]


반응형

Info

In iOS 10.3, the function to change app icons has been added, which allows you to change the icon without updating the app.
AlternateAppIcon.gif

How to add

In Project

// Info.plist
...
<key>CFBundleIcons</key>
<dict>
<key>CFBundleAlternateIcons</key>
<dict>
<key>icon_type_1</key>
<dict>
<key>CFBundleIconFiles</key>
<array>
<string>icon1</string> // <- added the alternate icon name
</array>
<key>UIPrerenderedIcon</key>
<false/>
</dict>
<key>icon_type_2</key>
<dict>
<key>CFBundleIconFiles</key>
<array>
<string>icon2</string>
</array>
<key>UIPrerenderedIcon</key>
<false/>
</dict>
<key>icon_type_3</key>
<dict>
<key>CFBundleIconFiles</key>
<array>
<string>icon3</string>
</array>
<key>UIPrerenderedIcon</key>
<false/>
</dict>
</dict>
<key>CFBundlePrimaryIcon</key>
<dict>
<key>CFBundleIconFiles</key>
<array>
<string>AppIcon60x60</string> // <- Assets AppIcon
</array>
</dict>
</dict>
...

In Code

  • Setting the alertnate Icon
if ([[UIApplication sharedApplication] supportsAlternateIcons] == NO)
return;
[[UIApplication sharedApplication] setAlternateIconName:@"icon_type_1" //AlternateIcons key name
completionHandler:^(NSError * _Nullable error) {
NSLog(@"%@", [error description]);
}];
  • Reset to the primary icon
if ([[UIApplication sharedApplication] supportsAlternateIcons] == NO)
return;
[[UIApplication sharedApplication] setAlternateIconName:nil
completionHandler:^(NSError * _Nullable error) {
NSLog(@"%@", [error description]);
}];


반응형

CLLocation - 두 점사이 거리 구하기

Info

GPS 사용하는 iPhone 개발을 진행하다보면 내비게이션에서 경로찾기를 하는 경우 혹은 특정 스팟까지의 거리를 구하기 위해 두 점 사이의 거리를 구해야 하는 경우들이 있다.
점 하나는 위도, 경도 값으로 이루어져 있어서 어떤 언어에서는 직접 계산을 해서 거리를 구하기도 하지만, Objective-C 에서는 CLLocation 클래스에서 distanceFromLocation: 이라는 함수를 제공해준다.

Code

CLLocation *pointA = [[CLLocation alloc] initWithLatitude:"latitudeDouble" longitude:"longitudeDouble"];
CLLocation *pointB = [[CLLocation alloc] initWithLatitude:"latitudeDouble" longitude:"longitudeDouble"];
CLLocationDistance distance = [pointA distanceFromLocation:pointB];
반응형