ApiBoot Logging uses RestTemplate to transparently transmit link information

Keywords: Programming Spring JSON xml Java

In the last article[ ApiBoot Logging uses spring cloud openfeign to transmit link information ]In this section, we explained in detail how to integrate spring cloud with ApiBoot Logging to transmit link information through Openfeign, including traceId (link number), parentSpanId (superior unit number) and other information. ApiBoot Logging can not only use Openfeign to transfer link information, but also support RestTemplate mode. This article will explain the specific use mode in detail.

Setting up Logging Admin

We need to set up the Logging Admin service to receive the request log information reported by the business service. Please refer to[ Report the logs collected by ApiBoot Logging to Admin ]Content of the article

Add ApiBoot unified version

Because this chapter uses Maven multi module method to build source code, we only need to configure the dependency of ApiBoot unified version in pom.xml of root project, as shown below:

<properties>
  <java.version>1.8</java.version>
  <!--ApiBoot Version number-->
  <api.boot.version>2.1.5.RELEASE</api.boot.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>
  </dependencies>
</dependencyManagement>

Next, we will create a simulation scenario of this article to query the user's account balance when querying the basic information of the user.

Create account service

Create a spring boot project called account service.

Add dependency

Add related dependencies in the project pom.xml configuration file as follows:

<dependencies>
  <!--SpringBoot Web-->
  <dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
  </dependency>
  <!--ApiBoot Logging-->
  <dependency>
    <groupId>org.minbox.framework</groupId>
    <artifactId>api-boot-starter-logging</artifactId>
  </dependency>
</dependencies>

Configuring Logging Admin for escalation

Add the Logging Admin address for request log reporting in the application.yml configuration file, as shown below:

spring:
  application:
    name: account-service
server:
  port: 9090

api:
  boot:
    logging:
      # Console print request log
      show-console-log: true
      # Beautify request log
      format-console-log-json: true
      # Logging Admin address
      admin:
        server-address: 127.0.0.1:8081

Note: the server address configuration parameter does not need to be prefixed with http: / /

Enable Logging Client

After adding the dependency, we use the @ EnableLoggingClient annotation to enable ApiBoot Logging. Add the following on the AccountServiceApplication class:

/**
 * Account service
 *
 * @author Heng Yu junior
 */
@SpringBootApplication
@EnableLoggingClient
public class AccountServiceApplication {
    /**
     * logger instance
     */
    static Logger logger = LoggerFactory.getLogger(AccountServiceApplication.class);

    public static void main(String[] args) {
        SpringApplication.run(AccountServiceApplication.class, args);
        logger.info("{}Service started successfully.", "account");
    }
}

@The EnableLoggingClient annotation instantiates some of the classes needed in ApiBoot Logging and places the instances in the Spring IOC container.

Query account balance code implementation

We create a controller named AccountController to query the balance information of the account. The code implementation is as follows:

/**
 * Account service implementation
 *
 * @author Heng Yu junior
 */
@RestController
@RequestMapping(value = "/account")
public class AccountController {

    /**
     * Example, memory account list
     */
    static final HashMap<Integer, Double> ACCOUNTS = new HashMap() {{
        put(1, 1233.22);
        put(2, 69269.22);
    }};

    /**
     * Get the balance of the specified account
     *
     * @param accountId
     * @return
     */
    @GetMapping(value = "/{accountId}")
    public Double getBalance(@PathVariable("accountId") Integer accountId) {
        return ACCOUNTS.get(accountId);
    }
}

Now that our account service has been written, let's write the user service.

Create user service

Let's create a spring boot project called user service.

Add dependency

Add related dependencies in the project pom.xml configuration file as follows:

<dependencies>
  <!--SpringBoot Web-->
  <dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
  </dependency>
  <!--ApiBoot Logging-->
  <dependency>
    <groupId>org.minbox.framework</groupId>
    <artifactId>api-boot-starter-logging</artifactId>
  </dependency>
</dependencies>

Configuring Logging Admin for escalation

In this chapter, we use the method of specifying the Logging Admin address to configure. Modify the application.yml configuration file as follows:

spring:
  application:
    name: user-service
server:
  port: 9091

api:
  boot:
    logging:
      # Console print request log
      show-console-log: true
      # Beautify request log
      format-console-log-json: true
      # Logging Admin address
      admin:
        server-address: 127.0.0.1:8081

Enable Logging Client

After adding the dependency, we need to add the @ EnableLoggingClient annotation on the XxxApplication entry class to enable ApiBoot Logging, as shown below:

/**
 * User service
 *
 * @author Heng Yu junior
 */
@SpringBootApplication
@EnableLoggingClient
public class UserServiceApplication {
    /**
     * logger instance
     */
    static Logger logger = LoggerFactory.getLogger(UserServiceApplication.class);

    public static void main(String[] args) {
        SpringApplication.run(UserServiceApplication.class, args);
        logger.info("{}Service started successfully.", "user");
    }
}

Instantiate RestTemplate object

In user service, you need to access the account service to get the balance of the current user. Therefore, we need to instantiate the RestTemplate in user service, so that we can access the user account balance information through the RestTemplate. We directly add an instance in the UserServiceApplication class, as shown below:

    /**
     * Instantiate RestTemplate
     *
     * @return {@link RestTemplate}
     */
    @Bean
    @ConditionalOnMissingBean
    public RestTemplate restTemplate() {
        return new RestTemplate();
    }

