λ‘κ·Έ κ΄λ¦¬
λ‘κ·Έ κ΄λ¦¬¶
νμ΅ λͺ©ν¶
μ΄ λ¬Έμλ₯Ό ν΅ν΄ λ€μμ νμ΅ν©λλ€:
- systemd-journaldμ μ€μ κ³Ό νμ©
- rsyslog μ€μ λ° νν°λ§
- logrotateλ₯Ό ν΅ν λ‘κ·Έ μν
- μ격 λ‘κ·Έ μμ§ κ΅¬μ±
λμ΄λ: βββ (μ€κΈ-κ³ κΈ)
λͺ©μ°¨¶
- Linux λ‘κ·Έ μμ€ν κ°μ
- systemd-journald
- journalctl κ³ κΈ μ¬μ©λ²
- rsyslog μ€μ
- logrotate
- μ격 λ‘κ·Έ μμ§
- λ‘κ·Έ λΆμ λꡬ
1. Linux λ‘κ·Έ μμ€ν κ°μ¶
λ‘κ·Έ μμ€ν μν€ν μ²¶
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β μ ν리μΌμ΄μ
/ μλΉμ€ β
βββββββββββββββββ¬ββββββββββββββββββββββββββ¬ββββββββββββββββββββ
β β
βΌ βΌ
βββββββββββββββββββββββββββββ βββββββββββββββββββββββββββββββ
β systemd-journald β β rsyslog / syslog-ng β
β (λ°μ΄λ리 μ λ) ββββΆβ (ν
μ€νΈ λ‘κ·Έ νμΌ) β
βββββββββββββββββββββββββββββ βββββββββββββββββββββββββββββββ
β β
βΌ βΌ
βββββββββββββββββββββββββββββ βββββββββββββββββββββββββββββββ
β /run/log/journal/ β β /var/log/*.log β
β /var/log/journal/ β β μ격 μλ² β
βββββββββββββββββββββββββββββ βββββββββββββββββββββββββββββββ
μ£Όμ λ‘κ·Έ νμΌ¶
| νμΌ | λ΄μ© |
|---|---|
/var/log/messages |
μΌλ° μμ€ν λ©μμ§ (RHEL/CentOS) |
/var/log/syslog |
μΌλ° μμ€ν λ©μμ§ (Ubuntu/Debian) |
/var/log/auth.log |
μΈμ¦ κ΄λ ¨ λ‘κ·Έ (Ubuntu) |
/var/log/secure |
μΈμ¦ κ΄λ ¨ λ‘κ·Έ (RHEL) |
/var/log/kern.log |
컀λ λ©μμ§ |
/var/log/dmesg |
λΆν μ 컀λ λ©μμ§ |
/var/log/cron |
ν¬λ‘ μμ λ‘κ·Έ |
/var/log/maillog |
λ©μΌ μλ² λ‘κ·Έ |
λ‘κ·Έ μ°μ μμ (Severity)¶
| λ 벨 | μ΄λ¦ | μ€λͺ |
|---|---|---|
| 0 | emerg | μμ€ν μ¬μ© λΆκ° |
| 1 | alert | μ¦μ μ‘°μΉ νμ |
| 2 | crit | μ¬κ°ν μ€λ₯ |
| 3 | err | μλ¬ |
| 4 | warning | κ²½κ³ |
| 5 | notice | μ μμ΄μ§λ§ μ£Όλͺ©ν λ§ν μν© |
| 6 | info | μ λ³΄μ± λ©μμ§ |
| 7 | debug | λλ²κ·Έ λ©μμ§ |
2. systemd-journald¶
journald μ€μ ¶
# μ€μ νμΌ
sudo vi /etc/systemd/journald.conf
# /etc/systemd/journald.conf
[Journal]
# μ μ₯ λ°©μ: volatile(λ©λͺ¨λ¦¬), persistent(λμ€ν¬), auto, none
Storage=persistent
# μ΅λ ν¬κΈ° (λμ€ν¬ μ μ₯ μ)
SystemMaxUse=500M
SystemKeepFree=1G
SystemMaxFileSize=50M
SystemMaxFiles=100
# λ°νμ μ μ₯μ (λ©λͺ¨λ¦¬)
RuntimeMaxUse=50M
# λ‘κ·Έ μμΆ
Compress=yes
# λ΄μΈ (tamper-evident)
Seal=yes
# rsyslogλ‘ μ λ¬
ForwardToSyslog=yes
# μ½μ μΆλ ₯
ForwardToConsole=no
# μ΅λ 보쑴 κΈ°κ°
MaxRetentionSec=1month
# μλ μ ν
RateLimitIntervalSec=30s
RateLimitBurst=10000
# μ€μ μ μ©
sudo systemctl restart systemd-journald
μꡬ μ μ₯ νμ±ν¶
# μ λ λλ ν 리 μμ± (persistent storage)
sudo mkdir -p /var/log/journal
sudo systemd-tmpfiles --create --prefix /var/log/journal
# κΆν μ€μ
sudo chown root:systemd-journal /var/log/journal
sudo chmod 2755 /var/log/journal
# journald μ¬μμ
sudo systemctl restart systemd-journald
μ λ μν νμΈ¶
# λμ€ν¬ μ¬μ©λ
journalctl --disk-usage
# μ λ νμΌ νμΈ
journalctl --header
# μ λ λ¬΄κ²°μ± κ²μ¦
journalctl --verify
3. journalctl κ³ κΈ μ¬μ©λ²¶
κΈ°λ³Έ μ‘°ν¶
# λͺ¨λ λ‘κ·Έ
journalctl
# μμ (μ΅μ λ¨Όμ )
journalctl -r
# μ€μκ° νλ‘μ°
journalctl -f
# λ§μ§λ§ Nμ€
journalctl -n 50
# νμ΄μ μμ΄ μΆλ ₯
journalctl --no-pager
μκ° κΈ°λ° νν°λ§¶
# μ€λ λ‘κ·Έ
journalctl --since today
# μ΄μ λ‘κ·Έ
journalctl --since yesterday --until today
# νΉμ μκ° λ²μ
journalctl --since "2024-01-15 10:00:00" --until "2024-01-15 12:00:00"
# μλμ μκ°
journalctl --since "1 hour ago"
journalctl --since "30 minutes ago"
# λΆν
κ΄λ ¨
journalctl -b # νμ¬ λΆν
journalctl -b -1 # μ΄μ λΆν
journalctl --list-boots # λΆν
λͺ©λ‘
μλΉμ€/μ λ νν°λ§¶
# νΉμ μλΉμ€
journalctl -u nginx.service
journalctl -u nginx -u php-fpm
# 컀λ λ©μμ§
journalctl -k
# νΉμ PID
journalctl _PID=1234
# νΉμ μ€ν νμΌ
journalctl /usr/bin/bash
# νΉμ μ¬μ©μ
journalctl _UID=1000
μ°μ μμ νν°λ§¶
# μλ¬ μ΄μ
journalctl -p err
# κ²½κ³ μ΄μ
journalctl -p warning
# λ²μ μ§μ
journalctl -p err..crit
# μ«μλ‘ μ§μ
journalctl -p 3
μΆλ ₯ νμ¶
# JSON νμ
journalctl -o json
journalctl -o json-pretty
# μμΈ μΆλ ₯
journalctl -o verbose
# κ°λ¨ν μΆλ ₯
journalctl -o short
journalctl -o short-precise # λ§μ΄ν¬λ‘μ΄ ν¬ν¨
# cat μ€νμΌ (λ©μμ§λ§)
journalctl -o cat
# λ΄λ³΄λ΄κΈ° νμ
journalctl -o export
λ³΅ν© μΏΌλ¦¬¶
# μ‘°ν© (AND)
journalctl -u nginx -p err --since today
# 컀μ€ν
νλ
journalctl _SYSTEMD_UNIT=sshd.service _PID=1234
# λ©μμ§ κ²μ
journalctl -g "error|fail|critical"
# νλ λͺ©λ‘ 보기
journalctl -F _SYSTEMD_UNIT
journalctl -F PRIORITY
μ λ μ μ§λ³΄μ¶
# μ€λλ λ‘κ·Έ μμ (μκ° κΈ°μ€)
sudo journalctl --vacuum-time=30d
# μ€λλ λ‘κ·Έ μμ (ν¬κΈ° κΈ°μ€)
sudo journalctl --vacuum-size=500M
# νμΌ μ κΈ°μ€ μμ
sudo journalctl --vacuum-files=10
# λͺ¨λ μ λ μμ
sudo journalctl --rotate
sudo journalctl --vacuum-time=1s
4. rsyslog μ€μ ¶
rsyslog κΈ°λ³Έ μ€μ ¶
# λ©μΈ μ€μ νμΌ
sudo vi /etc/rsyslog.conf
# /etc/rsyslog.conf (μ£Όμ μΉμ
)
# λͺ¨λ λ‘λ
module(load="imuxsock") # λ‘컬 μμ€ν
λ‘κ·Έ
module(load="imjournal") # journald ν΅ν©
module(load="imklog") # 컀λ λ‘κ·Έ
# μ μ μ€μ
global(
workDirectory="/var/lib/rsyslog"
maxMessageSize="64k"
)
# κΈ°λ³Έ κ·μΉ
*.info;mail.none;authpriv.none;cron.none /var/log/messages
authpriv.* /var/log/secure
mail.* -/var/log/maillog
cron.* /var/log/cron
*.emerg :omusrmsg:*
νν° λ¬Έλ²¶
# κΈ°λ³Έ λ¬Έλ²: facility.priority action
# facility: auth, authpriv, cron, daemon, kern, mail, user, local0-7, *
# priority: emerg, alert, crit, err, warning, notice, info, debug, none, *
# μμ
kern.* /var/log/kern.log # λͺ¨λ 컀λ λ©μμ§
*.crit /var/log/critical.log # λͺ¨λ μ¬κ°ν μλ¬
mail.err /var/log/mail-err.log # λ©μΌ μλ¬
*.info;mail.none /var/log/messages # info μ΄μ, λ©μΌ μ μΈ
κ³ κΈ νν°λ§¶
# /etc/rsyslog.d/custom.conf
# μμ± κΈ°λ° νν°
:programname, isequal, "nginx" /var/log/nginx/access.log
:programname, startswith, "postfix" /var/log/mail/postfix.log
# λ©μμ§ λ΄μ© κΈ°λ°
:msg, contains, "error" /var/log/errors.log
:msg, regex, "failed.*authentication" /var/log/auth-failures.log
# λ³΅ν© μ‘°κ±΄
if $programname == 'sshd' and $msg contains 'Failed' then {
action(type="omfile" file="/var/log/ssh-failures.log")
stop
}
ν νλ¦Ώ μ¬μ©¶
# 컀μ€ν
λ‘κ·Έ νμ
template(name="CustomFormat" type="string"
string="%timegenerated% %HOSTNAME% %syslogtag%%msg%\n")
# JSON νμ
template(name="JsonFormat" type="list") {
constant(value="{")
constant(value="\"timestamp\":\"") property(name="timereported" dateFormat="rfc3339")
constant(value="\",\"host\":\"") property(name="hostname")
constant(value="\",\"program\":\"") property(name="programname")
constant(value="\",\"severity\":\"") property(name="syslogseverity-text")
constant(value="\",\"message\":\"") property(name="msg" format="json")
constant(value="\"}\n")
}
# ν
νλ¦Ώ μ μ©
*.* action(type="omfile" file="/var/log/json.log" template="JsonFormat")
μ‘°κ±΄λΆ μ²λ¦¬¶
# RainerScript λ¬Έλ²
if $programname == 'nginx' then {
if $syslogseverity <= 3 then {
# μλ¬ μ΄μμ λ³λ νμΌ
action(type="omfile" file="/var/log/nginx/error.log")
} else {
# λλ¨Έμ§λ μΌλ° λ‘κ·Έ
action(type="omfile" file="/var/log/nginx/access.log")
}
stop
}
5. logrotate¶
κΈ°λ³Έ μ€μ ¶
# μ μ μ€μ
sudo vi /etc/logrotate.conf
# /etc/logrotate.conf
# μν μ£ΌκΈ°: daily, weekly, monthly
weekly
# 보κ΄ν λ‘κ·Έ μ
rotate 4
# μ λ‘κ·Έ νμΌ μμ±
create
# λ μ§ νμ₯μ μ¬μ©
dateext
# μμΆ
compress
delaycompress
# λΉ λ‘κ·Έ νμΌ λ¬΄μ
notifempty
# κ°λ³ μ€μ ν¬ν¨
include /etc/logrotate.d
μ ν리μΌμ΄μ λ³ μ€μ ¶
# /etc/logrotate.d/nginx
/var/log/nginx/*.log {
daily
missingok
rotate 14
compress
delaycompress
notifempty
create 0640 www-data adm
sharedscripts
postrotate
[ -f /var/run/nginx.pid ] && kill -USR1 `cat /var/run/nginx.pid`
endscript
}
# /etc/logrotate.d/mysql
/var/log/mysql/*.log {
daily
rotate 7
missingok
create 640 mysql adm
compress
sharedscripts
postrotate
test -x /usr/bin/mysqladmin || exit 0
if [ -f /root/.my.cnf ]; then
/usr/bin/mysqladmin flush-logs
fi
endscript
}
κ³ κΈ μ΅μ ¶
# /etc/logrotate.d/custom-app
/var/log/myapp/*.log {
# μν μ£ΌκΈ°
daily
# λ³΄κ΄ κ°μ
rotate 30
# ν¬κΈ° κΈ°λ° μν
size 100M
# μ΅μ ν¬κΈ° (μ΄λ³΄λ€ μμΌλ©΄ μν μ ν¨)
minsize 10M
# μ΅λ λ³΄κ΄ κΈ°κ°
maxage 365
# μμΆ μ€μ
compress
compresscmd /usr/bin/xz
compressoptions -9
compressext .xz
delaycompress
# νμΌ μμ΄λ μλ¬ μλ
missingok
# λΉ νμΌ μν μ ν¨
notifempty
# μ νμΌ μμ±
create 0644 root root
# λλ κΈ°μ‘΄ νμΌ μ μ§
# copytruncate
# μ€ν¬λ¦½νΈ
prerotate
echo "About to rotate logs"
endscript
postrotate
systemctl reload myapp
endscript
firstaction
echo "Starting log rotation batch"
endscript
lastaction
echo "Finished log rotation batch"
endscript
}
logrotate ν μ€νΈ¶
# λλΌμ΄λ° (μ€μ μ€ν μ ν¨)
sudo logrotate -d /etc/logrotate.d/nginx
# κ°μ μ€ν
sudo logrotate -f /etc/logrotate.d/nginx
# μμΈ μΆλ ₯
sudo logrotate -v /etc/logrotate.conf
# μν νμΌ νμΈ
cat /var/lib/logrotate/status
6. μ격 λ‘κ·Έ μμ§¶
rsyslog μλ² μ€μ ¶
# /etc/rsyslog.conf (μλ²)
# UDP μμ νμ±ν
module(load="imudp")
input(type="imudp" port="514")
# TCP μμ νμ±ν
module(load="imtcp")
input(type="imtcp" port="514")
# νΈμ€νΈλ³ λ‘κ·Έ λΆλ¦¬
$template RemoteLogs,"/var/log/remote/%HOSTNAME%/%PROGRAMNAME%.log"
*.* ?RemoteLogs
# λλ RainerScript μ¬μ©
template(name="RemoteLogsByHost" type="string"
string="/var/log/remote/%HOSTNAME%/%$YEAR%-%$MONTH%-%$DAY%.log")
if $fromhost-ip != '127.0.0.1' then {
action(type="omfile" dynaFile="RemoteLogsByHost")
stop
}
rsyslog ν΄λΌμ΄μΈνΈ μ€μ ¶
# /etc/rsyslog.d/remote.conf (ν΄λΌμ΄μΈνΈ)
# UDPλ‘ μ μ‘ (@)
*.* @logserver.example.com:514
# TCPλ‘ μ μ‘ (@@)
*.* @@logserver.example.com:514
# νΉμ λ‘κ·Έλ§ μ μ‘
auth.* @@logserver.example.com:514
*.err @@logserver.example.com:514
# ν μ€μ (μμ μ μ μ‘)
action(
type="omfwd"
target="logserver.example.com"
port="514"
protocol="tcp"
queue.type="LinkedList"
queue.filename="remote_queue"
queue.saveOnShutdown="on"
queue.maxDiskSpace="1g"
action.resumeRetryCount="-1"
)
TLS μνΈν μ€μ ¶
# μλ² μ€μ
module(load="imtcp"
StreamDriver.Name="gtls"
StreamDriver.Mode="1"
StreamDriver.AuthMode="x509/name"
)
global(
DefaultNetstreamDriver="gtls"
DefaultNetstreamDriverCAFile="/etc/rsyslog.d/ca.pem"
DefaultNetstreamDriverCertFile="/etc/rsyslog.d/server-cert.pem"
DefaultNetstreamDriverKeyFile="/etc/rsyslog.d/server-key.pem"
)
input(type="imtcp" port="6514")
# ν΄λΌμ΄μΈνΈ μ€μ
global(
DefaultNetstreamDriver="gtls"
DefaultNetstreamDriverCAFile="/etc/rsyslog.d/ca.pem"
DefaultNetstreamDriverCertFile="/etc/rsyslog.d/client-cert.pem"
DefaultNetstreamDriverKeyFile="/etc/rsyslog.d/client-key.pem"
)
action(
type="omfwd"
target="logserver.example.com"
port="6514"
protocol="tcp"
StreamDriver="gtls"
StreamDriverMode="1"
StreamDriverAuthMode="x509/name"
)
λ°©νλ²½ μ€μ ¶
# RHEL/CentOS (firewalld)
sudo firewall-cmd --permanent --add-port=514/tcp
sudo firewall-cmd --permanent --add-port=514/udp
sudo firewall-cmd --reload
# Ubuntu (ufw)
sudo ufw allow 514/tcp
sudo ufw allow 514/udp
7. λ‘κ·Έ λΆμ λꡬ¶
lnav (Log Navigator)¶
# μ€μΉ
# Ubuntu/Debian
sudo apt install lnav
# RHEL/CentOS
sudo yum install epel-release
sudo yum install lnav
# μ¬μ©
lnav /var/log/syslog
lnav /var/log/nginx/*.log
# μ격 λ‘κ·Έ (SSH)
lnav ssh://user@server/var/log/syslog
# νν°λ§ (λ΄λΆ λͺ
λ Ή)
:filter-in error
:filter-out debug
multitail¶
# μ€μΉ
sudo apt install multitail # Ubuntu
sudo yum install multitail # RHEL
# μ¬λ¬ νμΌ λμ λͺ¨λν°λ§
multitail /var/log/syslog /var/log/auth.log
# μμ ꡬλΆ
multitail -ci green /var/log/access.log -ci red /var/log/error.log
GoAccess (μΉ λ‘κ·Έ λΆμ)¶
# μ€μΉ
sudo apt install goaccess # Ubuntu
sudo yum install goaccess # RHEL
# ν°λ―Έλμμ μ€μκ° λΆμ
goaccess /var/log/nginx/access.log -c
# HTML λ³΄κ³ μ μμ±
goaccess /var/log/nginx/access.log -o report.html --log-format=COMBINED
# μ€μκ° HTML λμ보λ
goaccess /var/log/nginx/access.log -o /var/www/html/report.html \
--log-format=COMBINED --real-time-html
κ°λ¨ν λΆμ λͺ λ Ήμ΄¶
# κ°μ₯ λ§μ μμ² IP
awk '{print $1}' /var/log/nginx/access.log | sort | uniq -c | sort -rn | head
# HTTP μν μ½λ λΆν¬
awk '{print $9}' /var/log/nginx/access.log | sort | uniq -c | sort -rn
# μκ°λλ³ μμ² μ
awk '{print $4}' /var/log/nginx/access.log | cut -d: -f2 | sort | uniq -c
# μλ¬ λ©μμ§ λΉλ
grep -i error /var/log/syslog | awk '{print $5}' | sort | uniq -c | sort -rn | head
# μ€ν¨ν SSH λ‘κ·ΈμΈ
grep "Failed password" /var/log/auth.log | awk '{print $11}' | sort | uniq -c | sort -rn
μ°μ΅ λ¬Έμ ¶
λ¬Έμ 1: journalctl 쿼리¶
λ€μ 쑰건μ λ‘κ·Έλ₯Ό μ‘°ννλ λͺ λ Ήμ μμ±νμΈμ: 1. nginx μλΉμ€μ μλ¬ λ‘κ·Έλ§ (μ€λ) 2. νΉμ PID(1234)μ λ‘κ·Έλ₯Ό JSONμΌλ‘ μΆλ ₯ 3. μ§λ 1μκ° λμμ 컀λ κ²½κ³ μ΄μ λ©μμ§
λ¬Έμ 2: rsyslog νν°¶
λ€μ μꡬμ¬νμ λ§μ‘±νλ rsyslog κ·μΉμ μμ±νμΈμ:
- λͺ¨λ auth λ©μμ§λ₯Ό /var/log/auth-all.logμ μ μ₯
- "Failed" λ¬Έμμ΄μ΄ ν¬ν¨λ λ©μμ§λ /var/log/failures.logμλ μ μ₯
- μ격 μλ² 192.168.1.100μΌλ‘ μλ¬ μ΄μ λ‘κ·Έ μ μ‘
λ¬Έμ 3: logrotate μ€μ ¶
/var/log/myapp/ λλ ν 리μ λ‘κ·Έμ λν΄:
- λ§€μΌ μν
- 30μΌ λ³΄κ΄
- 100MB μ΄κ³Ό μ μν
- xz μμΆ
- μν ν μ ν리μΌμ΄μ
μ SIGHUP μ μ‘
μ λ΅¶
λ¬Έμ 1 μ λ΅¶
# 1. nginx μλ¬ λ‘κ·Έ (μ€λ)
journalctl -u nginx -p err --since today
# 2. PID 1234 JSON μΆλ ₯
journalctl _PID=1234 -o json-pretty
# 3. 컀λ κ²½κ³ μ΄μ (1μκ°)
journalctl -k -p warning --since "1 hour ago"
λ¬Έμ 2 μ λ΅¶
# /etc/rsyslog.d/custom.conf
# auth λ‘κ·Έ
auth.* /var/log/auth-all.log
# Failed ν¬ν¨ λ©μμ§
:msg, contains, "Failed" /var/log/failures.log
# μ격 μ μ‘ (μλ¬ μ΄μ)
*.err @@192.168.1.100:514
λ¬Έμ 3 μ λ΅¶
# /etc/logrotate.d/myapp
/var/log/myapp/*.log {
daily
rotate 30
size 100M
compress
compresscmd /usr/bin/xz
compressext .xz
delaycompress
missingok
notifempty
create 0644 root root
postrotate
[ -f /var/run/myapp.pid ] && kill -HUP $(cat /var/run/myapp.pid)
endscript
}
λ€μ λ¨κ³¶
- 19_Backup_Recovery.md - rsync, Borg Backup, μ¬ν΄λ³΅κ΅¬ μ λ΅
μ°Έκ³ μλ£¶
- systemd Journal
- rsyslog Documentation
- logrotate Manual
man journalctl,man rsyslog.conf,man logrotate