Spring Cloud 集成分布式日志 ELK+Swagger 接口文档实战

一、分布式日志(ELK)

1.1 ELK 介绍

1.1.1 什么是 ELK?

ELK 是 Elasticsearch、Logstash、Kibana 的简称(也称为 ELK Stack),是 elastic 公司提供的一套完整的日志收集以及展示的解决方案,能够安全可靠地获取任何来源、任何格式的数据,然后实时地对数据进行搜索、分析和可视化。

  • Elasticsearch:开源的分布式全文检索服务器,用于存储和检索日志数据。
  • Logstash:具有实时传输能力的数据收集引擎,负责数据收集、过滤、解析,并将数据发送给 ES。
  • Kibana:数据分析与可视化平台,对 Elasticsearch 存储的数据进行可视化分析并展示。
1.1.2 为什么要用 ELK?

大型分布式系统中,日志管理面临诸多问题:

  1. 文本日志搜索速度慢;
  2. 分布式环境下日志分散,难以统一查询;
  3. 无法多维度灵活查询日志信息。ELK 恰好能解决以上痛点,实现日志的集中化、高效化管理。

1.2 安装 Logstash

1.2.1 下载

下载地址:https://artifacts.elastic.co/downloads/logstash/logstash-6.2.3.tar.gz

1.2.2 安装

解压即可完成安装:

sh

复制代码
tar -zxvf logstash-6.2.3.tar.gz -C /usr/java/logstash
1.2.3 修改配置

在 Logstash 主目录下创建 / 修改配置文件:

sh

复制代码
vim config/log_to_es.conf

配置文件内容:

nginx

复制代码
# 配置文件结构参考:https://www.elastic.co/guide/en/logstash/current/configuration-file-structure.html  
input {
  # log4j输入配置参考:https://www.elastic.co/guide/en/logstash/current/plugins-inputs-log4j.html  
  tcp {
    mode => "server"
    host => "192.168.204.137"
    port => 9250
  }
}
filter {
  ## 过滤、格式化数据(此处暂未配置)  
}
output {
  # elasticsearch输出配置参考:https://www.elastic.co/guide/en/logstash/current/plugins-outputs-elasticsearch.html
  elasticsearch {
    action => "index"          # 对ES执行的操作  
    hosts  => "192.168.204.134:9200"   # ES地址(可配置数组)  
    index  => "applog"         # 写入ES的索引名  
  }
}
1.2.4 启动

sh

复制代码
# 前台启动
./bin/logstash -f config/log_to_es.conf
# 后台守护进程启动
./bin/logstash -f config/log_to_es.conf &

启动成功后可查看对应日志确认状态。

1.3 Spring Cloud 集成 ELK(以 power_shop_item 模块为例)

1.3.1 引入依赖(pom.xml)

xml

复制代码
<dependency>
    <groupId>net.logstash.logback</groupId>
    <artifactId>logstash-logback-encoder</artifactId>
</dependency>
1.3.2 配置 logback.xml

添加 Logstash 输出的 Appender,并关联到根日志配置:

xml

复制代码
<!-- 为logstash输出的JSON格式的Appender -->
<appender name="logstash"
          class="net.logstash.logback.appender.LogstashTcpSocketAppender">
    <destination>192.168.233.136:9250</destination>
    <!-- 日志输出编码 -->
    <encoder class="net.logstash.logback.encoder.LoggingEventCompositeJsonEncoder">
        <providers>
            <pattern>
                <!-- 格式化输出:%d日期 %thread线程名 %-5level级别 %logger类名 %msg日志消息 -->
                <pattern>{"message":"%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg" }</pattern>
            </pattern>
        </providers>
    </encoder>
</appender>

<!-- 日志输出级别 -->
<root level="DEBUG">
    <appender-ref ref="Stdout" />   
    <appender-ref ref="RollingFile" />
    <appender-ref ref="logstash" />
</root> 
1.3.3 测试验证
  • 通过 ES head 插件可查看日志索引数据;
  • 打开 Kibana 可对收集的日志进行可视化分析。

二、Swagger 接口文档

2.1 Swagger 是什么?

Swagger 是实现了 OpenAPI 规范的工具,用于生成 RESTful 风格的 API 文档,并提供可视化的接口调试能力。

OpenAPI 规范(OAS)是 Linux 基金会的项目,定义了描述 API 的统一语言,规范 RESTful 服务开发流程,目前 V3.0 版本已开源。

2.2 为什么要使用 Swagger?

前后端分离架构下,API 接口是前后端唯一的交互纽带,手写 API 文档存在以下问题:

  • 文档格式不统一,维护成本高;
  • 文档更新不及时,易出现 "文档和代码不一致";
  • 缺乏可视化调试能力,接口测试效率低。Swagger 可一站式解决以上问题,实现 API 文档的自动生成、实时更新和在线调试。

2.3 Swagger 使用(以 power_shop_item 模块为例)

2.3.1 引入依赖(pom.xml)

xml

复制代码
<dependency>
    <groupId>io.springfox</groupId>
    <artifactId>springfox-swagger2</artifactId>
    <version>2.9.2</version>
</dependency>
<dependency>
    <groupId>io.springfox</groupId>
    <artifactId>springfox-swagger-ui</artifactId>
    <version>2.9.2</version>
</dependency>
2.3.2 配置 Swagger(Config 类)

java

复制代码
package com.powershop.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import springfox.documentation.builders.ApiInfoBuilder;
import springfox.documentation.builders.PathSelectors;
import springfox.documentation.builders.RequestHandlerSelectors;
import springfox.documentation.service.ApiInfo;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spring.web.plugins.Docket;
import springfox.documentation.swagger2.annotations.EnableSwagger2;

@Configuration
@EnableSwagger2//开启Swagger2
public class SwaggerConfig {
    @Bean
    public Docket api() {
        // Docket:核心配置类,用于生成接口文档
        return new Docket(DocumentationType.SWAGGER_2)
                .apiInfo(apiInfo())
                .select()
                // 指定生成文档的包路径(Controller层)
                .apis(RequestHandlerSelectors.basePackage("com.powershop.controller"))
                .paths(PathSelectors.any())
                .build();
    }

    // 配置文档基本信息
    private ApiInfo apiInfo() {
        return new ApiInfoBuilder()
                .title("动力优品后台管理系统")// 文档标题
                .description("商品管理模块接口文档")// 文档描述
                .version("1.0")// 版本号
                .build();
    }
}
2.3.3 注解修饰 POJO

java

复制代码
package com.powershop.pojo;

import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;

import java.util.Date;

@ApiModel("商品实体类")
public class TbItem {
    @ApiModelProperty(hidden = true)// 隐藏该字段
    private Long id;

    @ApiModelProperty(value="商品名称",required = true)// 描述字段,标记为必填
    private String title;

    @ApiModelProperty(value="卖点",required = true)
    private String sellPoint;

    @ApiModelProperty(value="价格",required = true)
    private Long price;

    @ApiModelProperty(value="库存",required = true)
    private Integer num;
    // 省略其他字段及get/set
}    
2.3.4 注解修饰 Controller

java

复制代码
package com.powershop.controller;

import com.bjpowernode.feign.ItemServiceFeign;
import com.bjpowernode.pojo.TbItem;
import com.bjpowernode.utils.PageResult;
import com.bjpowernode.utils.Result;
import io.swagger.annotations.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

@RestController
@RequestMapping("/backend/item")
@Api("商品管理接口")// 描述Controller作用
public class ItemController {
    @Autowired
    private ItemServiceFeign itemServiceFeignClient;

    /**
     * 查询商品基本信息
     */
    @RequestMapping(value="/selectItemInfo",method = RequestMethod.POST)
    @ApiOperation(value = "查询商品基本信息",notes = "根据itemId查询该商品的基本信息")// 描述接口
    @ApiImplicitParam(name="itemId",type = "Long",value = "商品id")// 描述单个参数
    public Result selectItemInfo(Long itemId) {
        TbItem tbItem = itemServiceFeignClient.selectItemInfo(itemId);
        if (tbItem != null) {
            return Result.ok(tbItem);
        }
        return Result.error("查无结果");
    }

    /**
     * 查询商品并分页处理
     */
    @GetMapping("/selectTbItemAllByPage")
    @ApiOperation(value = "查询商品并分页处理",notes = "分页查询商品信息,每页显示2条")
    @ApiImplicitParams({// 描述多个参数
        @ApiImplicitParam(name="page",type = "Integer",value = "页码",defaultValue = "1"),
        @ApiImplicitParam(name="rows",type = "Integer",value = "每页多少条",defaultValue = "2")
    })
    public Result selectTbItemAllByPage(@RequestParam(defaultValue = "1")
                  Integer page, @RequestParam(defaultValue = "2") Integer rows) {

        PageResult pageResult = itemServiceFeignClient.selectTbItemAllByPage(page, rows);
        if (pageResult != null && pageResult.getResult() != null &&
                pageResult.getResult().size() > 0) {
            return Result.ok(pageResult);
        }
        return Result.error("查无结果");
    }

    /**
     * 添加商品
     */
    @PostMapping("/insertTbItem")
    @ApiOperation(value = "添加商品",notes = "添加商品及描述和规格参数信息")
    @ApiImplicitParams({
            @ApiImplicitParam(name="desc",type = "String",value = "商品描述信息"),
            @ApiImplicitParam(name="itemParams",type = "String",value = "商品规格参数")
    })
    public Result insertTbItem(TbItem tbItem,String desc,String itemParams){
 		Integer insertTbItemNum = itemServiceFeignClient.insertTbItem(tbItem, desc, itemParams);
        if(insertTbItemNum==3){
            return Result.ok();
        }
        return Result.error("添加失败");
    }
}
2.3.5 常用注解说明
注解 作用
@Api 修饰整个类,描述 Controller 的作用
@ApiOperation 描述接口 / 方法的功能
@ApiImplicitParam 描述单个请求参数
@ApiImplicitParams 批量描述多个请求参数
@ApiModel 描述 POJO 实体类
@ApiModelProperty 描述 POJO 字段的含义 / 约束
@ApiResponse 描述单个 HTTP 响应
@ApiResponses 批量描述 HTTP 响应

2.4 访问 Swagger 接口文档

  1. 启动服务后,访问地址:http://localhost:8091/swagger-ui.html(端口根据项目配置调整);
  2. 页面中点击对应 Controller(如 item-controller),可查看所有接口列表;
  3. 点击具体接口,可查看接口详情(参数、请求方式、响应等)。

2.5 测试 Swagger 接口

  1. 点击接口旁的Try It Out按钮;
  2. 填写接口所需参数;
  3. 点击Execute发送请求;
  4. 页面下方会展示接口的响应结果(状态码、响应体等)。

总结

本文详细介绍了分布式日志解决方案 ELK 的部署、Spring Cloud 集成方式,以及 Swagger 接口文档的配置与使用。ELK 实现了分布式日志的集中收集与可视化分析,Swagger 则解决了前后端分离场景下 API 文档的维护与调试痛点,二者结合可大幅提升分布式系统的可观测性和开发协作效率。

相关推荐
钝挫力PROGRAMER1 小时前
BugFixed:etcd 单节点宕机后数据“消失”
分布式·etcd
属鼠哥1 小时前
HDFS 短路读取:mmap 与 Unix Domain Socket 铸就的零拷贝艺术
后端
好好风格1 小时前
Scrapling:现代 Web 抓取,正在从“写选择器”走向“自适应”
linux·后端
屋外雨大,惊蛰出没1 小时前
spring boot+mybatis开发基础复习
java·spring boot·后端
这个DBA有点耶1 小时前
死锁排查进阶:从日志到根因的完整分析链
java·开发语言·数据库·sql·运维开发·学习方法·dba
叫我少年1 小时前
C# 文件级 using(global using)
后端
郝学胜_神的一滴1 小时前
系统设计 014:缓存深度实战:如何用 Cache 优雅优化数据库读写?
前端·后端·面试
ai程序羊沸沸1 小时前
Spring Cloud 微服务入门:从组件清单到问题驱动的学习路径
后端·微服务
JAVA9651 小时前
JAVA面试-并发篇 06-ReentrantLock如何实现公平锁的以及可重入吗
java·开发语言·面试