Note explanation:

  • @ConditionalOnMissingBean: This is an annotation of spring boot condition injection, indicating that the restTemplate() method will be executed to create an object when there is no instance of RestTemplate type in the IOC container.

Query user information code implementation

/**
 * User basic information controller
 *
 * @author Heng Yu junior
 */
@RestController
@RequestMapping(value = "/user")
public class UserController {
    /**
     * Example, user list
     */
    static final HashMap<Integer, User> USERS = new HashMap() {{
        put(1, new User(1, "Heng Yu junior"));
        put(2, new User(2, "Yu Qi Yu"));
    }};
    /**
     * Inject RestTemplate
     */
    @Autowired
    private RestTemplate restTemplate;

    /**
     * Get basic user information
     *
     * @param userId User number
     * @return
     */
    @GetMapping(value = "/{userId}")
    public User getUserInfo(@PathVariable("userId") Integer userId) {
        ResponseEntity<Double> responseEntity = restTemplate.getForEntity("http://localhost:9090/account/{accountId}", Double.class, userId);
        Double balance = responseEntity.getBody();
        User user = USERS.get(userId);
        if (ObjectUtils.isEmpty(user)) {
            throw new RuntimeException("User:" + userId + ",Non-existent.");
        }
        user.setBalance(balance);
        return user;
    }

    @Data
    public static class User {
        private Integer id;
        private String name;
        private Double balance;

        public User(Integer id, String name) {
            this.id = id;
            this.name = name;
        }
    }
}

The two services we need have been written. Let's test that RestTemplate can transparently transmit the link information of ApiBoot Logging?

Operation test

Start logging admin > User Service > account service.

Test point: transmission link information

We use the curl command to access the address / user provided by user service, as follows:

➜ ~ curl http://localhost:9091/user/1
{"id":1,"name":"Heng Yu junior","balance":1233.22}

Let me take a look at the request log received by the logging admin console.

Receive user service request log

Receiving Service: [user-service -> 127.0.0.1], Request Log Report,Logging Content: [
	{
		"endTime":1573032865311,
		"httpStatus":200,
		"requestBody":"",
		"requestHeaders":{
			"host":"localhost:9091",
			"user-agent":"curl/7.64.1",
			"accept":"*/*"
		},
		"requestIp":"0:0:0:0:0:0:0:1",
		"requestMethod":"GET",
		"requestParam":"{}",
		"requestUri":"/user/1",
		"responseBody":"{\"id\":1,\"name\":\"Heng Yu junior\",\"balance\":1233.22}",
		"responseHeaders":{},
		"serviceId":"user-service",
		"serviceIp":"127.0.0.1",
		"servicePort":"9091",
		"spanId":"f8cff018-42d5-481f-98df-c19b7196b3c3",
		"startTime":1573032865130,
		"timeConsuming":181,
		"traceId":"16ad1dd4-beaa-4110-b4b7-fc7d952d9a57"
	}
]

Receive account service request log

Receiving Service: [account-service -> 127.0.0.1], Request Log Report,Logging Content: [
	{
		"endTime":1573032865309,
		"httpStatus":200,
		"parentSpanId":"f8cff018-42d5-481f-98df-c19b7196b3c3",
		"requestBody":"",
		"requestHeaders":{
			"minbox-logging-x-parent-span-id":"f8cff018-42d5-481f-98df-c19b7196b3c3",
			"minbox-logging-x-trace-id":"16ad1dd4-beaa-4110-b4b7-fc7d952d9a57",
			"host":"localhost:9090",
			"connection":"keep-alive",
			"accept":"application/json, application/*+json",
			"user-agent":"Java/1.8.0_211"
		},
		"requestIp":"127.0.0.1",
		"requestMethod":"GET",
		"requestParam":"{}",
		"requestUri":"/account/1",
		"responseBody":"1233.22",
		"responseHeaders":{},
		"serviceId":"account-service",
		"serviceIp":"127.0.0.1",
		"servicePort":"9090",
		"spanId":"63b18b40-5718-431c-972f-78956ce78380",
		"startTime":1573032865307,
		"timeConsuming":2,
		"traceId":"16ad1dd4-beaa-4110-b4b7-fc7d952d9a57"
	}
]
  • When we access the / user path in the user service service, because it is the first time to access ApiBoot Logging, we will actively create traceId (link number) and spanId (unit number). Because there is no superior unit, the parentSpanId is null
  • When you view the request log reported by the account service service, you can see that the link information related to ApiBoot Logging is passed through the HttpHeader
    • Minbox logging x trace ID - > link number
    • Minbox logging x parent span ID - > superior unit no

Knock on the blackboard

ApiBoot Logging implements the interceptor configuration of RestTemplate in internal automation, so we only need to create an instance instead of actively configuring the interceptor information. For the specific source code, please visit org.minbox.framework.logging.client.http.rest.LoggingRestTemplateInterceptor.

No matter how many services you request span at a time, you can pass the link information generated by the request portal in turn, and the parent-child relationship is bound according to parentSpanId and spanId.

Code example

If you like this article, please point a Star for the source repository, thank you!!! The sample source code of this article can be obtained through the following ways. The directory is SpringBoot2.x/apiboot-logging-using-resttemplate-transparent-traceid:

Author individual Blog Using open source framework ApiBoot Help you become Api interface service architect

Posted by Tracer on Wed, 06 Nov 2019 02:53:09 -0800