Springboot集成ELK

ELK环境搭建

编写docker-compose.yml,使用docker-compose部署ELK服务

注:elasticsearch、logstash、kibana这里使用的是7.17.4。如果需要更换版本要确保三者版本号一致。

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
28
29
30
31
32
33
34
35
36
37
38
version: '3'

services:
elasticsearch:
image: "docker.elastic.co/elasticsearch/elasticsearch:7.17.4"
environment:
- discovery.type=single-node
- "ES_JAVA_OPTS=-Xms4g -Xmx4g"
volumes:
- /etc/localtime:/etc/localtime
- /data/es/data:/usr/share/elasticsearch/data
ports:
- "9200:9200"
- "9300:9300"

logstash:
depends_on:
- elasticsearch
image: "docker.elastic.co/logstash/logstash:7.17.4"
volumes:
- /data/logstash/logstash.conf:/usr/share/logstash/pipeline/logstash.conf
ports:
- "5044:5044"
links:
- elasticsearch

kibana:
depends_on:
- elasticsearch
image: "docker.elastic.co/kibana/kibana:7.17.4"
environment:
- ELASTICSEARCH_URL=http://elasticsearch:9200
volumes:
- /etc/localtime:/etc/localtime
ports:
- "5601:5601"
links:
- elasticsearch

logstash配置文件logstash.conf

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
input {
tcp {
mode => "server"
host => "0.0.0.0"
port => 5044
codec => json
}

}

output {
elasticsearch {
hosts => ["http://elasticsearch:9200"]
index => "springboot-%{+YYYY.MM.dd}"
}
stdout { codec => rubydebug }
}

可能出现的问题

  1. elasticsearch启动时OOM

    通过指定环境变量"ES_JAVA_OPTS=-Xms4g -Xmx4g" 来限制JVM内存大小

  2. elasticsearch启动失败提示无法访问数据目录

    产生问题的原因是容器内部目录与宿主机目录关联,当服务向容器内部写入数据时会同步到宿主机目录,但是由于对宿主机目录没有写权限,从而报错

    解决方案是执行chmod 777 -R <宿主机挂载路径>

Springboot集成

  1. 在pom.xml中添加logstash依赖
1
2
3
4
5
<dependency>
<groupId>net.logstash.logback</groupId>
<artifactId>logstash-logback-encoder</artifactId>
<version>7.1.1</version>
</dependency>
  1. logback-spring.xml中添加appender,将日志按照想要的格式发送给logstash
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
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<include resource="org/springframework/boot/logging/logback/defaults.xml"/>
<springProperty scope="context" name="logstashHost" source="logstash.host" />
<springProperty scope="context" name="logstashPort" source="logstash.port" />
<appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>INFO</level>
</filter>
<encoder>
<pattern>%red(%date) %green([%thread]) %highlight(%-5level) %boldMagenta([%logger{50}]) %cyan(%file:%line -
%msg%n)
</pattern>
<charset>UTF-8</charset>
</encoder>
</appender>
<!-- logstash tcp -->
<appender name="LOGSTASH" class="net.logstash.logback.appender.LogstashTcpSocketAppender">
<destination>${logstashHost}:${logstashPort}</destination>
<encoder charset="UTF-8"
class="net.logstash.logback.encoder.LoggingEventCompositeJsonEncoder">
<providers>
<timestamp>
<timeZone>UTC</timeZone>
</timestamp>
<pattern>
<pattern>
{
"logLevel": "%level",
"serviceName": "${springAppName:-}",
"pid": "${PID:-}",
"thread": "%thread",
"class": "%logger",
"rest": "%message"
}
</pattern>
</pattern>
</providers>
</encoder>
</appender>

