Spring Cloud Sleuth + ELK示例

我与影子孤独终老i 提交于 2020-02-27 02:41:59

目录

Eureka服务端

Spring Cloud服务端

Spring Cloud客户端

Elasticsearch

Logstash

Kibana


Spring版本:5.1.8.RELEASE

Spring Boot版本:2.1.6.RELEASE

Spring Cloud版本:Greenwich.SR1

ELK版本:7.6.0

Eureka服务端

请参考Spring Cloud服务发现之Eureka中的Eureka Server

Spring Cloud服务端

请参考Spring Cloud服务发现之Eureka中的Test Server

Spring Cloud客户端

pom文件如下,添加了logback相关依赖以便使用其记录日志

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
	<modelVersion>4.0.0</modelVersion>
	<parent>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-parent</artifactId>
		<version>2.1.6.RELEASE</version>
		<relativePath/> <!-- lookup parent from repository -->
	</parent>
	<groupId>com.sean</groupId>
	<artifactId>trace-client</artifactId>
	<version>0.0.1-SNAPSHOT</version>
	<name>trace-client</name>
	<description>Demo project for Spring Boot</description>

	<properties>
		<java.version>1.8</java.version>
		<spring-cloud.version>Greenwich.SR1</spring-cloud.version>
	</properties>

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

		<dependency>
			<groupId>org.springframework.cloud</groupId>
			<artifactId>spring-cloud-starter-sleuth</artifactId>
		</dependency>

		<dependency>
			<groupId>net.logstash.logback</groupId>
			<artifactId>logstash-logback-encoder</artifactId>
			<version>6.3</version>
		</dependency>

		<dependency>
			<groupId>ch.qos.logback</groupId>
			<artifactId>logback-core</artifactId>
			<version>1.2.3</version>
		</dependency>

		<dependency>
			<groupId>ch.qos.logback</groupId>
			<artifactId>logback-classic</artifactId>
			<version>1.2.3</version>
		</dependency>

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

		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-web</artifactId>
		</dependency>

		<dependency>
			<groupId>commons-collections</groupId>
			<artifactId>commons-collections</artifactId>
			<version>3.2.2</version>
		</dependency>
	</dependencies>

	<dependencyManagement>
		<dependencies>
			<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>

	<build>
		<plugins>
			<plugin>
				<groupId>org.springframework.boot</groupId>
				<artifactId>spring-boot-maven-plugin</artifactId>
			</plugin>
		</plugins>
	</build>
</project>

 服务启动类

package com.sean;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class TraceClientApplication {
	public static void main(String[] args) {
		SpringApplication.run(TraceClientApplication.class, args);
	}
}

 Controller

package com.sean;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;

/**
 * Created by seanzou on 2019/7/3.
 */
@RestController
@RequestMapping(value = "/")
public class TestController {

    @Autowired
    private TestService testService;

    @RequestMapping(value = "/test" , method = RequestMethod.GET)
    public void test(){
        testService.test();
    }
}

Service

package com.sean;

import org.apache.commons.collections.CollectionUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.discovery.DiscoveryClient;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Component;
import org.springframework.web.client.RestTemplate;

import java.util.List;

/**
 * Created by seanzou on 2019/7/10.
 */
@Component
public class TestService {

    @Autowired
    private RestTemplate restTemplate;

    @Autowired
    private DiscoveryClient discoveryClient;

    public void test(){
        List<ServiceInstance> instances = discoveryClient.getInstances("test-service");
        if(CollectionUtils.isNotEmpty(instances)){
            ServiceInstance instance = instances.get(0);
            String host = instance.getHost();
            Integer port = instance.getPort();

            ResponseEntity responseEntity = restTemplate.getForEntity("http://" + host + ":" + port + "/name", String.class);
            if(responseEntity != null && responseEntity.getStatusCode() != null &&
                    responseEntity.getStatusCode().is2xxSuccessful()){
                String resp = (String)responseEntity.getBody();
                System.out.println(resp);
            }
        }
    }
}

 支持Http调用相关配置

package com.sean;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.client.ClientHttpRequestFactory;
import org.springframework.http.client.SimpleClientHttpRequestFactory;
import org.springframework.web.client.RestTemplate;

/**
 * Created by seanzou on 2019/9/10.
 */
@Configuration
public class RestTemplateConfig {

    @Bean
    public RestTemplate restTemplate(ClientHttpRequestFactory clientHttpRequestFactory){
        return new RestTemplate(clientHttpRequestFactory);
    }

    @Bean
    public ClientHttpRequestFactory clientHttpRequestFactory() {
        SimpleClientHttpRequestFactory factory = new SimpleClientHttpRequestFactory();
        factory.setReadTimeout(5000);//ms
        factory.setConnectTimeout(5000);//ms
        return factory;
    }
}

 Spring Cloud配置文件application.properties内容如下

server.port=8090
spring.application.name=trace-client

eureka.client.service-url.defaultZone=http://localhost:8000/eureka

# 是否注册至eureka,默认值为true,如果为true,需要配置eureka.client.service-url.defaultZone
# 否则会访问默认eureka地址:http://localhost:8761/eureka/
# 本服务仅供测试,不对外提供服务,因此不需要注册到eureka中
eureka.client.register-with-eureka=false

# 服务续租任务执行时间间隔
eureka.instance.lease-renewal-interval-in-seconds=10
# 服务过期时间
eureka.instance.lease-expiration-duration-in-seconds=20

logging.level.root=INFO
#使用该配置可以打出请求trace日志
logging.level.org.springframework.web.servlet.DispatcherServlet=DEBUG

 logback配置文件logback-spring.xml内容如下

