目录
一、简介
分布式应用必须有一套日志采集功能,目的是将分布在各个服务器节点上的应用日志文件采集到统一的服务器上,方便日志的查看。springCloud本身提供了基于elk的日志采集,但是由于使用logstash,会加大运维成本。这里将使用轻量级的方案。
springCloud提供的解决方案请看这篇文章《spring-cloud 分布式日志采集》
二、思路
我们的目的是提供轻量级的日志采集来代替logstash,日志最终还是会存进Elasticsearch。为了能轻量级的实现日志采集,并且避免对代码的侵入,我们可以扩展Logback的appender,也可以扩展log4j的appender。这样我们使用slf4j来记录日志的时候,日志自动会保存到Elasticsearch中,并且不用修改任何业务代码。
三、自定义Logback appender
我们先来看一下Logback的appender的Uml图,我们可以发现两个对我们有借鉴意义的类
UnsynchronizedAppenderBase提供了异步的日志记录
DBAppender基于数据库的日志记录
这两个类还是比较简单的,具体的代码我就不详细解说了,请自行查阅
属性注入
基本实现逻辑从UnsynchronizedAppenderBase和DBAppender已经能够知道了,现在把我们需要的信息注入到Appender中,这里需要如下的知识
-
Logback标签注入属性
我们可以直接在Xml中用标签配置属性,这些标签只要名称和appender中的成员变量名一致,则会自动把标签中的属性注入到成员变量中。
我们举一个例子:
xml这样配置
<appender name="ES" class="com.luminroy.component.logger.appender.ElasticsearchAppender">
<profile>test</profile>
<esType>demo</esType>
<withJansi>true</withJansi>
<encoder>
<pattern>${CONSOLE_LOG_PATTERN_IDE}</pattern>
<charset>utf8</charset>
</encoder>
</appender>
其中ElasticsearchAppender是我们自己实现的Appender。这里有一个profile标签,我们需要ElasticsearchAppender中成员变量的名称和该标签名一致,这样就可以把test值注入到成员变量profile中。
protected String profile = ""; // 运行环境
-
Spring配置信息注入属性
有些信息可能已经在spring中做了配置,我们不想要重复的配置,这个时候我们可以用springProperty标签来进行设置。
scope:作用范围
name:名称
source:spring配置
defaultValue: 默认值,必须要指定
然后在标签中用上面的name属性作为占位符,类中的成员变量名和标签名一致。
我们举一个例子:
xml这样配置
<springProperty scope="context" name="applicationName" source="spring.application.name"
defaultValue=""/>
<springProperty scope="context" name="profile" source="spring.profiles.active"
defaultValue="default"/>
<springProperty scope="context" name="esUserName" source="luminary.elasticsearch.username"
defaultValue="elastic"/>
<springProperty scope="context" name="esPassword" source="luminary.elasticsearch.password"
defaultValue="123456"/>
<springProperty scope="context" name="esServer" source="luminary.elasticsearch.server"
defaultValue="127.0.0.1:9200"/>
<springProperty scope="context" name="esMultiThreaded" source="luminary.elasticsearch.multiThreaded"
defaultValue="true"/>
<springProperty scope="context" name="esMaxTotalConnection" source="luminary.elasticsearch.maxTotalConnection"
defaultValue="20"/>
<springProperty scope="context" name="esMaxTotalConnectionPerRoute" source="luminary.elasticsearch.maxTotalConnectionPerRoute"
defaultValue="5"/>
<springProperty scope="co