配置rsyslog日志_syslog強大而安全的日志處理系統
安裝
apt-get install rsyslog -y
查看版本
rsyslogd -v
查看狀態
systemctl status rsyslog
重新啟動
systemctl restart rsyslog
配置Rsyslog服務端
vim /etc/rsyslog.conf
取消這幾行前面的注釋,同事使用UDP和TCP協議的514端口
$ModLoad imudp $UDPServerRun 514 $ModLoad imtcp $InputTCPServerRun 514
指定子網、IP或域名來限制訪問,如下所示:
$AllowedSender TCP, 127.0.0.1, 192.168.0.0/24, *.example.com $AllowedSender UDP, 127.0.0.1, 192.168.0.0/24, *.example.com
創建一個模板來告訴Rsyslog如何存儲傳入的syslog消息。在GLOBAL DIRECTIVES部分之前添加以下幾行:
$template remote-incoming-logs,"/var/log/%HOSTNAME%/%PROGRAMNAME%.log" *.* ?remote-incoming-logs
用以下命令檢查Rsyslog配置信息是否有語法錯誤:
linuxprobe@ubuntu-18-04-lts:~$ rsyslogd -f /etc/rsyslog.conf -N1 rsyslogd: version 8.32.0, config validation run (level 1), master config /etc/rsyslog.conf rsyslogd: End of config validation run. Bye.
配置Rsyslog客戶端
配置Rsyslog客戶端來向遠程服務端發送系統日志消息。登錄客戶端,打開/etc/rsyslog.conf添加如下信息:
linuxprobe@ubuntu-18-04-lts:~$ vim /etc/rsyslog.conf ##Enable sending of logs over UDP add the following line: *.* @192.168.0.101:514 ##Enable sending of logs over TCP add the following line: *.* @@192.168.0.101:514 ##Set disk queue when rsyslog server will be down: $ActionQueueFileName queue $ActionQueueMaxDiskSpace 1g $ActionQueueSaveOnShutdown on $ActionQueueType LinkedList $ActionResumeRetryCount -1
重新啟動Rsyslog:
linuxprobe@ubuntu-18-04-lts:~$ systemtcl restart rsyslog
查看日志
此時,Rsyslog客戶端被配置為將它們的日志發送到Rsyslog服務端。
現在,登錄到Rsyslog服務器並檢查/var/log目錄。看到客戶端機器的主機名,包括幾個日志文件
ls /var/log/rsyslog-client/ CRON.log kernel.log rsyslogd-2039.log rsyslogd.log sudo.log wpa_supplicant.log
docker容器中使用rsyslogd
rsyslogd作為CentOS:7系統自帶的日志管理工具,為很多服務提供了便捷的日志管理接入方案,然而 CentOS:7的官方鏡像 默認是不支持rsyslogd的。我們做個實驗:
1)啟動測試容器
docker run -it --name=test-syslog centos:7 /bin/bash
2)安裝rsyslogd
yum -y install rsyslog
3)測試rsyslogd
rsyslogd # 啟動日志服務 logger "Hello rsyslog" # 發送一條日志 cat /var/log/messages # 查看日志內容
我們可以看到並沒有任何輸出。
4)分析原因
原因比較簡單,即rsyslog默認通過 journal 讀取日志信息,但CentOS鏡像默認並未安裝systemd和journald。有兩個解決方案:
(1)按官方提供的教程(systemd integration)將systemd和journald集成到CentOS:7鏡像里;
(2)修改 rsyslogd 的配置,不經過 journal 讀取日志信息。這里講解下方案(2)的具體操作。
5)修改配置
cat /var/run/syslogd.pid # 查看剛才啟動的rsyslogd進程pid kill -9 進程號 # 將剛才啟動的rsyslogd關掉 rm -rf /etc/rsyslog.d/listen.conf # 將 journal 的配置刪除
vi 打開 /etc/rsyslog.conf 文件,將 $ModLoad imjournal 和 $IMJournalStateFile imjournal.state 這兩行注釋;將 $OmitLocalLogging on 改為 $OmitLocalLogging off。保存退出。
6)測試驗證
rsyslogd # 啟動日志服務 logger "Hello rsyslog" # 發送一條日志 cat /var/log/messages # 查看日志內容
可以看到如下輸出,說明日志服務已正常:
May 21 08:57:54 60c66cdf443f rsyslogd: [origin software="rsyslogd" swVersion="8.24.0-34.el7" x-pid="108" x-info="http://www.rsyslog.com"] start May 21 08:58:05 60c66cdf443f root: Hello rsyslog
用python socket發送rsyslog日志
-
原文地址:https://blog.csdn.net/safenli/article/details/75452741
UDP rsyslog
(1) 首先編輯/etc/rsyslog.conf,把udp注釋去掉
# provides udp syslog reception $modload imudp $InputUDPServerRun 514 ##### template #### $template LongFileFormat, "<%PRI%>%TIMESTAMP:::date-rfc3339% %syslogpriority% %HOSTNAME% %syslogtag%%msg:::sp-if-no-1st-sp%%msg:::drop-last-lf%\n" $template ScTemplate,"/var/log/tem.log" if $msg contains "*|" then{ *.* ?ScTemplate;LongFileFormat & stop }
(2)客戶端用python socket正常發送就行
#!/usr/bin/env python #-*-coding:utf-8 -*- import socket s = u"5*|987654321*|admin*|check*|1*|加班*|datacenterid=1*|" setSock = socket.socket(socket.AF_INET,socket.SOCK_DGRAM) try: setSock.sendto(s,(HOST, 514)) except socket.error, e: print e setSock.close()
TCP syslog
這個才是重中之重,開始我只是按照上面的配置方法把相應的udp改成tcp,我以為就完事了,誰想….客戶端用socket的tcp把數據成功發送出去了,服務器端的514也改成tcp協議了,selinux,iptables等都放開了,用tcpdump監聽514端口,也收到數據了,但是,就是不寫到日志文件里。
#創建/etc/rsyslog.d/tcp.conf文件,內容如下 # provides tcp syslog reception $modload imtcp $InputTCPServerRun 514 ##### template #### $template LongFileFormat, "<%PRI%>%TIMESTAMP:::date-rfc3339% %syslogpriority% %HOSTNAME% %syslogtag%%msg:::sp-if-no-1st-sp%%msg:::drop-last-lf%\n" $template ScTemplate,"/var/log/tem.log" if $msg contains "*|" then{ *.* ?ScTemplate;LongFileFormat & stop }
后來我用echo “5*|987654321*|admin*|check*|” | nc host port命令模擬發送syslog日志時,syslog竟然寫入到日志文件里了。這時初步判定,問題在發送方,即python socket tcp。
(1)我用模塊logging發送syslog日志時,偶爾也能成功,所以我就決定看一下這個logging發送tcp的原理,找到如下,濃縮版:
#!/usr/bin/env python #-*-coding:utf-8 -*- import socket import cPickle import struct s = u"5*|987654321*|admin*|check*|1*|加班*|datacenterid=1*|" setSock = socket.socket(socket.AF_INET,socket.SOCK_STREAM) setSock.connect((HOST, 514)) cs = cPickle.dumps(s) #slen = struct.pack(">L", 2) try: setSock.send(slen + cs) except socket.error, e: pass setSock.close()
從上面的代碼中我們可以定位到logging模塊用了兩個關鍵的處理cPickle.dumps和struct.pack,后來發現struct.pack沒啥特別大的用。因為我發送的是字符串,如果是字典的話用處就大了。
(2)但是這個發送時,syslog接收的日志開頭會莫名的多出一個大寫V。后來知道如果被傳入字符串是unicode時會是V,utf-8時是S。為了去掉這個多余難看的V,我又看了cPickle模塊的源碼,原理濃縮如下:
#!/usr/bin/env python #-*-coding:utf-8 -*- try: from cStringIO import StringIO except ImportError: from StringIO import StringIO import socket s = u"5*|987654321*|admin*|check*|1*|加班*|datacenterid=1*|" def dumps(obj): fd = StringIO() obj = obj.replace("\\", "\\u005c") obj = obj.replace("\n", "\\u000a") fd.write('V' + obj.encode('raw-unicode-escape') + '\n') fd.write('p' + repr(0) + '\n') fd.write('.') return fd.getvalue() ss = dumps(a) setSock = socket.socket(socket.AF_INET,socket.SOCK_STREAM) setSock.connect((HOST,514)) try: setSock.send(ss) except (AttributeError,socket.error), e: pass setSock.close()
從上面源碼可以發現,它發送的是一個ASCII流。但是為什么要添加那么多的V,P還有換行符呢?
(3)從上面我發現了一個重點raw-unicode-escape,感覺這個東東肯定是重點,然后就把傳入的字符串都轉換成這個格式試試,結果失望。參考了這個,在我不斷嘗試中,終於發現了問題的關鍵,濃縮代碼如下:
#!/usr/bin/env python #-*-coding:utf-8 -*- import socket s = u"5*|987654321*|admin*|check*|1*|加班*|datacenterid=1*|" setSock = socket.socket(socket.AF_INET,socket.SOCK_STREAM) setSock.connect((HOST,514)) ss = (s + '\n').encode('raw-unicode-escape') try: setSock.send(ss) except (AttributeError,socket.error), e: pass setSock.close()
我認為火眼晶晶的小伙伴們都發現了重點,就是字符串后面必須加個\n,還要用raw-unicode-escape編碼,具體為啥,我也不知道。
rsyslog詳解實戰和避坑
作 者:Taosiyu
出 處:https://www.cnblogs.com/taosiyu/p/12930410.html
python logging測試
import logging import socket import sys import os from loguru import logger from logging.handlers import SysLogHandler import logging.handlers from configs import LOG_FILE_DIR LOG_FORMAT = ( "[{time:YYYY-MM-DD HH:mm:ss.SSS}] [{level}] [{module}.{function}:{line}] {message}" ) logger.configure( handlers=[ dict( sink=sys.stderr, filter={ "": logging.INFO, "app1.view": logging.ERROR, }, colorize=False, backtrace=False, format=LOG_FORMAT, ), dict( sink=LOG_FILE_DIR / "ai.log", filter={ "": False, "app1.view": logging.INFO, "app2.view": logging.INFO, }, level=logging.INFO, colorize=False, backtrace=False, format=LOG_FORMAT, ) ] ) formatter = logging.Formatter('%(name)s: %(levelname)s %(message)r') handler = SysLogHandler(facility=SysLogHandler.LOG_LOCAL5, address=('localhost', 514), socktype=socket.SOCK_STREAM) handler.setFormatter(formatter) logger.add(handler, level="INFO")
測試
import socket def test_loguru(): import logging from loguru import logger from logging.handlers import SysLogHandler handler = logging.handlers.SysLogHandler(facility=SysLogHandler.LOG_LOCAL5, address=('localhost', 514), socktype=socket.SOCK_STREAM) logger.add(handler) logger.debug('debug message test') # 指明級別為debug logger.error('error message test') # 指明級別為error logger.debug("That's it, beautiful and simple logging!") def test_logging(): # coding:utf-8, import logging from logging.handlers import SysLogHandler log = logging.getLogger('mylog') log.setLevel(logging.DEBUG) # log_hdlr = SysLogHandler(facility=SysLogHandler.LOG_LOCAL5) log_hdlr = SysLogHandler(facility=SysLogHandler.LOG_LOCAL5, address=("127.0.0.1", 514), socktype=socket.SOCK_STREAM) # log_hdlr = SysLogHandler() log_format = logging.Formatter( 'hhl-%(name)s-server[%(process)d]-%(levelname)s: %(message)s') log_hdlr.setFormatter(log_format) log_hdlr.setLevel(logging.ERROR) # 接受error及以上的日志信息 log.addHandler(log_hdlr) log.debug('debug message test') # 指明級別為debug log.error('error message test') # 指明級別為error print("test_logging") # 最后只保存error及更高優先級的日志 def test_shell(): """ # 最后只保存error及更高優先級的日志 # echo “5*|987654321*|admin*|check*|” | nc localhost 514 """ def socket_log(): import socket import pickle s = u"5*|987654321*|admin*|check*|1*|加班*|datacenterid=1*|" s = b'<171>hhl-mylog-server[3093]-ERROR: error message test\x00' setSock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) setSock.connect(("localhost", 514)) cs = pickle.dumps(s) try: setSock.send(cs) except socket.error as e: pass setSock.close() if __name__ == '__main__': test_loguru()