<appender name="FILE_INFO" class="ch.qos.logback.core.rolling.RollingFileAppender">
<!--如果只是想要 Info 级别的日志,只是过滤 info 还是会输出 Error 日志,因为 Error 的级别高, 所以我们使用下面的策略,可以避免输出 Error 的日志-->
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<!--过滤 Error-->
<level>ERROR</level>
<!--匹配到就禁止-->
<onMatch>DENY</onMatch>
<!--没有匹配到就允许-->
<onMismatch>ACCEPT</onMismatch>
</filter>
<!--日志名称,如果没有File 属性,那么只会使用FileNamePattern的文件路径规则如果同时有<File>和<FileNamePattern>,那么当天日志是<File>,明天会自动把今天的日志改名为今天的日期。即,<File> 的日志都是当天的。-->
<!--<File>logs/info.spring-boot-demo-logback.log</File>-->
<!--滚动策略,按照时间滚动 TimeBasedRollingPolicy-->
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<!--文件路径,定义了日志的切分方式——把每一天的日志归档到一个文件中,以防止日志填满整个磁盘空间-->
<FileNamePattern>logs/info.created_on_%d{yyyy-MM-dd}.part_%i.log</FileNamePattern>
<!--只保留最近90天的日志-->
<maxHistory>7</maxHistory>
<!--用来指定日志文件的上限大小,那么到了这个值,就会删除旧的日志-->
<totalSizeCap>10GB</totalSizeCap>
<timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
<!-- maxFileSize:这是活动文件的大小,默认值是10MB,本篇设置为1KB,只是为了演示 -->
<maxFileSize>500MB</maxFileSize>
</timeBasedFileNamingAndTriggeringPolicy>
</rollingPolicy>
<!--<triggeringPolicy class="ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy">-->
<!--<maxFileSize>1KB</maxFileSize>-->
<!--</triggeringPolicy>-->
<encoder>
<pattern>%date [%thread] %-5level [%logger{50}] %file:%line - %msg%n</pattern>
<charset>UTF-8</charset> <!-- 此处设置字符集 -->
</encoder>
</appender>

<appender name="FILE_ERROR" class="ch.qos.logback.core.rolling.RollingFileAppender">
<!--如果只是想要 Error 级别的日志,那么需要过滤一下,默认是 info 级别的,ThresholdFilter-->
<filter class="ch.qos.logback.classic.filter.ThresholdFilter">
<level>Error</level>
</filter>
<!--日志名称,如果没有File 属性,那么只会使用FileNamePattern的文件路径规则如果同时有<File>和<FileNamePattern>,那么当天日志是<File>,明天会自动把今天的日志改名为今天的日期。即,<File> 的日志都是当天的。-->
<!--<File>logs/error.spring-boot-demo-logback.log</File>-->
<!--滚动策略,按照时间滚动 TimeBasedRollingPolicy-->
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<!--文件路径,定义了日志的切分方式——把每一天的日志归档到一个文件中,以防止日志填满整个磁盘空间-->
<FileNamePattern>logs/error.created_on_%d{yyyy-MM-dd}.part_%i.log</FileNamePattern>
<!--只保留最近90天的日志-->
<maxHistory>7</maxHistory>
<timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
<!-- maxFileSize:这是活动文件的大小,默认值是10MB,本篇设置为1KB,只是为了演示 -->
<maxFileSize>100MB</maxFileSize>
</timeBasedFileNamingAndTriggeringPolicy>
</rollingPolicy>
<encoder>
<pattern>%date [%thread] %-5level [%logger{50}] %file:%line - %msg%n</pattern>
<charset>UTF-8</charset> <!-- 此处设置字符集 -->
</encoder>
</appender>

<root level="info">
<appender-ref ref="CONSOLE"/>
<appender-ref ref="LOGSTASH"/>
<appender-ref ref="FILE_INFO"/>
<appender-ref ref="FILE_ERROR"/>
</root>
</configuration>

Trick:

如果想通过springboot的配置文件获取logstash的配置信息可以通过springProperty标签

1
2
<springProperty scope="context" name="logstashHost" source="logstash.host" />
<springProperty scope="context" name="logstashPort" source="logstash.port" />

再通过指定变量<destination>${logstashHost}:${logstashPort}</destination>即可对接logstash