一、首先建立四個項目
1、服務端 項目名稱 ZipkinServer
pom文件如下
其中主要是zipkin的依賴
<?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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.zipkinServer</groupId>
<artifactId>ZipkinServer</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging>
<name>ZipkinServer</name>
<description>Demo project for Spring Boot</description>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.5.8.RELEASE</version>
<relativePath/>
</parent>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version>
<spring-cloud.version>Camden.SR6</spring-cloud.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.zipkin.java</groupId>
<artifactId>zipkin-server</artifactId>
</dependency>
<dependency>
<groupId>io.zipkin.java</groupId>
<artifactId>zipkin-autoconfigure-ui</artifactId>
</dependency>
<!--加上zipkin的依賴和zipkin-autoconfigure-storage-elasticsearch-http的依賴-->
<dependency>
<groupId>io.zipkin.java</groupId>
<artifactId>zipkin</artifactId>
<version>1.28.0</version>
</dependency>
<dependency>
<groupId>io.zipkin.java</groupId>
<artifactId>zipkin-autoconfigure-storage-elasticsearch-http</artifactId>
<version>1.28.0</version>
</dependency>
<!--ELK依賴-->
<dependency>
<groupId>net.logstash.logback</groupId>
<artifactId>logstash-logback-encoder</artifactId>
<version>4.9</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>
application.properties 文件如下
server.port=11008
spring.application.name=ZipkinServer
在啓動主方法類中加上註解 @EnableZipkinServer,聲明這是一個zipkin的服務端
package com.zipkinServer.ZipkinServer;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import zipkin.server.EnableZipkinServer;
@SpringBootApplication
@EnableZipkinServer
public class ZipkinServerApplication {
public static void main(String[] args) {
SpringApplication.run(ZipkinServerApplication.class, args);
}
}
2、客戶端A 項目名稱 ZipkinHello
pom文件如下, 同樣主要是zipkin的依賴
<?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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.ZipkinHello</groupId>
<artifactId>ZipkinHello</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging>
<name>ZipkinHello</name>
<description>Demo project for Spring Boot</description>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.5.8.RELEASE</version>
<relativePath/>
</parent>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version>
<spring-cloud.version>Camden.SR6</spring-cloud.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!--
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-sleuth</artifactId>
</dependency>
-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-zipkin</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<!--ELK依賴-->
<dependency>
<groupId>net.logstash.logback</groupId>
<artifactId>logstash-logback-encoder</artifactId>
<version>4.9</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>
application.properties文件如下
server.port=8989
spring.zipkin.base-url=http://localhost:11008
spring.application.name=ZipkinHello
集成日誌工具logback往ELK輸出所以logback.xml文件如下
<?xml version="1.0" encoding="UTF-8" ?>
<!-- 級別從高到低 OFF 、 FATAL 、 ERROR 、 WARN 、 INFO 、 DEBUG 、 TRACE 、 ALL -->
<!-- 日誌輸出規則 根據當前ROOT 級別,日誌輸出時,級別高於root默認的級別時 會輸出 -->
<!-- 以下 每個配置的 filter 是過濾掉輸出文件裏面,會出現高級別文件,依然出現低級別的日誌信息,通過filter 過濾只記錄本級別的日誌 -->
<!-- scan 當此屬性設置爲true時,配置文件如果發生改變,將會被重新加載,默認值爲true。 -->
<!-- scanPeriod 設置監測配置文件是否有修改的時間間隔,如果沒有給出時間單位,默認單位是毫秒。當scan爲true時,此屬性生效。默認的時間間隔爲1分鐘。 -->
<!-- debug 當此屬性設置爲true時,將打印出logback內部日誌信息,實時查看logback運行狀態。默認值爲false。 -->
<configuration scan="true" scanPeriod="60 seconds" debug="false">
<contextName>ZipkinHello</contextName>
<include resource="org/springframework/boot/logging/logback/defaults.xml"/>
<springProperty scope="context" name="springAppName" source="spring.application.name"/>
<!-- 日誌輸出格式 -->
<property name="CONSOLE_LOG_PATTERN" value="%d{yyyy-MM-dd HH:mm:ss.SSS}[%X{X-B3-TraceId:-},%X{X-B3-SpanId:-}] [%thread] %-5level %logger{50} - %msg%n"/>
<!-- 定義日誌文件 輸出位置 -->
<property name="log.home_dir" value="F:\\logs\\ZipkinHello"/>
<!-- 日誌最大的歷史 30天 -->
<property name="log.maxHistory" value="30"/>
<!-- 打印debug級別日誌及以上級別日誌 -->
<property name="log.level" value="debug"/>
<!-- ConsoleAppender 控制檯輸出日誌 start -->
<appender name="console" class="ch.qos.logback.core.ConsoleAppender">
<filter class="ch.qos.logback.classic.filter.ThresholdFilter">
<level>DEBUG</level>
</filter>
<encoder>
<pattern>
<pattern>${CONSOLE_LOG_PATTERN}</pattern>
<charset>utf8</charset>
</pattern>
</encoder>
</appender>
<!-- ConsoleAppender 控制檯輸出日誌 end -->
<!-- errorAppender 控制檯輸出日誌 start -->
<appender name="error" class="ch.qos.logback.core.rolling.RollingFileAppender">
<!-- 過濾器,只記錄WARN級別的日誌 -->
<!-- 果日誌級別等於配置級別,過濾器會根據onMath 和 onMismatch接收或拒絕日誌。 -->
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<!-- 設置過濾級別 -->
<level>ERROR</level>
<!-- 用於配置符合過濾條件的操作 -->
<onMatch>ACCEPT</onMatch>
<!-- 用於配置不符合過濾條件的操作 -->
<onMismatch>DENY</onMismatch>
</filter>
<!-- 最常用的滾動策略,它根據時間來制定滾動策略.既負責滾動也負責觸發滾動 -->
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<!--日誌輸出位置 可以是相對和絕對路徑 -->
<fileNamePattern>
${log.home_dir}/error/%d{yyyy-MM-dd}/errorLog-%i.log
</fileNamePattern>
<!-- 可選節點,控制保留的歸檔文件的最大數量,超出數量就刪除舊文件假設設置每個月滾動,且<maxHistory>是6, 則只保存最近6個月的文件,刪除之前的舊文件。注意,刪除舊文件是,那些爲了歸檔而創建的目錄也會被刪除 -->
<maxHistory>${log.maxHistory}</maxHistory>
<TimeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
<!-- 單個log文件超過該大小就會重新建一個log文件 -->
<MaxFileSize>2MB</MaxFileSize>
</TimeBasedFileNamingAndTriggeringPolicy>
</rollingPolicy>
<encoder>
<pattern>
<pattern>${CONSOLE_LOG_PATTERN}</pattern>
<charset>utf8</charset>
</pattern>
</encoder>
</appender>
<!-- errorAppender 控制檯輸出日誌 end -->
<!-- warnAppender 控制檯輸出日誌 start -->
<appender name="warn" class="ch.qos.logback.core.rolling.RollingFileAppender">
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>WARN</level>
<onMatch>ACCEPT</onMatch>
<onMismatch>DENY</onMismatch>
</filter>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>
${log.home_dir}/warn/%d{yyyy-MM-dd}/warnLog-%i.log
</fileNamePattern>
<maxHistory>${log.maxHistory}</maxHistory>
<TimeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
<MaxFileSize>2MB</MaxFileSize>
</TimeBasedFileNamingAndTriggeringPolicy>
</rollingPolicy>
<encoder>
<pattern>
<pattern>${CONSOLE_LOG_PATTERN}</pattern>
<charset>utf8</charset>
</pattern>
</encoder>
</appender>
<!-- warnAppender 控制檯輸出日誌 end -->
<!-- infoAppender 控制檯輸出日誌 start -->
<appender name="info" class="ch.qos.logback.core.rolling.RollingFileAppender">
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>INFO</level>
<onMatch>ACCEPT</onMatch>
<onMismatch>DENY</onMismatch>
</filter>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>${log.home_dir}/info/%d{yyyy-MM-dd}/infoLog-%i.log</fileNamePattern>
<maxHistory>${log.maxHistory}</maxHistory>
<TimeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
<MaxFileSize>2MB</MaxFileSize>
</TimeBasedFileNamingAndTriggeringPolicy>
</rollingPolicy>
<encoder>
<pattern>
<pattern>${CONSOLE_LOG_PATTERN}</pattern>
<charset>utf8</charset>
</pattern>
</encoder>
</appender>
<!-- infoAppender 控制檯輸出日誌 end -->
<!-- debugAppender 控制檯輸出日誌 start -->
<appender name="debug" class="ch.qos.logback.core.rolling.RollingFileAppender">
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>DEBUG</level>
<onMatch>ACCEPT</onMatch>
<onMismatch>DENY</onMismatch>
</filter>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>${log.home_dir}/debug/%d{yyyy-MM-dd}/debugLog-%i.log</fileNamePattern>
<maxHistory>${log.maxHistory}</maxHistory>
<TimeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
<MaxFileSize>2MB</MaxFileSize>
</TimeBasedFileNamingAndTriggeringPolicy>
</rollingPolicy>
<encoder>
<pattern>
<pattern>${CONSOLE_LOG_PATTERN}</pattern>
<charset>utf8</charset>
</pattern>
</encoder>
</appender>
<!-- debugAppender 控制檯輸出日誌 end -->
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<layout class="ch.qos.logback.classic.PatternLayout">
<Pattern>
%d{yyyy-MM-dd HH:mm:ss SSS} [%thread] %-5level %logger{36} - %msg%n
</Pattern>
</layout>
</appender>
<!--日誌發送到logstash=>elasticSearch=>kibana start-->
<appender name="LOGSTASH" class="net.logstash.logback.appender.LogstashTcpSocketAppender">
<destination>localhost:9601</destination>
<queueSize>1048576</queueSize>
<encoder charset="UTF-8" class="net.logstash.logback.encoder.LogstashEncoder" />
</appender>
<logger name="kibanaLog" level="DEBUG" additivity="false">
<appender-ref ref="LOGSTASH"/>
</logger>
<!--日誌發送到logstash=>elasticSearch=>kibana end -->
<root>
<level value="${log.level}"/>
<!-- 控制檯輸出 -->
<appender-ref ref="console"/>
<!-- 文件輸出 -->
<appender-ref ref="error"/>
<appender-ref ref="warn"/>
<appender-ref ref="info"/>
<appender-ref ref="debug"/>
</root>
<!-- 文件不輸出 -->
<Logger name="org.springframework" level="ERROR"></Logger>
<Logger name="org.hibernate" level="ERROR"></Logger>
<Logger name="org.apache" level="ERROR"></Logger>
<Logger name="com.netflix" level="ERROR"></Logger>
<Logger name="ch.qos.logback" level="ERROR"></Logger>
</configuration>
程序入口代碼
package com.zipkinServer.ZipkinServer;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@SpringBootApplication
@RestController
public class ZipkinHelloApplication {
public static void main(String[] args) {
SpringApplication.run(ZipkinHelloApplication.class, args);
}
private final static Logger logger = LoggerFactory.getLogger(ZipkinHelloApplication.class);
private final static Logger kibanaLogger = LoggerFactory.getLogger("kibanaLog");
@Autowired
private RestTemplate restTemplate;
@Bean
public RestTemplate getRestTemplate(){
return new RestTemplate();
}
@RequestMapping("/sayhello")
public String sayhello() {
logger.info("----sayhello----");
kibanaLogger.info("======kibana:sayhello======");
ResponseEntity<String> responseEntity = restTemplate.getForEntity("http://localhost:8999/helloToGoodBye?name={1}", String.class, "8989張三");
return responseEntity.getBody();
}
@RequestMapping("/goodBye")
public String goodBye(String name) {
logger.info("----goodBye----");
kibanaLogger.info("======kibana:goodBye======");
return "goodBye,"+name;
}
}
第一個sayHello是調用服務的發起者
第二個goodBye服務是被調用方
客戶端A ZipkinHello 完畢
3、客戶端B ZipkinUnicom 該服務作爲 A C 服務的中轉服務存在 具體設置與客戶端A類似主要取別如下
application.properties文件
server.port=8999
spring.zipkin.base-url=http://localhost:11008
spring.application.name=ZipkinUnicom
程序代碼
package com.zipkinServer.ZipkinServer;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@SpringBootApplication
@RestController
public class ZipkinUnicomApplication {
public static void main(String[] args) {
SpringApplication.run(ZipkinUnicomApplication.class, args);
}
private final static Logger logger = LoggerFactory.getLogger(ZipkinUnicomApplication.class);
private final static Logger kibanaLogger = LoggerFactory.getLogger("kibanaLog");
@Autowired
private RestTemplate restTemplate;
@Bean
public RestTemplate getRestTemplate(){
return new RestTemplate();
}
@RequestMapping("/helloToGoodBye")
public String helloToGoodBye(String name) {
logger.info("====helloToGoodBye====");
kibanaLogger.info("=========kibana:helloToGoodBye=========");
ResponseEntity<String> responseEntity = restTemplate.getForEntity("http://localhost:8988/hello?name={1}", String.class, name);
return responseEntity.getBody();
}
@RequestMapping("/goodByeToHello")
public String goodByeToHello(String name) {
logger.info("====goodByeToHello====");
kibanaLogger.info("=========kibana:goodByeToHello=========");
ResponseEntity<String> responseEntity = restTemplate.getForEntity("http://localhost:8989/goodBye?name={1}", String.class, name);
return responseEntity.getBody();
}
}
4、客戶端C ZipkinGoodBye
application.properties代碼如下
server.port=8988
spring.zipkin.base-url=http://localhost:11008
spring.application.name=ZipkinGoodBye
程序代碼如下
package com.zipkinServer.ZipkinServer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;
@SpringBootApplication
@RestController
public class ZipkinGoodByeApplication {
public static void main(String[] args) {
SpringApplication.run(ZipkinGoodByeApplication.class, args);
}
private final static Logger logger = LoggerFactory.getLogger(ZipkinGoodByeApplication.class);
private final static Logger kibanaLogger = LoggerFactory.getLogger("kibanaLog");
@Autowired
private RestTemplate restTemplate;
@Bean
public RestTemplate getRestTemplate(){
return new RestTemplate();
}
@RequestMapping("/sayGoodBye")
public String sayGoodBye() {
logger.info("----sayGoodBye----");
kibanaLogger.info("=========kibana:sayGoodBye=========");
ResponseEntity<String> responseEntity = restTemplate.getForEntity("http://localhost:8999/goodByeToHello?name={1}", String.class, "8988李四");
return responseEntity.getBody();
}
@RequestMapping("/hello")
public String sayHello2(String name) {
logger.info("----hello----");
kibanaLogger.info("=========kibana:hello=========");
return "hello,"+name;
}
}
二、啓動這四個服務
啓動順序爲 ZipkinServer -->ZipkinHello --> ZipkinUnicom --> ZipkinGoodBye 要按順序啓動
啓動後打開http://localhost:11008/可看到界面
三、訪問地址http://localhost:8988/sayGoodBye,http://localhost:8989/sayhello
可以看到返回信息界面
四、查看控制檯打印的日誌
三個客戶端服務分別輸出下列日誌
2018-11-09 17:45:53.953[3b823e4538d5bd90,3b823e4538d5bd90] [http-nio-8989-exec-4] INFO c.zipkinServer.ZipkinServer.ZipkinHelloApplication - ----sayhello----
2018-11-09 17:45:53.958[3b823e4538d5bd90,053423295201b4c4] [http-nio-8999-exec-4] INFO c.z.ZipkinServer.ZipkinUnicomApplication - ====helloToGoodBye====
2018-11-09 17:45:53.966[3b823e4538d5bd90,dce48c58b696242f] [http-nio-8988-exec-5] INFO c.z.ZipkinServer.ZipkinGoodByeApplication - ----hello----
因爲logback服務定義的輸出日誌格式是
<!-- 日誌輸出格式 -->
<property name="CONSOLE_LOG_PATTERN" value="%d{yyyy-MM-dd HH:mm:ss.SSS}[%X{X-B3-TraceId:-},%X{X-B3-SpanId:-}] [%thread] %-5level %logger{50} - %msg%n"/>
[%X{X-B3-TraceId:-},%X{X-B3-SpanId:-}] 的部分都是“3b823e4538d5bd90” 表明它是一次調用的一個過程
這樣就能通過日誌查看服務的調用情況了