项目环境:spring boot
日志框架 :slf4j+logback
ELK安装(docker方式):
具体步骤:
1,下载elk镜像(不带版本号应该可以下到最新版的)
docker pull sebp/elk
2,设置线程大小,该数值过小可能导致无法启动elk容器;
echo "vm.max_map_count=262144" > /etc/sysctl.conf
sysctl -p
3,启动命令
docker run -dit --name elk -e ES_JAVA_OPTS="-Xms3072m -Xmx3072m" -p 5601:5601 -p 9200:9200 -p 5044:5044 -v /data/elk:/var/lib/elasticsearch -v /etc/localtime:/etc/localtime sebp/elk
-name 给容器去个名字,我这里容器名字是: elk
-e 设置elasticsearch参数,也可以在配置文件中改(稍后会说);
-p docker端口映射,5601kibana端口,9200es端口,5044 logstash端口;
-v 目录映射
4,ELK容器内配置
docker exec -it elk /bin/bash
进入docker终端后可在一下路径中找到相关配置文件
/etc/logstash/ ## logstash 配置文件路径
/etc/elasticsearch/ ## es 配置文件路径
/var/log/ ## 日志路径
注意:部分配置可能并不在上面的文件夹中,需要进入 /etc/init.d/ 文件夹中找到对应的配置更改后才能生效;
- Logstash 配置:
vim /etc/logstash/conf.d/02-beats-input.conf
input {
tcp {
port => 5044 //logstash 端口
codec=>json_lines //半结构化的json字符串数据格式
}
}
output {
elasticsearch {
hosts => ["127.0.0.1:9200"] //elasticsearch的地址和端口,127.0.0.1只是个示例,最好不要天回环地址
index => "logstash-%{+YYYY.MM.dd}" //索引名称,可以应用变量的。这里我配置成了logstash-XXX 稍后和spring boot集成时会说明
}
}
- kibana配置
这个其实没有太多要配置的,我改过内存,然鹅并没有什么卵用,还没找到原因
vim /opt/kibana/config/kibana.yml
在文件内追加 i18n.locale: "zh-CN" 可以改成中文
配置完后按Ctrl+D退出docker终端;
重启容器,配置生效
docker restart elk
5,集成到spring boot 项目
- POM依赖
<dependency>
<groupId>net.logstash.logback</groupId>
<artifactId>logstash-logback-encoder</artifactId>
<version>6.3</version>
</dependency>
- application.properties配置
spring.profiles.active=release
logging.config=classpath:logback-spring.xml
- logback-spring.xml配置
<?xml version="1.0" encoding="UTF-8"?>
<configuration debug="false">
<contextName>third-party-gateway-api</contextName>
<property name="LOG_HOME" value="./logs" />
<!-- 控制台输出 -->
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
<!--格式化输出:%d表示日期,%thread表示线程名,%-5level:级别从左显示5个字符宽度%msg:日志消息,%n是换行符-->
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{40}.%M %L %X{sessionId} - %msg%n</pattern>
</encoder>
</appender>
<!-- 按照每天生成日志文件 -->
<appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<!--日志文件输出的文件名-->
<FileNamePattern>${LOG_HOME}/log.%d{yyyy-MM-dd}.log</FileNamePattern>
<!--日志文件保留天数-->
<MaxHistory>30</MaxHistory>
</rollingPolicy>
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
<!--格式化输出:%d表示日期,%thread表示线程名,%-5level:级别从左显示5个字符宽度%msg:日志消息,%n是换行符-->
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{40}.%M %L %X{sessionId} - %msg%n</pattern>
</encoder>
<!--日志文件最大的大小-->
<!-- <triggeringPolicy class="ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy">
<MaxFileSize>10MB</MaxFileSize>
</triggeringPolicy> -->
</appender>
<springProfile name="release">
<appender name="LOGSTASH" class="net.logstash.logback.appender.LogstashTcpSocketAppender">
<destination>127.0.0.1:5044</destination>
<encoder
class="net.logstash.logback.encoder.LoggingEventCompositeJsonEncoder">
<providers>
<timestamp>
<timeZone>UTC</timeZone>
</timestamp>
<pattern>
<pattern>
{
"hostName":"${HOSTNAME}",
"contextName":"%contextName",
"thread":"%thread",
"level":"%-5level",
"sessionId": "%X{sessionId}",
"class": "%logger{40}",
"method":"%M",
"line":"%L",
"msg": "%msg"
}
</pattern>
</pattern>
</providers>
</encoder>
</appender>
</springProfile>
<!-- 日志输出级别 -->
<root level="INFO">
<appender-ref ref="STDOUT" />
<appender-ref ref="FILE" />
<springProfile name="release">
<appender-ref ref="LOGSTASH" />
</springProfile >
</root>
<!--日志异步到数据库 -->
<!--<appender name="DB" class="ch.qos.logback.classic.db.DBAppender">-->
<!--<!–日志异步到数据库 –>-->
<!--<connectionSource class="ch.qos.logback.core.db.DriverManagerConnectionSource">-->
<!--<!–连接池 –>-->
<!--<dataSource class="com.mchange.v2.c3p0.ComboPooledDataSource">-->
<!--<driverClass>com.mysql.jdbc.Driver</driverClass>-->
<!--<url>jdbc:mysql://127.0.0.1:3306/databaseName</url>-->
<!--<user>root</user>-->
<!--<password>root</password>-->
<!--</dataSource>-->
<!--</connectionSource>-->
<!--</appender>-->
</configuration>
几个关键点说明:
- <contextName>third-party-gateway-api</contextName>工程或模块名称
- %X{sessionId} 这是一个自定义参数,可以用sfl4j的MDC.put("sessionId","123"),设置会话ID以便追踪日志,分析问题,一般在过滤器或拦截器中设置此值
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
String contentPath = request.getContextPath();
String uri = request.getServletPath();
MDC.put("sessionId",IdUtil.fastSimpleUUID());
//MDC.put("sessionId",request.getParameter("requestId"));
logger.info("-----------------------------------------------");
logger.info("client IP {}",ServletUtil.getClientIP(request));
logger.info("access url : {},{}",request.getMethod(),request.getRequestURL());
logger.info("access content : {}",contentPath);
logger.info("access ServletPath : {}",uri);
return true;
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)
throws Exception {
// TODO Auto-generated method stub
MDC.clear();
}
- <springProfile name="release"> 表示只在spring.profiles.active=release的情况下才激活logstash配置,因为一般开发环境不会安装ELK
-
<pattern> { "hostName":"${HOSTNAME}", "contextName":"%contextName", "thread":"%thread", "level":"%-5level", "sessionId": "%X{sessionId}", "class": "%logger{40}", "method":"%M", "line":"%L", "msg": "%msg" } </pattern>
这段是传送给logstash的数据格式,每个字段都可以在ES中做成索引
6,kibana使用
浏览器打开 http://127.0.0.1:5601 第一次进去会提示加载示例数据,选“否”就可以了;
- 建立索引模式,在索引模式中输入logstash-*(建立之前先启动 spring boot 项目,如不启动,恐无法建立logstash-*模式的索引,还记得第4步中的配置吗:"logstash-%{+YYYY.MM.dd}" ),如图:
- 配置索引策略和生命周期
- 日志查询
看到了么,JSON字符串的所有字段有显示出来了,并且可以快速筛选,KQL语法还支持模糊全文索引,可以用不同的组合查询方式提高查询速度;
7,问题
- 告警,运行状态一直是yellow,(我的是green状态)
其实这个问题并不影响适用,原因是我们采用的是单机ES模式,改一下索引模式的配置就可以了
任意点击一索引,index.number_of_replicas值改成0