互联网时代,数据的价值被无限强调,对于开发人员来说,日志并不陌生,但是不知道有多少人有尝试过系统化的收集和处理日志,本文尝试从服务器日志收集建设开始讲起,给出一套相对简单、经济的日志采集方案。

这几年各家云主机轮番价格战之后,我们的云主机越来越多,网站也越来越多,除了在云主机管理面板或者通过API进行资源查询之外,有什么更好的方式可以尽可能在不大量编码,把不同云主机厂商的日志收归一处么?

当然,现在的公司一般都配置了数据团队,会使用ELK技术栈或者SPARK技术栈去进行数据的ETL,但是对于个人来说,这些都过于笨重了,即使因为容器技术蓬勃发展,几个配置文件一两条命令就能够把服务启动起来,但是有2个小问题:

  1. ELK本身对维护和对硬件资源要求不低。
  2. 周边对接的系统,对维护和资源的要求不低。

本着节约(穷)的精神,本文使用家里的宽带和一台闲置小主机进行日志的采集收归,相关资源配置,我在Home-Network-Note有提及,一台ATOM群晖兼容机即可,还能偷懒不折腾界面。

数据桥梁

公网和家里的机器想愉快进行日志采集,有这么几个方式:

  • 家庭宽带有固定IP,暴露端口到最外层路由,公网机器和家庭机器公网IP到公网IP。
    • 前几年还有这类宽带,现在已经基本绝迹,商用宽带太贵,而且需要公司进行申请。
  • 家庭宽带有浮动IP,使用DDNS将家庭IP绑定到一个域名上,随着IP更新,域名指向更新。
    • 如果动态域名指向的最外层设备存在安全隐患,将会危害整个内网,以及需要考虑域名解析被劫持的问题,域名解析存在生效时间、域名解析服务商选择也比较麻烦。
  • 使用被动连接的方式,将家庭内部应用流量转发到一个固定IP的公网机器,充当数据桥梁,云主机到云主机,然后再从这台桥梁的机器转发到内网。
    • 本文采取这种方案。

配置日志采集服务端

我们先进行服务端配置。

在群晖Web管理界面中找到套件中心,选择日志中心进行安装,软件安装之后。

安装日志服务

我们可以ssh到机器上,通过ps进行进程查看,我们可以看到:

soulteary@Lemon:/$ ps -ef | grep log
system    4325     1  0 01:27 ?        00:03:09 /usr/bin/syslog-ng -F --worker-threads=4 -u system -g log
root      4747     1  0 01:27 ?        00:00:02 /usr/syno/sbin/synologaccd -f
root      4881     1  0 01:27 ?        00:00:00 /usr/syno/bin/synologrotated
soultea+  5741  5722  0 12:06 pts/17   00:00:00 grep --color=auto log
root     11594     1  0 01:28 ?        00:00:18 /var/packages/LogCenter/target/usr/bin/syslog-ng --cfgfile=/var/packages/LogCenter/target/etc/syslog-ng/syslog-ng.conf -F --worker-threads=4

群晖的日志系统是使用 syslog-ng 这个软件来做的服务端,简单扫了一眼这个开源项目的仓库,了解到这个工具有一个将日志进行数据库化落地的能力,支持 RFC3164RFC5424 两种风格的日志消息。

简单进行一番配置,选择好文件数据库存放位置,归档配置(synologrotated),新建一个接收日志的配置(syslog-ng)。

配置日志服务

下面是我的配置:

名称: CloudServer
日志格式: BSD格式
规则参数: 不填
传输协议: UDP
端口: 514
SSL安全连接:不勾选

为了测试这个服务是否正常,我写了一个简单的脚本来进行验证:

const os = require('os');
const syslog = require('syslog-client');

const reportHost = '10.9.8.180';
const port = 514;
const mode = 'UDP';
const facility = syslog.Facility.User;
const appName = 'Test';
const syslogHostname = os.hostname();
const severity = syslog.Severity.Informational;
const transport = (mode === 'UDP' ? syslog.Transport.Udp : syslog.Transport.Tcp);
const testTimes = 100000;

const options = {syslogHostname, transport, port, facility, appName, severity};
const logger = syslog.createClient(reportHost, options);

for (let i = 0; i < 10; i++) {
  setTimeout(() => {
    for (let i = 0; i < testTimes / 10; i++) {
      logger.log('example message');
    }
  }, 10);
}

logger.on('close', () => {
  console.log('socket closed');
});

logger.on('error', (error) => {
  console.error(error);
});

执行脚本,尝试在短时间内快速发送10万个日志,看到日志中心有实时的消息进来了,但是数量有很大的出入。

发送UDP日志测试

将脚本中定义的发送方式改为TCP,同时修改接受服务端的模式,再次尝试发送。

可以看到10w个日志一条不差的都收集过来了。

发送TCP日志测试

接下来把内网的日志服务通过一台公网服务器暴露出去就可以对外提供服务了。

这里采取frp的方式进行,之前的文章里有提过这个方式,不过这次要转发的不是HTTP/HTTPS协议的内容,而是TCP。

前文提过数据桥梁的事情,内网服务器虽然是日志采集服务端,但是在数据传递上面来讲,它是数据桥梁的消费者,所以要执行frp客户端。

下面直接给出一份客户端配置参考:

[common]
server_addr = 你的公网服务器地址
server_port = 公网frp服务端口

token = 连接token
dns_server = DNS服务器地址,这里填写内网DNS服务器地址

[syslog]
type = tcp
local_ip = 0.0.0.0
local_port = 514
remote_port = 公网服务器服务端口

