4

最简单的Spring Boot 整合ELK教程,实现日志收集

 3 years ago
source link: http://dockone.io/article/2434439
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

最简单的Spring Boot 整合ELK教程,实现日志收集


开发任务后,提交代码的那一刻,心情是自由自在……速度是八十迈……

以为接下来是游戏、逛GAI或暖烘烘的被窝。

然而,梦想何其丰满,现实何其骨干。

总有测试小姐姐教你紧急刹车,回头做(改)人(bug):你这不行啊!(吃瓜群众排排坐,笑歪了嘴)

我低头看了看自己的八块腹肌:行不行可不是你说了算!

小姐姐也不是吃素的,撸起袖子,打开她的联想十代:你行你连连报错,毒奶队友!

我:(⊙o⊙)……原来你说的是这个不行,我还以为……

小姐姐一脸疑惑:以为什么?真以为自己是大神了!

我清咳掉自己的尴尬,绝不认输:我认为是你传错了参数。毕竟本大师在本地调试时可没有任何问题。

小姐姐久经沙场,从无败绩:不!可!能!是你是你就是你!我从来不会错。

那一刻,我仿佛看到生理期的女朋友在面前闪现,内心是崩溃的。

我们俩就这样争执了很久,最后自然不出意料,缴械投降的还是我。

毕竟——

中华民族的传统美(糟)德(粕)是:好男不跟女斗!

于是我只能去服务器上看看日志,但是日志内容累累如高山,多多如牛毛,足足3.5个G,无奈的我只好使用一堆Linux骚命令,将文件切割成一个个小文件,好在最后终于找到了那次请求,排查后找到了原因。

通过这件事,我痛定思痛:如果有一个平台能实时收集我们的日志,并能以可视化的界面呈现出来,那该多好啊!这样我们就再也不用在那堆厚重的日志文件里面找数据了。
其实,这种神奇的平台早就有了,那就是ELK,它是三大神兽Elasticsearch(搜索引擎), Logstash(日志收集),Kibana(可视化的Web界面)的组合,我们来看下架构图:

对照架构图,我们来看下这三大神兽的工作过程:
  1. 用户发送请求到我们的服务端
  2. 服务端将需要落日志的数据通过网络请求传送到Logstash
  3. Logstash对数据进行过滤清洗后,再传给Elasticsearch
  4. Elasticsearch负责对数据创建索引,进行存储
  5. 用户通过访问Kibana的Web页面,能够实时查看日志
好吧,秘籍都告诉你了,现在需要带领你们去实战了。
在打仗之前,我们需要士兵们必须具备以下技能,不然上了战场后,只会被虐的体无完肤。
  • 了解ELK三大组件
  • 有实操过Docker
  • 本地有Docker环境
  • IDEA工具
  • 配置相对高一点的武器(电脑),不然会崩溃的

准备粮草:准备一个Spring Boot项目

首先创建一个Spring Boot项目,项目结构如下:

引入项目必备依赖:
<dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter</artifactId>
    </dependency>
    <dependency>
        <groupId>com.alibaba</groupId>
        <artifactId>fastjson</artifactId>
        <version>1.2.35</version>
    </dependency>
    <dependency>
        <groupId>cn.hutool</groupId>
        <artifactId>hutool-all</artifactId>
        <version>5.4.0</version>
    </dependency>

创建一些基础组件:

创建切面,实现低耦合记录日志。

