配置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()