使用方式同之前的文章中提到的,在服务端执行服务端程序并指定配置文件,客户端同理:

frpc -c frpc.ini

(群晖进程守护部分稍后补上。)

接下来我们来配置日志采集客户端。

日志采集客户端

在搭建日志采集的客户端,数据提供方之前,我们需要把网络先联通,把之前提到的数据桥梁先搭建起来。

同样给出frp的服务端配置:

[common]
bind_port        = 公网frp服务端口

token = 连接token

dashboard_addr = 0.0.0.0
dashboard_port = 公网管理端口

# dashboard user and passwd for basic auth protect, if not set, both default value is admin
dashboard_user = 管理用户账号
dashboard_pwd  = 管理用户密码

启动服务,可以看到frp客户端和服务端显示已经连接成功,出于信息敏感就不贴日志输出了。

frpc -c frpc.ini

一般来说,服务器的运行是很稳定的,但是服务器有可能因为提供商的种种原因而升级或者迁移而重启、进程可能因为系统资源不足而被干掉,为了保障服务的稳定,我们使用进行管理工具来进一步加固这个服务。

这里推荐使用 supervisor 进行进程守护,先进行安装,并进行:

sudo apt install supervisor -y

/etc/supervisor/conf.d 创建一个frp的配置文件,:

[program:syslog-frp]
user=root
command=/data/syslog/frps -c /data/syslog/frps.ini
autostart=true
startsecs=3
startretries=100
autorestart=true
stderr_logfile=/data/syslog/error.log
stderr_logfile_maxbytes=50MB
stderr_logfile_backups=10
stdout_logfile=/data/syslog/access.log
stdout_logfile_maxbytes=50MB
stdout_logfile_backups=10

重启 supervisor ,加载刚刚创建的配置,然后查看配置是否被正确的加载。

sudo systemctl restart supervisor
sudo supervisorctl status

可以看到配置文件被正确的加载,frp进程得到了守护。

syslog-frp                       RUNNING   pid 3781, uptime 1:09:34

好了,那么接着来配置日志上报服务。

刚才提到服务端支持两种协议,所以我们不必使用同样的软件,只要软件支持这两种协议即可。

这里推荐使用rsyslog进行日志的采集传输,Linux系统中一般都会默认安装,如果没有安装可以使用下面的命令进行安装:

sudo apt-get install rsyslog -y

在使用之前,需要先检查一下版本,新老版本支持的配置有一些不同。

rsyslogd -version
rsyslogd 8.16.0, compiled with:
	PLATFORM:				x86_64-pc-linux-gnu
	PLATFORM (lsb_release -d):		
	FEATURE_REGEXP:				Yes
	GSSAPI Kerberos 5 support:		Yes
	FEATURE_DEBUG (debug build, slow code):	No
	32bit Atomic operations supported:	Yes
	64bit Atomic operations supported:	Yes
	memory allocator:			system default
	Runtime Instrumentation (slow code):	No
	uuid support:				Yes
	Number of Bits in RainerScript integers: 64

See http://www.rsyslog.com for more information.

如果你的软件大版本也是8.x的话,可以参考下面的配置方法:

先修改位于 /etc/rsyslog.conf 的配置文件。

# 添加或者去掉配置文件中被注释的内容
module(load="imtcp")
input(type="imtcp" port="514")


# 在文件底部添加网络故障进行本地缓存,稍后重试
$ActionQueueFileName queue
$ActionQueueMaxDiskSpace 1g
$ActionQueueSaveOnShutdown on
$ActionQueueType LinkedList
$ActionResumeRetryCount -1

# 在文件底部添加使用TCP模式转发日志数据

*.*                    @@公网服务器地址:公网服务端端口

重启服务,让本次修改生效。

service rsyslog restart

为了验证服务是否配置正确,输入测试语句:

logger -p local0.info "Hello World"

测试日志接收

可以看到客户端已经可以成功接收来自云服务器的日志消息了。

之前提到我有使用traefik来提供服务发现,作为应用网关。

当时把输出日志保存成了文件,对于这类日志该如何处理呢,再次修改位于 /etc/rsyslog.conf 的配置文件。

# 在配置顶部添加读取文件的模块,配置更新间隔为1s
module(load="imfile" PollingInterval="1")

创建一个 /etc/rsyslog.d/30-traefik.conf 配置文件,内容如下:

# proc log
$InputFileName /data/traefik/logs/access.log
$InputFileTag traefik-proc:
$InputFileStateFile stat-traefik-proc
$InputFileSeverity debug
$InputFileFaility local6
$InputFilePollInterval 1
$InputRunFileMonitor

# access log
$InputFileName /data/traefik/logs/access.log
$InputFileTag traefik:
$InputFileSeverity debug
$InputFileFaility local6
$InputFilePollInterval 1
$InputRunFileMonitor

再次重启进程之后,我们发现客户端已经可以正确接受这些消息了。

来自云服务器的日志

额外要提的一些事

对所有的机器和应用进行类似的配置之后,你的日志采集服务就搭设完毕了。

最终运行效果

在服务运行一定时间之后,我们就可以尝试进行简单的ETL数据操作了。

另外,日志文件虽然不见得有“业务文件”和“业务数据”重要,但是备份也是必须的。

建议使用Raid或者Rsync之类的方案将数据进行合理备份,避免后续想进行分析的时候缺少数据。

最后

先写到这里,后面有机会聊聊日志文件的分析整理,以及采集服务的安全加固。

如果你对本篇文章的内容有疑问或者想讨论,欢迎联系我,我的联系方式聪明的你应该找的到吧?

–EOF