概述
程序运行的日志是一个必不可少的东西,包括一些统计日志和程序运行的异常日志。通过日志,我们可以知道程序是不是在正常地运行,如果出现错误,我们还需要利用日志来排查问题。
日志的重要性毋庸置疑,但是我们在使用这些日志的时候效率并不高,主要原因有以下几点:
- 日志文件过于分散,一般会将不同模块的日志以文件的形式分开保存。但是即使是将日志写在统一的目录下,不管是系统正常运行还是出现问题的时候都可能需要检查多个日志。
- 内容过于繁杂,特别是遇到问题的时候,日志更是非常的多,但是在查看日志的时候却往往不得不反复前后翻看错误的关联日志信息,同时还要略过大量无关日志。
- 出现问题的被动性,很可能在程序刚开始运行起来的时候日志是正常,但是在遇到异常的时候不能够及时的发现问题。
目前的解决方案就是规定好统一的日志格式,将所有模块的日志进行适配之后通过 ELK 进行统一的收集存储起来,并建立相应的日志分类与报表,在检查到问题的时候通过邮件的形式通知运维。但是这样的解决方案需要的时间和技术成本还是很大的,而且也不能够很好的提高日志的使用效率。
Sentry简介
Sentry 是一个使用 Python 开发的通过策略将日志事件进行过滤聚合的日志服务。Sentry 依赖的外部服务主要有 Redis 和 PostgreSQL。
Issue & Events
Sentry 使用 Issue 来聚合一类的 Events。
DSN(Data Source Name)
Sentry 服务支持多用户、多团队、多应用管理,每个应用都对应一个 PROJECT_ID
,以及用于身份认证的 PUBLIC_KEY
和 SECRET_KEY
。由此组成一个这样的 DSN。
{PROTOCOL}://{PUBLIC_KEY}:{SECRET_KEY}@{HOST}/{PATH}{PROJECT_ID}
PROTOCOL
通常会是 http
或者 https
,HOST
为 Sentry 服务的主机名和端口,PATH
通常为空。
Sentry SDKs
使用Sentry前还需要在自己的应用中配置Sentry的SDK——通常在各语言的包管理工具中叫做Raven。现在官方支持的SDK如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
|
JavaScript
React-Native
Python
Ruby
Node
PHP
Go
Java
Objective-C/Swift
C#
Perl
Elixir
Laravel
|
应用例子
聚合Spark异常日志
1.替换 JAVA_HOME
的 cacerts
文件,使其支持自定义的 https
cp cacerts /opt/java8/jre/lib/security/cacerts
2.将 Sentry 和 sentry-log4j 的 jar 包拷贝到 $SPARK_HOME
cp sentry.jar sentry-log4j.jar $SPARK_HOME/jars
3.配置 $SPARK_HOME
的 log4j.conf
1
2
3
4
5
6
|
# Enable the Console and Sentry appenders
log4j.rootLogger=INFO, Sentry
# Configure the Sentry appender, overriding the logging threshold to the WARN level
log4j.appender.Sentry=io.sentry.log4j.SentryAppender
log4j.appender.Sentry.threshold=WARN
|
4.修改 spark-submit
的启动参数增加以下选项
1
|
--conf "spark.executor.extraJavaOptions=-Dsentry.dsn=https://<key>@sentry.k8s.uc.host.test/6" --conf "spark.driver.extraJavaOptions=-Dsentry.dsn=https://<key>@sentry.k8s.uc.host.test/6"
|
Spark 任务运行后在 Sentry Web 上显示的错误日志。
应用聚合异常日志
我司很多项目都有接入 Sentry,其中我负责的推荐系统也同意接入了,接入的主要事项如下:
1.依赖定义
在 pom 文件中添加如下依赖。
1
2
3
4
5
6
7
8
9
10
|
<dependency>
<groupId>io.sentry</groupId>
<artifactId>sentry-log4j2</artifactId>
<version>1.7.3</version>
</dependency>
<dependency>
<groupId>io.sentry</groupId>
<artifactId>sentry-log4j</artifactId>
<version>1.7.3</version>
</dependency>
|
2.日志配置
系统用的是 Log4j2 来管理日志,修改 log4j2.xml 文件如下,注意添加的 Sentry 部分:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
|
<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="debug" dev="err" packages="org.apache.logging.log4j.core,io.sentry.log4j2">
<Appenders>
<Console name="STDOUT">
<PatternLayout pattern="%d{DEFAULT} %tid [%tn] %p %c{1}: %m%n"/>
</Console>
<Sentry name="Sentry" />
<Syslog name="RFC5424" format="RFC5424" host="localhost" port="514"
protocol="UDP" appName="recommend-metric-log:"
facility="LOCAL4" enterpriseNumber="18060" newLine="true"
messageId="Audit" mdcId="mdc">
<LoggerFields>
<KeyValuePair key="thread" value="%t"/>
<KeyValuePair key="priority" value="%p"/>
<KeyValuePair key="category" value="%c"/>
<KeyValuePair key="exception" value="%ex"/>
<KeyValuePair key="message" value="%m"/>
</LoggerFields>
</Syslog>
</Appenders>
<Loggers>
<Root level="info">
<AppenderRef ref="STDOUT"/>
<AppenderRef ref="Sentry" level="ERROR"/>
</Root>
</Loggers>
</Configuration>
|
3.DSN 配置
配置相应的 DSN 参数,指定日志发送的 Sentry 服务。
1
|
-Dsentry.dsn=https://<Sentry 服务地址>
|
4.效果
在 Sentry 的 Web 页面上,已经提供了聚合好的异常信息的分类已经发生的时间,也可以把异常当成是待处理的 issue
来指定组员去解决,解决完之后还能进行 comment
等操作,这个流程非常简单、清晰,非常便于团队对 Bug 的跟踪和修复。
警告
本文最后更新于 2017年2月1日,文中内容可能已过时,请谨慎参考。