介绍
我们终于准备好为我们的生产应用程序设置设置集中式日志记录。 集中式日志记录是收集和可视化服务器日志的好方法。 通常,设置一个精心设计的日志系统不如设置可靠的备份和监控重要,但它在尝试识别应用程序的趋势或问题时非常有用。
在本教程中,我们将设置一个 ELK 堆栈(Elasticsearch、Logstash 和 Kibana),并配置构成我们应用程序的服务器以将其相关日志发送到日志服务器。 我们还将设置 Logstash 过滤器,它将解析和构建我们的日志,这将使我们能够轻松地搜索和过滤它们,并在 Kibana 可视化中使用它们。
先决条件
如果您想通过域名访问日志仪表板,请在您的域下创建一个 A 记录,例如“logging.example.com”,它指向您的 logging 服务器的公网 IP 地址。 或者,您可以通过公共 IP 地址访问监控仪表板。 建议您将日志记录 Web 服务器设置为使用 HTTPS,并通过将其置于 VPN 后面来限制对其的访问。
在日志服务器上安装 ELK
按照本教程在 logging 服务器上设置 ELK:如何在 Ubuntu 14.04 上安装 Elasticsearch、Logstash 和 Kibana 4。
如果您使用私有 DNS 进行名称解析,请务必遵循 生成 SSL 证书部分 中的 选项 2。
当您到达 Set Up Logstash Forwarder 部分时停止。
在客户端上设置 Logstash 转发器
在您的客户端服务器上设置 Logstash Forwarder,一个日志传送器,即 db1、app1、app2 和 lb1,按照 ELK 教程的 设置 Logstash 转发器部分 。
完成后,您应该可以通过 logging 服务器的公网地址登录 Kibana,并查看每个服务器的 syslog。
确定要收集的日志
根据您的具体应用程序和设置,可以将不同的日志收集到您的 ELK 堆栈中。 在我们的例子中,我们将收集以下日志:
- MySQL 慢查询日志 (db1)
- Apache 访问和错误日志(app1 和 app2)
- HAProxy 日志 (lb1)
我们选择这些日志是因为它们可以在故障排除或尝试识别趋势时提供一些有用的信息。 您的服务器可能有您想要收集的其他日志,但这将帮助您开始。
设置 MySQL 日志
MySQL 的慢查询日志通常位于 /var/log/mysql/mysql-slow
。 它由运行时间足以被视为“慢查询”的日志组成,因此识别这些查询可以帮助您优化或排除应用程序故障。
开启 MySQL 慢查询日志
默认情况下不启用慢查询日志,所以让我们配置 MySQL 来记录这些类型的查询。
打开你的 MySQL 配置文件:
sudo vi /etc/mysql/my.cnf
找到注释过的“log_slow_queries”行,取消注释,如下所示:
/etc/mysql/my.cnf
log_slow_queries = /var/log/mysql/mysql-slow.log
保存并退出。
我们需要重新启动 MySQL 以使更改生效:
sudo service mysql restart
现在 MySQL 会将其长时间运行的查询记录到配置中指定的日志文件中。
运送 MySQL 日志文件
我们必须配置 Logstash Forwarder 以将 MySQL 慢查询日志发送到我们的日志服务器。
在您的数据库服务器 db1 上,打开 Logstash Forwarder 配置文件:
sudo vi /etc/logstash-forwarder.conf
在现有条目下的“文件”部分添加以下内容,以将 MySQL 慢查询日志作为“mysql-slow”类型发送到您的 Logstash 服务器:
logstash-forwarder.conf — MySQL 慢查询
, { "paths": [ "/var/log/mysql/mysql-slow.log" ], "fields": { "type": "mysql-slow" } }
保存并退出。 这将 Logstash Forwarder 配置为发送 MySQL 慢查询日志并将它们标记为“mysql-slow”类型的日志,稍后将用于过滤。
重新启动 Logstash Forwarder 以开始传送日志:
sudo service logstash-forwarder restart
多行输入编解码器
MySQL慢查询日志是多行格式(即 每个条目跨越多行),因此我们必须启用 Logstash 的多行编解码器才能处理这种类型的日志。
在 ELK 服务器 logging 上,打开定义了 Lumberjack 输入的配置文件:
sudo vi /etc/logstash/conf.d/01-lumberjack-input.conf
在 lumberjack
输入定义中,添加以下行:
codec => multiline { pattern => "^# User@Host:" negate => true what => previous }
保存并退出。 这会将 Logstash 配置为在遇到包含指定模式的日志时使用多行日志处理器(即 以“#User@Host:”开头)。
接下来,我们将为 MySQL 日志设置 Logstash 过滤器。
MySQL 日志过滤器
在 ELK 服务器 logging 上,打开一个新文件以将我们的 MySQL 日志过滤器添加到 Logstash。 我们将其命名为 11-mysql.conf
,因此它将在 Logstash 输入配置之后读取(在 01-lumberjack-input.conf
文件中):
sudo vi /etc/logstash/conf.d/11-mysql.conf
添加以下过滤器定义:
11-mysql.conf
filter { # Capture user, optional host and optional ip fields # sample log file lines: if [type] == "mysql-slow" { grok { match => [ "message", "^# User@Host: %{USER:user}(?:\[[^\]]+\])?\s+@\s+%{HOST:host}?\s+\[%{IP:ip}?\]" ] } # Capture query time, lock time, rows returned and rows examined grok { match => [ "message", "^# Query_time: %{NUMBER:duration:float}\s+Lock_time: %{NUMBER:lock_wait:float} Rows_sent: %{NUMBER:results:int} \s*Rows_examined: %{NUMBER:scanned:int}"] } # Capture the time the query happened grok { match => [ "message", "^SET timestamp=%{NUMBER:timestamp};" ] } # Extract the time based on the time of the query and not the time the item got logged date { match => [ "timestamp", "UNIX" ] } # Drop the captured timestamp field since it has been moved to the time of the event mutate { remove_field => "timestamp" } } }
保存并退出。 这将 Logstash 配置为使用 match
指令中指定的 Grok 模式过滤 mysql-slow
类型的日志。 apache-access
类型日志由 Logstash 提供的与默认 Apache 日志消息格式匹配的 Grok 模式解析,而 apache-error
类型日志由为匹配而编写的 Grok 过滤器解析默认错误日志格式。
为了让这些过滤器发挥作用,让我们重新启动 Logstash:
sudo service logstash restart
此时,您需要确保 Logstash 正常运行,因为配置错误会导致它失败。
您还需要确认 Kibana 能够查看过滤后的 Apache 日志。
阿帕奇日志
Apache 的日志通常位于 /var/log/apache2
中,名为“access.log”和“error.log”。 除了 Apache 报告的任何错误消息之外,收集这些日志将允许您查看谁在访问您的服务器的 IP 地址、他们的请求以及他们使用的操作系统和 Web 浏览器。
运送 Apache 日志文件
我们必须配置 Logstash Forwarder 以将 Apache 访问和错误日志发送到我们的日志服务器。
在您的应用服务器 app1 和 app2 上,打开 Logstash Forwarder 配置文件:
sudo vi /etc/logstash-forwarder.conf
在现有条目下的“文件”部分添加以下内容,以将 Apache 日志作为适当的类型发送到您的 Logstash 服务器:
logstash-forwarder.conf — Apache 访问和错误日志
, { "paths": [ "/var/log/apache2/access.log" ], "fields": { "type": "apache-access" } }, { "paths": [ "/var/log/apache2/error.log" ], "fields": { "type": "apache-error" } }
保存并退出。 这会将 Logstash Forwarder 配置为发送 Apache 访问和错误日志,并将它们标记为各自的类型,用于过滤日志。
重新启动 Logstash Forwarder 以开始传送日志:
sudo service logstash-forwarder restart
现在,您的所有 Apache 日志都将具有与 HAProxy 服务器的私有 IP 地址匹配的客户端源 IP 地址,因为 HAProxy 反向代理是从 Internet 访问您的应用程序服务器的唯一方式。 要更改此设置以显示访问您站点的实际用户的源 IP,我们可以修改默认 Apache 日志格式以使用 HAProxy 发送的 X-Forwarded-For
标头。
打开您的 Apache 配置文件 (apache2.conf):
sudo vi /etc/apache2/apache2.conf
找到如下所示的行:
[Label apache2.conf — Original "combined" LogFormat] LogFormat "%h %l %u %t \"%r\" %>s %O \"%{Referer}i\" \"%{User-Agent}i\"" combined
将 %h 替换为 %{X-Forwarded-For}i,如下所示:
[Label apache2.conf — Updated "combined" LogFormat] LogFormat "%{X-Forwarded-For}i %l %u %t \"%r\" %>s %O \"%{Referer}i\" \"%{User-Agent}i\"" combined
保存并退出。 这会将 Apache 访问日志配置为包含实际用户的源 IP 地址,而不是 HAProxy 服务器的私有 IP 地址。
重新启动 Apache 以使日志更改生效:
sudo service apache2 restart
现在我们准备好将 Apache 日志过滤器添加到 Logstash。
Apache 日志过滤器
在 ELK 服务器 logging 上,打开一个新文件以将我们的 Apache 日志过滤器添加到 Logstash。 我们将其命名为 12-apache.conf
,因此它将在 Logstash 输入配置之后读取(在 01-lumberjack-input.conf
文件中):
sudo vi /etc/logstash/conf.d/12-apache.conf
添加以下过滤器定义:
12-apache.conf
filter { if [type] == "apache-access" { grok { match => { "message" => "%{COMBINEDAPACHELOG}" } } } } filter { if [type] == "apache-error" { grok { match => { "message" => "\[(?<timestamp>%{DAY:day} %{MONTH:month} %{MONTHDAY} %{TIME} %{YEAR})\] \[%{DATA:severity}\] \[pid %{NUMBER:pid}\] \[client %{IPORHOST:clientip}:%{POSINT:clientport}] %{GREEDYDATA:error_message}" } } } }
保存并退出。 这将 Logstash 配置为使用各自 match
指令中指定的 Grok 模式过滤 apache-access
和 apache-error
类型的日志。 apache-access
类型日志由 Logstash 提供的与默认 Apache 日志消息格式匹配的 Grok 模式解析,而 apache-error
类型日志由为匹配而编写的 Grok 过滤器解析默认错误日志格式。
为了让这些过滤器发挥作用,让我们重新启动 Logstash:
sudo service logstash restart
此时,您需要确保 Logstash 正常运行,因为配置错误会导致它失败。 您还需要确认 Kibana 能够查看过滤后的 Apache 日志。
HAProxy 日志
HAProxy 的日志通常位于 /var/log/haproxy.log
。 收集这些日志将允许您查看谁在访问您的负载均衡器的 IP 地址、他们正在请求什么、哪个应用程序服务器正在为他们的请求提供服务,以及有关连接的各种其他详细信息。
运送 HAProxy 日志文件
我们必须配置 Logstash Forwarder 来发送 HAProxy 日志。
在您的 HAProxy 服务器 lb1 上,打开 Logstash Forwarder 配置文件:
sudo vi /etc/logstash-forwarder.conf
在现有条目下的“文件”部分添加以下内容,以将 HAProxy 日志作为“haproxy-log”类型发送到您的 Logstash 服务器:
logstash-forwarder.conf — HAProxy 日志
, { "paths": [ "/var/log/haproxy.log" ], "fields": { "type": "haproxy-log" } }
保存并退出。 这会将 Logstash Forwarder 配置为发送 HAProxy 日志并将它们标记为 haproxy-log
,这将用于过滤日志。
重新启动 Logstash Forwarder 以开始传送日志:
sudo service logstash-forwarder restart
HAProxy 日志过滤器
在 ELK 服务器 logging 上,打开一个新文件以将我们的 HAProxy 日志过滤器添加到 Logstash。 我们将其命名为 13-haproxy.conf
,因此它将在 Logstash 输入配置之后读取(在 01-lumberjack-input.conf
文件中):
sudo vi /etc/logstash/conf.d/13-haproxy.conf
添加以下过滤器定义:
filter { if [type] == "haproxy-log" { grok { match => { "message" => "%{SYSLOGTIMESTAMP:timestamp} %{HOSTNAME:hostname} %{SYSLOGPROG}: %{IPORHOST:clientip}:%{POSINT:clientport} \[%{MONTHDAY}[./-]%{MONTH}[./-]%{YEAR}:%{TIME}\] %{NOTSPACE:frontend_name} %{NOTSPACE:backend_name}/%{NOTSPACE:server_name} %{INT:time_request}/%{INT:time_queue}/%{INT:time_backend_connect}/%{INT:time_backend_response}/%{NOTSPACE:time_duration} %{INT:http_status_code} %{NOTSPACE:bytes_read} %{DATA:captured_request_cookie} %{DATA:captured_response_cookie} %{NOTSPACE:termination_state} %{INT:actconn}/%{INT:feconn}/%{INT:beconn}/%{INT:srvconn}/%{NOTSPACE:retries} %{INT:srv_queue}/%{INT:backend_queue} "(%{WORD:http_verb} %{URIPATHPARAM:http_request} HTTP/%{NUMBER:http_version})|<BADREQ>|(%{WORD:http_verb} (%{URIPROTO:http_proto}://))" } } } }
保存并退出。 这将 Logstash 配置为使用相应 match
指令中指定的 Grok 模式过滤 haproxy-log
类型的日志。 haproxy-log
类型的日志由与默认 HAProxy 日志消息格式匹配的 Logstash 提供的 Grok 模式解析。
为了让这些过滤器发挥作用,让我们重新启动 Logstash:
sudo service logstash restart
此时,您需要确保 Logstash 正常运行,因为配置错误会导致它失败。
设置 Kibana 可视化
现在您正在一个中心位置收集日志,您可以开始使用 Kibana 来可视化它们。 本教程可以帮助您入门:如何使用 Kibana 仪表板和可视化。
一旦您对 Kibana 有所了解,请尝试本教程以一种有趣的方式可视化您的用户:如何使用 GeoIP 和 ELK 映射用户位置。
结论
恭喜! 您已完成生产 Web 应用程序设置教程系列。 如果您按照所有教程进行操作,那么您应该有一个类似于我们在概述教程中描述的设置(使用私有 DNS 和远程备份):
也就是说,您应该有一个工作应用程序,具有分离的组件,由备份、监控和集中式日志记录组件支持。 请务必测试您的应用程序,并确保所有组件都按预期工作。