平民日志处理

@chunpu 2015-06-02 15:37:54发表于 chunpu/blog linuxnginx

平民日志处理

旨在

  • 不需要安装专业日志处理程序
  • 不需要了解专业日志处理的各种概念
  • 改动很小, 每一步都只需添加几行配置
  • 比专业日志处理更加灵活, 更加能自己控制
  • 真正做到 real time
  • 可以直接使用 Linux 命令进行日志分析

日志处理主要是下面这个流程

  • agent 发送日志
  • server 收集日志
  • rotate 日志
  • 分析日志

该方案适合日 PV 10亿量级或以下的中小型服务

agent 发送日志

发送日志使用 Nginx Logging to syslog

Nginx 支持把 error 或者 access log 使用 syslog 方式发送, 而不只是简单的写文件

该功能在 Nginx 1.7.1 才有, 而且默认是 udp syslog, 可以在 Nginx 源码中看到 udp 是 hard code 的, 无法更改

新版 Nginx 支持一个同时存在多个 error_log 或者 access_log directive, 但不能通过 reload 生效, 需要 restart

使用例子, 比如现在是这么存 access 和 error log 的

access_log /path/to/my_service_access.log main;
error_log /path/to/my_service_error.log notice;

现在加上日志发送

# 写入文件部分保持不变
access_log /path/to/my_service_access.log main;
error_log /path/to/my_service_error.log notice;

# 新增 syslog 发送
access_log syslog:server=127.0.0.1:514,facility=local6,severity=debug,tag=na main;
error_log syslog:server=127.0.0.1:514,facility=local6,severity=debug,tag=ne notice;

syslog 这种方式提供参数选择, 在 Nginx 文档中已经写出了参数的含义

  • server 对应日志收集机器的IP和端口, 514 是 rsyslogd 的默认 UDP 端口
  • facility 对应类型, 默认为 local7, 但 Linux 有些程序也是使用 local7, 因此这里填写 local6, 目的是便于筛选
  • severity 对应程序, 默认值为 info, 这里使用了 debug, 因为 debug(7) 比 info(6) 还弱, 目的也是便于筛选
  • tag 是我们自己的标记, 默认值为 nginx, 为了节省空间的原则, 我们把 access 缩减成 na(nginx access 的缩写), ne 同理, 当然叫其他名字也可以

server 收集日志

日志使用 rsyslog, 一般 Linux 发行版都会自带 rsyslog, 但建议尽量升级 rsyslog 到新版本, 旧的 rsyslog 发现过丢失日志的严重问题

rsyslog 用法和很多程序一样

service rsyslog {start|stop|restart}

这里需要我们改动的是 rsyslog 的配置文件 /etc/rsyslog.conf

帮助信息可以通过 man rsyslog.conf 查看

首先需要修改配置头部

# 一般配置都会有这一条
*.info  /var/log/messages
# 我们需要改成下面这样来避免日志被写入默认日志文件, local6 就是前面我们定义的 facility
*.info;local6.none /var/log/messages

然后我们需要在配置加入这三行

# 这里定义了一个日志模板, 具体格式就是: "agentIp 接收时间 tag 信息主体"
$template nginx_template,"%fromhost-ip% %timegenerated:1:19:date-rfc3339% %syslogtag%%msg%\n"

# `:syslogtag, isequal, "na:"` 表示筛选 tag 为 "na:" 的日志
# 日志路径前面加一个 `-` 是为了加快写入速度, 具体可以看 man
:syslogtag, isequal, "na:" -/path/to/my_service_collect_access.log;nginx_template
:syslogtag, isequal, "ne:" -/path/to/my_service_collect_error.log;nginx_template

有些默认配置是注释掉 udp 514 这个端口的, 需要打开它 $UDPServerRun 514

然后 restart 就行啦

rotate 日志

rotate 是一个容易被忽视的细节, 在 PV 日益变高的情况下, 硬盘大小已经成了瓶颈, 日志收集 server 尤其是捉襟见肘, 每天10亿 access_log 已经几百G了, 对于请求 url 复杂或者访问量大的服务, 一天的日志就可以到 1T, 而一般企业提供的硬盘也不过是一个 T 而已, 但如果我们将日志 gzip, 那可以存将近 5个T 的日志

这时候需要更加精细的进行 log rotate

我们新增一个 logrotate 任务 /etc/logrotate.d/collect, 内容如下

/path/to/my_service_collect_access.log
{
    size 100G
    dateext
    dateformat -%Y%m%d-%s
    rotate 20
    compress
    missingok
    notifempty
    sharedscripts
    postrotate
        /bin/kill -HUP `cat /var/run/syslogd.pid 2> /dev/null` 2> /dev/null || true
    endscript
}

我们还需要把 logrotate 从 cron.daily 移到 cron.hourly 中

这段配置的意思是每小时都去尝试日志滚动, 如果超过 100G, 就重命名日志文件(在后面加上时间戳)

dateformat -%Y%m%d-%s 这个配置比较关键, 巧妙使用 %s 时间戳来避免了小时 rotate 出现名字重复的情况, 注意 logrotate 是没有 %H %M 这种时间宏的

分析日志

可以看到整个日志收集流程非常简单, 我们依然可以像单台机器那样 tail -f 直接跟踪全部机器的日志

依然可以使用 awk sort uniq perl 等 Linux 命令去进行一些数据统计, 以及报警触发