下面是核心代码:
// 使用环绕通知
@Around("controllerLog()")
public Object doAround(ProceedingJoinPoint joinPoint) throws Throwable {
long startTime = System.currentTimeMillis();
// 获取当前请求对象
ServletRequestAttributes attributes =
    (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
HttpServletRequest request = attributes.getRequest();
// 记录请求信息
ReqRspLog webLog = new ReqRspLog();
Object result = joinPoint.proceed();
Signature signature = joinPoint.getSignature();
MethodSignature methodSignature = (MethodSignature) signature;
Method method = methodSignature.getMethod();
// 通过反射,获取入参和出参,封装成json,落日志
long endTime = System.currentTimeMillis();
String urlStr = request.getRequestURL().toString();
webLog.setBasePath(StrUtil.removeSuffix(urlStr, URLUtil.url(urlStr).getPath()));
webLog.setIp(request.getRemoteUser());
webLog.setMethod(request.getMethod());
webLog.setParameter(getParameter(method, joinPoint.getArgs()));
webLog.setResult(result);
webLog.setSpendTime((int) (endTime - startTime));
webLog.setStartTime(startTime);
webLog.setUri(request.getRequestURI());
webLog.setUrl(request.getRequestURL().toString());
logger.info("{}", JSONUtil.parse(webLog));
return result;


创建测试接口:
@RestController
@RequestMapping("/api")
public class ApiController {
@GetMapping
public R<String> addLog(@RequestParam(value = "param1",required = false) String param1){
    return R.success("你好,这段话将被日志记录");
}


我们现在请求一下接口,会发现在控制台打印出这样一段日志:
{"method":"GET","uri":"/api","url":"http://localhost:8080/api","result":{"code":200,"data":"你好,这段话将被日志记录","message":"操作成功"},"basePath":"http://localhost:8080","parameter":{"param1":"测试ELK"},"startTime":1611529379353,"spendTime":9} 

使用切面,实现日志记录并打印到控制台上已经完成了,现在我们按照架构图,需要通过Logstash把日志发送到es里面,接下来整合Logstash实现传送日志的功能。

招兵买马:整合Logstash

添加Logstash依赖:
<!--集成Logstash-->
    <dependency>
        <groupId>net.logstash.logback</groupId>
        <artifactId>logstash-logback-encoder</artifactId>
        <version>5.3</version>
    </dependency>
    <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
        <optional>true</optional>
    </dependency>

编辑配置文件logback-spring.xml:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE configuration>
<configuration>
<include resource="org/springframework/boot/logging/logback/defaults.xml"/>
<include resource="org/springframework/boot/logging/logback/console-appender.xml"/>
<!--应用名称-->
<property name="APP_NAME" value="mall-admin"/>
<!--日志文件保存路径-->
<property name="LOG_FILE_PATH" value="${LOG_FILE:-${LOG_PATH:-${LOG_TEMP:-${java.io.tmpdir:-/tmp} } }/logs}"/>
<contextName>${APP_NAME}</contextName>
<!--每天记录日志到文件appender-->
<appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
    <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
        <fileNamePattern>${LOG_FILE_PATH}/${APP_NAME}-%d{yyyy-MM-dd}.log</fileNamePattern>
        <maxHistory>30</maxHistory>
    </rollingPolicy>
    <encoder>
        <pattern>${FILE_LOG_PATTERN}</pattern>
    </encoder>
</appender>
<!--输出到Logstash的appender-->
<appender name="LOGSTASH" class="net.logstash.logback.appender.LogstashTcpSocketAppender">
    <!--可以访问的Logstash日志收集端口-->
    <destination>127.0.0.1:4560</destination>
    <encoder charset="UTF-8" class="net.logstash.logback.encoder.LogstashEncoder"/>
</appender>
<root level="info">
    <appender-ref ref="CONSOLE"/>
    <appender-ref ref="FILE"/>
    <appender-ref ref="LOGSTASH"/>
</root>
</configuration>

编辑完之后,项目结构是这样的:

虽然在项目中已经集成了Logstash功能,但是Logstash还不知道把日志往哪里发,因为我们还没有城池。

既然没有,那就建造吧!

搭建城池:搭建ELK环境

ELK这里我使用dokcer-compose搭建,一个字:快!

首先我们约定一个根目录:/user/aimashi/docker

按要求执行如下命令:
mkdir -p /Users/yangle/docker
cd /Users/yangle/docker
mkdir elk_stanrd
cd elk_stanrd
mkdir logstash
cd logstash
vim logstash.conf

将以下文件内容复制到logstash.conf。
input {
tcp {
mode => "server"
host => "0.0.0.0"
port => 4560
codec => json_lines
}
}

output {
elasticsearch {
hosts => "es:9200"
index => "logstash-service-%{+YYYY.MM.dd}"
}


继续执行如下命令:
cd ../
vim docker-compose.yml

同样将以下内容复制到配置文件中。
version: '3'
services:
elasticsearch:
image: elasticsearch:6.4.0
container_name: elasticsearch
environment:
  - "cluster.name=elasticsearch" #设置集群名称为Elasticsearch
  - "discovery.type=single-node" #以单一节点模式启动
  - "ES_JAVA_OPTS=-Xms512m -Xmx512m" #设置使用JVM内存大小
volumes:
  - /Users/yangle/docker/elk_stanrd/elasticsearch/plugins:/usr/share/elasticsearch/plugins #插件文件挂载
  - /Users/yangle/docker/elk_stanrd/elasticsearch/data:/usr/share/elasticsearch/data #数据文件挂载
ports:
  - 9200:9200
  - 9300:9300
kibana:
image: kibana:6.4.0
container_name: kibana
links:
  - elasticsearch:es #可以用es这个域名访问Elasticsearch服务
depends_on:
  - elasticsearch #Kibana在Elasticsearch启动之后再启动
environment:
  - "elasticsearch.hosts=http://es:9200" #设置访问Elasticsearch的地址
ports:
  - 5601:5601
logstash:
image: logstash:6.4.0
container_name: logstash
volumes:
  - ~/Users/yangle/docker/elk_stanrd/logstash/logstash.conf:/usr/share/logstash/pipeline/logstash.conf #挂载Logstash的配置文件
depends_on:
  - elasticsearch #Kibana在Elasticsearch启动之后再启动
links:
  - elasticsearch:es #可以用es这个域名访问Elasticsearch服务
ports:
  - 4560:4560

到目前为止,搭建ELK环境的准备工作已经完成。

现在需要启动ELK,在/Users/yangle/docker/elk_stanrd目录下执行如下命令:
docker-compose up -d

执行之后出现如下提示,则代表初创建成功。

接下来,我们执行docker ps 来查看容器是否启动。

如果和图中一样,代表容器正常启动,但是还需等待一分钟左右,才能访问可视化平台。

访问地址:http://localhost:5601/

如果出现这个页面,则代表ELK已经搭建完成,现在,我们需要往里面塞点数据。

发起进攻:发送请求

ELK环境搭建完成之后,需要产生一点数据。该怎么做呢?

只要调用:http://localhost:8080/api?param1=测试ELK接口,多调用几次,就会产生一些测试数据。

除此之外,还需要做一些配置才能让es去收集这些日志,用户才能看到:


选择字段,创建索引:

成功创建索引之后的界面:


选择logstash-servicez之后,界面是这样的:

可以看到系统中的日志已经被收集上来了,试下搜索“你好”。

所有包含“你好”的日志都被筛选出来,当然这里还可以有很多检索条件,例如右上角有一个时间过滤检索,我就不一一演示了,大家有兴趣的话可以自己研究下。

仓库:https://gitee.com/yangleliu/learning.git
每个新技术的出现,都是为了解决某一类问题。

就像ELK的出现,就是为了减少日渐脱发的代码攻城狮们从海量日志中找数据的时间,节省出更多的精力放在业务处理上面。

有了ELK,我们只需要在输入框中,轻松输入关键字,敲下回车,需要的数据就会呈现在我们面前。

测试小姐姐等待的时间短了,心情好了,矛盾自然也就少了。

如此想来,如果能有一个平台,将女友的十万个情绪爆发的原因实时展现出来,那世界将是多么美好的明天!

原文链接:https://mp.weixin.qq.com/s/4lpM7DcpMq0e4lvhhL2yxg

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK