文档章节

ApiBoot Logging使用SpringCloud Openfeign透传链路信息

恒宇少年
 恒宇少年
发布于 2019/11/06 14:09
字数 2305
阅读 13
收藏 0

ApiBoot Logging可以无缝整合SpringCloud来采集请求日志,目前支持RestTemplateOpenfeign两种方式,我们本章来讲解下在使用Openfeign完成服务之间请求相互调用的一条链路请求日志是否可以都采集到。

博客原文地址:http://blog.yuqiyu.com/apiboot-logging-using-openfeign-transparent-traceid.html

搭建Eureka Server

我们先来搭建一个Eureka Server,请访问【搭建服务注册中心Eureka Server】文章内容查看具体搭建流程。

搭建Logging Admin

我们需要搭建一个Logging Admin用于接收Logging Client上报的请求日志,请访问【ApiBoot Logging整合SpringCloud Eureka负载均衡上报日志】查看具体的搭建流程。

我们本章来模拟提交订单的业务逻辑,涉及到两个服务,分别是:商品服务订单服务,接下来我们需要来创建这两个服务。

本章源码采用Maven多模块的形式进行编写,请拉至文章末尾查看下载本章源码。

添加ApiBoot & SpringCloud统一版本

由于是采用Maven 多模块项目,存在继承关系,我们只需要在root模块添加版本依赖即可,其他子模块就可以直接使用,如下所示:

<properties>
  <java.version>1.8</java.version>
  <!--ApiBoot版本号-->
  <api.boot.version>2.1.5.RELEASE</api.boot.version>
  <!--SpringCloud版本号-->
  <spring.cloud.version>Greenwich.SR3</spring.cloud.version>
</properties>
<dependencyManagement>
  <dependencies>
    <dependency>
      <groupId>org.minbox.framework</groupId>
      <artifactId>api-boot-dependencies</artifactId>
      <version>${api.boot.version}</version>
      <type>pom</type>
      <scope>import</scope>
    </dependency>
    <dependency>
      <groupId>org.springframework.cloud</groupId>
      <artifactId>spring-cloud-dependencies</artifactId>
      <version>${spring.cloud.version}</version>
      <type>pom</type>
      <scope>import</scope>
    </dependency>
  </dependencies>
</dependencyManagement>

创建公共Openfeign接口定义

学习过Openfeign的同学应该都知道,Openfeign可以继承实现,我们只需要创建一个公共的服务接口定义,在实现该接口的服务进行业务实现,在调用该接口的地方直接注入即可。 下面我们创建一个名为common-openfeign的公共依赖项目,pom.xml添加依赖如下所示:

<dependencies>
  <!--SpringBoot Web-->
  <dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
    <optional>true</optional>
  </dependency>
  <!--Openfeign-->
  <dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-openfeign</artifactId>
    <optional>true</optional>
  </dependency>
</dependencies>

在提交订单时我们简单模拟需要获取商品的单价,所以在common-openfeign项目内我们要提供一个查询商品单价的服务接口,创建一个名为GoodClient的接口如下所示:

package org.minbox.chapter.common.openfeign;

import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;

/**
 * 商品服务接口定义
 *
 * @author 恒宇少年
 */
@FeignClient(name = "good-service")
@RequestMapping(value = "/good")
public interface GoodClient {
    /**
     * 获取商品价格
     *
     * @param goodId 商品编号
     * @return
     */
    @GetMapping(value = "/{goodId}")
    Double getGoodPrice(@PathVariable("goodId") Integer goodId);
}

注解解释:

  • @FeignClientSpringCloud Openfeign提供的接口客户端定义注解,通过value或者name来指定GoodClient访问的具体ServiceID,这里我们配置的value值为good-service项目spring.application.name配置参数(ServiceID = spring.application.name)。

这样当我们通过注入GoodClient接口调用getGoodPrice方法时,底层通过OpenfeignHttp代理访问good-service的对应接口。

创建商品服务

下面我们再来创建一个名为good-serviceSpringBoot项目。

添加相关依赖

pom.xml项目配置文件内添加如下依赖:

<dependencies>
  <!--ApiBoot Logging Client-->
  <dependency>
    <groupId>org.minbox.framework</groupId>
    <artifactId>api-boot-starter-logging</artifactId>
  </dependency>

  <!--SpringBoot Web-->
  <dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
  </dependency>

  <!--Eureka Client-->
  <dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
  </dependency>

  <!--公共Openfeign接口定义依赖-->
  <dependency>
    <groupId>org.minbox.chapter</groupId>
    <artifactId>common-openfeign</artifactId>
    <version>0.0.1-SNAPSHOT</version>
  </dependency>
</dependencies>

可以看到我们在good-service项目依赖内添加了我们在上面创建的common-openfeign依赖模块,因为GoodClient服务接口的实现是在good-service项目内,我们需要添加common-openfeign依赖后创建对应的XxxController并实现GoodClient接口完成对应的业务逻辑实现。

商品业务实现

这里我们简单做个示例,将价格固定返回,实现GoodClient的控制器如下所示:

package org.minbox.chapter.good.service;

import org.minbox.chapter.common.openfeign.GoodClient;
import org.springframework.web.bind.annotation.RestController;

/**
 * 商品服务接口实现
 *
 * @author 恒宇少年
 * @see GoodClient
 */
@RestController
public class GoodController implements GoodClient {
    @Override
    public Double getGoodPrice(Integer goodId) {
        if (goodId == 1) {
            return 15.6;
        }
        return 0D;
    }
}

注册到Eureka Server

我们需要将good-service注册到Eureka Server,修改application.yml配置文件如下所示:

# ServiceID
spring:
  application:
    name: good-service
# 端口号
server:
  port: 8082
# Eureka Config
eureka:
  client:
    service-url:
      defaultZone: http://127.0.0.1:10000/eureka/
  instance:
    prefer-ip-address: true

配置上报的Logging Admin

我们需要将good-service的请求日志上报到Logging Admin,采用SpringCloud ServiceID的方式配置,修改application.yml配置文件如下所示:

api:
  boot:
    logging:
      # 控制台打印日志
      show-console-log: true
      # 美化打印日志
      format-console-log-json: true
      # 配置Logging Admin 服务编号
      discovery:
        service-id: logging-admin

启用Eureka Client & Logging

最后我们在XxxApplication入口类添加注解来启用Eureka Client以及Logging Client,如下所示:

/**
 * 商品服务
 *
 * @author 恒宇少年
 */
@SpringBootApplication
@EnableLoggingClient
@EnableDiscoveryClient
public class GoodServiceApplication {
    /**
     * logger instance
     */
    static Logger logger = LoggerFactory.getLogger(GoodServiceApplication.class);

    public static void main(String[] args) {
        SpringApplication.run(GoodServiceApplication.class, args);
        logger.info("{}服务启动成功.", "商品");
    }
}

至此我们的商品服务已经准备完成.

创建订单服务

创建一个名为order-serviceSpringBoot项目(建议参考源码,本章采用Maven多模块创建)。

添加相关依赖

修改pom.xml添加相关依赖如下所示:

<dependencies>
  <!--ApiBoot Logging Client-->
  <dependency>
    <groupId>org.minbox.framework</groupId>
    <artifactId>api-boot-starter-logging</artifactId>
  </dependency>

  <!--SpringBoot Web-->
  <dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
  </dependency>

  <!--Eureka Client-->
  <dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
  </dependency>

  <!--Openfeign-->
  <dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-openfeign</artifactId>
  </dependency>

  <!--公共Openfeign接口定义依赖-->
  <dependency>
    <groupId>org.minbox.chapter</groupId>
    <artifactId>common-openfeign</artifactId>
    <version>0.0.1-SNAPSHOT</version>
  </dependency>
</dependencies>

订单业务实现

我们来模拟一个提交订单的场景,创建一个名为OrderController的控制器,如下所示:

/**
 * 订单控制器
 *
 * @author 恒宇少年
 */
@RestController
@RequestMapping(value = "/order")
public class OrderController {
    /**
     * 商品接口定义注入
     * {@link GoodClient}
     */
    @Autowired
    private GoodClient goodClient;

    @PostMapping
    public String submit(Integer goodId, Integer buyCount) {
        Double goodPrice = goodClient.getGoodPrice(goodId);
        Double orderAmount = goodPrice * buyCount;
        //...
        return "订单提交成功,订单总金额:" + orderAmount;
    }
}

注册到Eureka Server

将我们创建的order-service注册到Eureka Server,修改application.yml配置文件如下所示:

spring:
  application:
    name: order-service
server:
  port: 8081
# Eureka Config
eureka:
  client:
    service-url:
      defaultZone: http://127.0.0.1:10000/eureka/
  instance:
    prefer-ip-address: true

配置上报的Logging Admin

我们需要将order-service的请求日志上报到Logging Admin,采用SpringCloud ServiceID的方式配置,修改application.yml配置文件如下所示:

api:
  boot:
    logging:
      # 控制台打印日志
      show-console-log: true
      # 美化打印日志
      format-console-log-json: true
      # 配置Logging Admin 服务编号
      discovery:
        service-id: logging-admin

启用Eureka Client & Logging

修改order-service入口类OrderServiceApplication,添加启用Eureka ClientLogging Client的注解,如下所示:

/**
 * 订单服务
 *
 * @author 恒宇少年
 */
@SpringBootApplication
@EnableDiscoveryClient
@EnableLoggingClient
@EnableFeignClients(basePackages = "org.minbox.chapter.common.openfeign")
public class OrderServiceApplication {
    /**
     * logger instance
     */
    static Logger logger = LoggerFactory.getLogger(OrderServiceApplication.class);

    public static void main(String[] args) {
        SpringApplication.run(OrderServiceApplication.class, args);
        logger.info("{}服务启动成功.", "");
    }
}

注解解释:

  • @EnableFeignClients:该注解是Openfeign提供的启用自动扫描Client的配置,我们通过basePackages(基础包名)的方式进行配置扫描包下配置@FeignClient注解的接口,并为每个接口生成对应的代理实现并添加到Spring IOC容器。

    org.minbox.chapter.common.openfeign包名在common-openfeign项目内。

运行测试

依次启动项目,eureka-server > logging-admin > good-service > order-service

通过curl命令访问order-service内的提交订单地址:/order,如下所示:

➜ ~ curl -X POST http://localhost:8081/order\?goodId\=1\&buyCount\=3
订单提交成功,订单总金额:46.8

可以看到我们已经可以成功的获取订单的总金额,我们在/order请求方法内调用good-service获取商品的单价后计算得到订单总金额。

测试点:链路信息传递

我们通过控制台输出的日志信息来确认下链路信息(traceId、spanId)的透传是否正确。

收到order-service上报的日志

Receiving Service: 【order-service -> 127.0.0.1】, Request Log Report,Logging Content:[
	{
		"endTime":1573009439840,
		"httpStatus":200,
		"requestBody":"",
		"requestHeaders":{
			"host":"localhost:8081",
			"user-agent":"curl/7.64.1",
			"accept":"*/*"
		},
		"requestIp":"0:0:0:0:0:0:0:1",
		"requestMethod":"POST",
		"requestParam":"{\"buyCount\":\"3\",\"goodId\":\"1\"}",
		"requestUri":"/order",
		"responseBody":"订单提交成功,订单总金额:46.8",
		"responseHeaders":{},
		"serviceId":"order-service",
		"serviceIp":"127.0.0.1",
		"servicePort":"8081",
		"spanId":"241ef717-b0b3-4fcc-adae-b63ffd3dbbe4",
		"startTime":1573009439301,
		"timeConsuming":539,
		"traceId":"3e20cc72-c880-4575-90ed-d54a6b4fe555"
	}
]

收到good-service上报的日志

Receiving Service: 【good-service -> 127.0.0.1】, Request Log Report,Logging Content:[
	{
		"endTime":1573009439810,
		"httpStatus":200,
		"parentSpanId":"241ef717-b0b3-4fcc-adae-b63ffd3dbbe4",
		"requestBody":"",
		"requestHeaders":{
			"minbox-logging-x-parent-span-id":"241ef717-b0b3-4fcc-adae-b63ffd3dbbe4",
			"minbox-logging-x-trace-id":"3e20cc72-c880-4575-90ed-d54a6b4fe555",
			"host":"10.180.98.156:8082",
			"connection":"keep-alive",
			"accept":"*/*",
			"user-agent":"Java/1.8.0_211"
		},
		"requestIp":"10.180.98.156",
		"requestMethod":"GET",
		"requestParam":"{}",
		"requestUri":"/good/1",
		"responseBody":"15.6",
		"responseHeaders":{},
		"serviceId":"good-service",
		"serviceIp":"127.0.0.1",
		"servicePort":"8082",
		"spanId":"6339664e-097d-4a01-a734-935de52a7d44",
		"startTime":1573009439787,
		"timeConsuming":23,
		"traceId":"3e20cc72-c880-4575-90ed-d54a6b4fe555"
	}
]

结果分析:

  • 请求日志的入口为order-service所以并不存在parentSpanId(上级单元编号),而spanId(单元编号)、traceId(链路编号)也是新生成的。

  • 本次请求会经过good-service服务,因此parentSpanId则是order-service生成的spanIdtraceId同样也是order-service生成的,透传HttpHeader方式进行传递,表示在同一条请求链路上。

敲黑板,划重点

ApiBoot Logging支持使用Openfeign传递链路信息,内部通过Openfeign拦截器实现,源码详见:org.minbox.framework.logging.client.http.openfeign.LoggingOpenFeignInterceptor

traceId(链路编号)、parentSpanId(单元编号)通过HttpHeader的形式传递到目标访问服务,服务通过请求日志拦截器进行提取并设置链路绑定关系。

  • traceId传递时HttpHeader名称为:minbox-logging-x-trace-id.
  • parentSpanId传递时HttpHeader名称为:minbox-logging-x-parent-span-id

代码示例

如果您喜欢本篇文章请为源码仓库点个Star,谢谢!!! 本篇文章示例源码可以通过以下途径获取,目录为SpringBoot2.x/apiboot-logging-using-openfeign-transparent-traceid

作者个人 博客 使用开源框架 ApiBoot 助你成为Api接口服务架构师

© 著作权归作者所有

恒宇少年

恒宇少年

粉丝 19
博文 62
码字总数 89955
作品 4
济南
高级程序员
私信 提问
加载中

评论(0)

ApiBoot 2.1.3发布,支持 Logging Admin 界面管理

ApiBoot 为接口服务而生,基于 SpringBoot 完成扩展、自动化配置,通过封装一系列 Starter 来让调用者快速集成组件,降低学习、使用门槛,提高开发效率。 从 版本开始,内的全部会从模块从陆...

恒宇少年
2019/08/15
3.7K
0
ApiBoot 2.1.1.RELEASE版本发布,新增链路式日志分析

ApiBoot为接口服务而生,基于SpringBoot完成扩展、自动化配置,通过封装一系列Starter来让调用者快速集成组件,降低学习、使用门槛,提高开发效率。 ApiBoot 官网 官网地址:http://apiboot....

恒宇少年
2019/07/17
0
0
MinBox Logging 1.0.1.RELEASE 发布,分布式链路日志

是一款分布式、零侵入式的链路日志分析框架,支持 微服务架构下配置使用,内部封装了 、 两种方式透传链路信息。 零侵入式 无需使用注解配置采集链路日志,只需要添加 后简单配置 的相关 或 ...

恒宇少年
2019/09/17
1K
0
ApiBoot 2.1.1 发布,新增链路式请求日志分析框架

ApiBoot为接口服务而生,基于SpringBoot完成扩展、自动化配置,通过封装一系列Starter来让调用者快速集成组件,降低学习、使用门槛,提高开发效率。 ApiBoot 官网 官网地址:http://apiboot....

恒宇少年
2019/07/17
2.1K
2
分布式链路日志组件 minbox-logging 初版发布

MinBox Logging 是一款分布式、零侵入式的链路日志分析框架,支持 微服务架构下配置使用,内部封装了 、 两种方式透传链路信息。 零侵入式 无需使用注解配置采集链路日志,只需要添加 后简单...

恒宇少年
2019/09/05
1.9K
6

没有更多内容

加载失败,请刷新页面

加载更多

Minecraft Fabric Client 教程 #5 添加Event、Sprint和ToggleCommand

首发于Enaium的个人博客 添加Event 下载 放在cn.enaium.excel里 然后在Excel.java里面添加EventManager public enum Excel { [...] public EventManager eventManager; pu......

Enaium
15分钟前
25
0
记 S3Service 代码中的一个低级错误

osgl-storage 是 osgl 工具箱 中用于简化存储的. 其特点是接口简单, 支持多种存储引擎插件, 包括本地文件系统, AWS S3, Azure Blob, 七牛 Kodo 服务. 最近老码农在一次调试中偶然发现了 osgl...

开源老码农
17分钟前
392
1
如何实现Samba文件共享服务

目标:实现Samba文件共享服务 试验环境:两台主机服务端:192.168.56.11客户端:192.168.56.12 配置用户认证共享 服务端操作: 1.关闭防火墙,关闭selunix [root@hejie ~]# setenforce 0[...

linuxprobe2020
19分钟前
18
0
SQL Server Profiler - 如何过滤跟踪以仅显示来自一个数据库的事件?

如何将SQL Server Profiler跟踪限制为特定数据库? 我看不到如何过滤跟踪,看不到我连接的实例上的所有数据库的事件。 #1楼 在Trace properties> Events Selection选项卡下>选择show all co...

技术盛宴
19分钟前
25
0
Kafka配置及常用命令笔记

一、kafka配置 1. 服务端 server.properties #broker 的全局唯一编号,不能重复broker.id=0#删除 topic 功能使能delete.topic.enable=true#处理网络请求的线程数量num.network.thr...

liddblog
23分钟前
31
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部