总共生产三种类型的日志,分别是控制台日志,后端处理日志,已经需要使用logstash收集的日志

<?xml version="1.0" encoding="UTF-8"?>
<configuration>
    <include resource="org/springframework/boot/logging/logback/defaults.xml"/>

    <property scope="context" name="springAppName" value="trace-client"/>
    <property name="LOG_FILE" value="${BUILD_FOLDER:-build}/${springAppName}"/>
    <property name="CONSOLE_LOG_PATTERN"
              value="%d{yyyy-MM-dd HH:mm:ss.SSS} %level ${springAppName:-} %X{X-B3-TraceId:-} %X{X-B3-SpanId:-} %X{X-Span-Export:-} ${PID:-} %thread %class %message%n"/>

    <!-- Appender to log to console -->
    <appender name="console" class="ch.qos.logback.core.ConsoleAppender">
        <encoder>
            <pattern>${CONSOLE_LOG_PATTERN}</pattern>
            <charset>utf8</charset>
        </encoder>
    </appender>

    <!-- Appender to log to file -->
    <appender name="flatfile" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <file>${LOG_FILE}</file>
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <fileNamePattern>${LOG_FILE}.%d{yyyy-MM-dd}.gz</fileNamePattern>
            <maxHistory>7</maxHistory>
        </rollingPolicy>
        <encoder>
            <pattern>${CONSOLE_LOG_PATTERN}</pattern>
            <charset>utf8</charset>
        </encoder>
    </appender>

    <!-- Appender to log to file in a JSON format -->
    <appender name="logstash" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <file>${LOG_FILE}.json</file>
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <fileNamePattern>${LOG_FILE}.json.%d{yyyy-MM-dd}.gz</fileNamePattern>
            <maxHistory>7</maxHistory>
        </rollingPolicy>
        <encoder class="net.logstash.logback.encoder.LoggingEventCompositeJsonEncoder">
            <providers>
                <timestamp>
                    <timeZone>UTC</timeZone>
                </timestamp>
                <pattern>
                    <pattern>
                        {
                            "level": "%level",
                            "service": "${springAppName:-}",
                            "trace": "%X{X-B3-TraceId:-}",
                            "span": "%X{X-B3-SpanId:-}",
                            "exportable": "%X{X-Span-Export:-}",
                            "pid": "${PID:-}",
                            "thread": "%thread",
                            "class": "%class",
                            "content": "%message"
                        }
                    </pattern>
                </pattern>
            </providers>
        </encoder>
    </appender>

    <root level="INFO">
        <appender-ref ref="console"/>
        <appender-ref ref="logstash"/>
        <appender-ref ref="flatfile"/>
    </root>
</configuration>

当我们调用Spring Cloud客户端接口http://localhost:8090/test,日志中将会观察到如下trace日志

2020-02-26 14:56:37.377 DEBUG trace-client 962515422adbba84 962515422adbba84 false 15252 http-nio-8090-exec-8 org.springframework.core.log.LogFormatUtils GET "/test", parameters={}
2020-02-26 14:56:37.379 DEBUG trace-client 962515422adbba84 962515422adbba84 false 15252 http-nio-8090-exec-8 org.springframework.web.servlet.FrameworkServlet Completed 200 OK
2020-02-26 14:56:37.445 DEBUG trace-client 709a688616659d24 709a688616659d24 false 15252 http-nio-8090-exec-9 org.springframework.core.log.LogFormatUtils GET "/favicon.ico", parameters={}
2020-02-26 14:56:37.448 DEBUG trace-client 709a688616659d24 709a688616659d24 false 15252 http-nio-8090-exec-9 org.springframework.web.servlet.FrameworkServlet Completed 200 OK

Elasticsearch

在官网下载的免安装Win版本,解压后直接运行bin路径下的elasticsearch.bat即可

http://localhost:9200/可以正常访问说明ES启动成功

Logstash

编写Logstash配置文件(特别需要注意输入文件路径需要使用“/”,而不是“\”

input {
    file {
        codec => json
        path => "D:/workspace_localtest/trace-client/build/*.json"
    }
}
filter {
    grok {
        match => {
	  "message" => "%{TIMESTAMP_ISO8601:timestamp}\s+%{LOGLEVEL:level}\s+%{DATA:service}+%{DATA:trace}+%{DATA:span}+%{DATA:exportable}+%{DATA:pid}+%{DATA:thread}+%{DATA:class}+%{DATA:content}"	
        }
    }	
}
output {
    elasticsearch {
        hosts => ["http://localhost:9200"]
        index => "trace-test"
    }
}

使用该配置文件启动Logstash

D:\logstash-7.6.0\bin>logstash -f D:\logstash-7.6.0\config\logstash.conf

 启动后我们可以通过观察D:\logstash-7.6.0\data\plugins\inputs\file路径下sincedb文件中的内容来判断Logstash是否收集了文件信息

此时我们再访问ES,可以发现ES上已经成功创建了对应的索引,并且该索引下已经有数据存在

Kibana

修改Kibana配置文件config/kibana.yml中ES实例服务地址

然后使用bin路径下的kibana.bat启动Kibana服务即可,服务启动成功后会打印如下日志

[03:26:18.297] [info][server][Kibana][http] http server running at http://localhost:5601

访问http://localhost:5601/

创建自定义索引规则 

 会自动列出ES中的所有索引,这里我们选择Logstash中配置的trace-test

 

 然后选择数据中的时间字段

点击Create index pattern创建成功,之后我们就可以在Kibana中查询trace-test索引中的相关数据了

我们再次调用http://localhost:8090/test,客户端将打印新的trace日志,Kibana中也可以查询到最新的trace日志

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!