Merge branch 'master' into 2.0.x

This commit is contained in:
Adrian Cole
2017-10-22 19:36:17 +03:00
27 changed files with 44 additions and 959 deletions

View File

@@ -41,19 +41,17 @@ a baggage element then it will be sent downstream either via HTTP or messaging t
* Provides simple metrics of accepted / dropped spans.
* If `spring-cloud-sleuth-zipkin` then the app will generate and collect Zipkin-compatible traces.
* If `spring-cloud-sleuth-zipkin2` then the app will generate and collect Zipkin-compatible traces.
By default it sends them via HTTP to a Zipkin server on localhost (port 9411).
Configure the location of the service using `spring.zipkin.baseUrl`.
- If you depend on `spring-rabbit` or `spring-kafka` your app will send traces to a broker instead of http.
- Note: `spring-cloud-sleuth-stream` is deprecated and should no longer be used.
* If `spring-cloud-sleuth-stream` then the app will generate and collect traces via https://github.com/spring-cloud/spring-cloud-stream[Spring Cloud Stream].
Your app automatically becomes a producer of tracer messages that are sent over your broker of choice
(e.g. RabbitMQ, Apache Kafka, Redis).
IMPORTANT: If using Zipkin or Stream, configure the percentage of spans exported using `spring.sleuth.sampler.percentage`
IMPORTANT: If using Zipkin, configure the percentage of spans exported using `spring.sleuth.sampler.percentage`
(default 0.1, i.e. 10%). *Otherwise you might think that Sleuth is not working cause it's omitting some spans.*
NOTE: the SLF4J MDC is always set and logback users will immediately see the trace and span ids in logs per the example
above. Other logging systems have to configure their own formatter to get the same result. The default is
`logging.pattern.level` set to `%5p [${spring.zipkin.service.name:${spring.application.name:-}},%X{X-B3-TraceId:-},%X{X-B3-SpanId:-},%X{X-Span-Export:-}]`
(this is a Spring Boot feature for logback users).
*This means that if you're not using SLF4J this pattern WILL NOT be automatically applied*.
*This means that if you're not using SLF4J this pattern WILL NOT be automatically applied*.

View File

@@ -280,7 +280,7 @@ the Spring BOM
==== Sleuth with Zipkin via HTTP
If you want both Sleuth and Zipkin just add the `spring-cloud-starter-zipkin` dependency.
If you want both Sleuth and Zipkin just add the `spring-cloud-starter-zipkin2` dependency.
[source,xml,indent=0,subs="verbatim,attributes",role="primary"]
.Maven
@@ -299,12 +299,12 @@ If you want both Sleuth and Zipkin just add the `spring-cloud-starter-zipkin` de
<dependency> <2>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-zipkin</artifactId>
<artifactId>spring-cloud-starter-zipkin2</artifactId>
</dependency>
----
<1> In order not to pick versions by yourself it's much better if you add the dependency management via
the Spring BOM
<2> Add the dependency to `spring-cloud-starter-zipkin`
<2> Add the dependency to `spring-cloud-starter-zipkin2`
[source,groovy,indent=0,subs="verbatim,attributes",role="secondary"]
.Gradle
@@ -316,16 +316,22 @@ dependencyManagement { <1>
}
dependencies { <2>
compile "org.springframework.cloud:spring-cloud-starter-zipkin"
compile "org.springframework.cloud:spring-cloud-starter-zipkin2"
}
----
<1> In order not to pick versions by yourself it's much better if you add the dependency management via
the Spring BOM
<2> Add the dependency to `spring-cloud-starter-zipkin`
<2> Add the dependency to `spring-cloud-starter-zipkin2`
==== Sleuth with Zipkin via Spring Cloud Stream
==== Sleuth with Zipkin via RabbitMQ or Kafka
If you want both Sleuth and Zipkin just add the `spring-cloud-sleuth-stream` dependency.
If you want to use RabbitMQ or Kafka instead of http, add the `spring-rabbit` or `spring-kafka`
dependencies. The default destination name is `zipkin`.
_Note: `spring-cloud-sleuth-stream` is deprecated and incompatible with these destinations_
If you want Sleuth over RabbitMQ add the `spring-cloud-sleuth-starter-zipkin2` and `spring-rabbit`
dependencies.
[source,xml,indent=0,subs="verbatim,attributes",role="primary"]
.Maven
@@ -344,23 +350,17 @@ If you want both Sleuth and Zipkin just add the `spring-cloud-sleuth-stream` dep
<dependency> <2>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-sleuth-stream</artifactId>
<artifactId>spring-cloud-sleuth-starter-zipkin2</artifactId>
</dependency>
<dependency> <3>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-sleuth</artifactId>
</dependency>
<!-- EXAMPLE FOR RABBIT BINDING -->
<dependency> <4>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-stream-binder-rabbit</artifactId>
<groupId>org.springframework.amqp</groupId>
<artifactId>spring-rabbit</artifactId>
</dependency>
----
<1> In order not to pick versions by yourself it's much better if you add the dependency management via
the Spring BOM
<2> Add the dependency to `spring-cloud-sleuth-stream`
<3> Add the dependency to `spring-cloud-starter-sleuth` - that way all dependant dependencies will be downloaded
<4> Add a binder (e.g. Rabbit binder) to tell Spring Cloud Stream what it should bind to
<2> Add the dependency to `spring-cloud-starter-sleuth-zipkin2` - that way all dependent dependencies will be downloaded
<3> To automatically configure rabbit, simply add the spring-rabbit dependency
[source,groovy,indent=0,subs="verbatim,attributes",role="secondary"]
.Gradle
@@ -372,86 +372,14 @@ dependencyManagement { <1>
}
dependencies {
compile "org.springframework.cloud:spring-cloud-sleuth-stream" <2>
compile "org.springframework.cloud:spring-cloud-starter-sleuth" <3>
// Example for Rabbit binding
compile "org.springframework.cloud:spring-cloud-stream-binder-rabbit" <4>
compile "org.springframework.cloud:spring-cloud-starter-sleuth-zipkin2" <2>
compile "org.springframework.amqp:spring-rabbit" <3>
}
----
<1> In order not to pick versions by yourself it's much better if you add the dependency management via
the Spring BOM
<2> Add the dependency to `spring-cloud-sleuth-stream`
<3> Add the dependency to `spring-cloud-starter-sleuth` - that way all dependant dependencies will be downloaded
<4> Add a binder (e.g. Rabbit binder) to tell Spring Cloud Stream what it should bind to
==== Spring Cloud Sleuth Stream Zipkin Collector
If you want to start a Spring Cloud Sleuth Stream Zipkin collector just add the `spring-cloud-sleuth-zipkin-stream`
dependency
[source,xml,indent=0,subs="verbatim,attributes",role="primary"]
.Maven
----
<dependencyManagement> <1>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${release.train.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependency> <2>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-sleuth-zipkin-stream</artifactId>
</dependency>
<dependency> <3>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-sleuth</artifactId>
</dependency>
<!-- EXAMPLE FOR RABBIT BINDING -->
<dependency> <4>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-stream-binder-rabbit</artifactId>
</dependency>
----
<1> In order not to pick versions by yourself it's much better if you add the dependency management via
the Spring BOM
<2> Add the dependency to `spring-cloud-sleuth-zipkin-stream`
<3> Add the dependency to `spring-cloud-starter-sleuth` - that way all dependant dependencies will be downloaded
<4> Add a binder (e.g. Rabbit binder) to tell Spring Cloud Stream what it should bind to
[source,groovy,indent=0,subs="verbatim,attributes",role="secondary"]
.Gradle
----
dependencyManagement { <1>
imports {
mavenBom "org.springframework.cloud:spring-cloud-dependencies:${releaseTrainVersion}"
}
}
dependencies {
compile "org.springframework.cloud:spring-cloud-sleuth-zipkin-stream" <2>
compile "org.springframework.cloud:spring-cloud-starter-sleuth" <3>
// Example for Rabbit binding
compile "org.springframework.cloud:spring-cloud-stream-binder-rabbit" <4>
}
----
<1> In order not to pick versions by yourself it's much better if you add the dependency management via
the Spring BOM
<2> Add the dependency to `spring-cloud-sleuth-zipkin-stream`
<3> Add the dependency to `spring-cloud-starter-sleuth` - that way all dependant dependencies will be downloaded
<4> Add a binder (e.g. Rabbit binder) to tell Spring Cloud Stream what it should bind to
and then just annotate your main class with `@EnableZipkinStreamServer` annotation:
[source,java]
----
include::https://raw.githubusercontent.com/spring-cloud/spring-cloud-sleuth/master/spring-cloud-sleuth-samples/spring-cloud-sleuth-sample-zipkin-stream/src/main/java/example/ZipkinStreamServerApplication.java[]
----
<2> Add the dependency to `spring-cloud-starter-sleuth-zipkin2` - that way all dependent dependencies will be downloaded
<3> To automatically configure rabbit, simply add the spring-rabbit dependency
== Additional resources
@@ -459,4 +387,4 @@ include::https://raw.githubusercontent.com/spring-cloud/spring-cloud-sleuth/mast
video::eQV71Mw1u1c[youtube]
https://www.youtube.com/watch?v=eQV71Mw1u1c[click here to see the video]
https://www.youtube.com/watch?v=eQV71Mw1u1c[click here to see the video]

View File

@@ -6,11 +6,7 @@ There are a few samples with slightly different features. You can run all of the
* `spring-cloud-sleuth-sample`: vanilla (no zipkin) web app that calls back to itself on various endpoints ("/", "/call", "/async")
* `spring-cloud-sleuth-sample-zipkin`: same as vanilla sample but with zipkin (set `sample.zipkin.enabled=true` if you have a collector running)
* `spring-cloud-sleuth-sample-stream`: same as vanilla sample, but exports span data to RabbitMQ using Spring Cloud Stream
* `spring-cloud-sleuth-sample-stream-zipkin`: a consumer for the span data on RabbitMQ that pushes it into a Zipkin span store, so it can be queried and visualized using the embedded Zipkin UI.
* `spring-cloud-sleuth-sample-zipkin2`: same as vanilla sample but with zipkin (set `sample.zipkin.enabled=true` if you have a collector running)
* `spring-cloud-sleuth-sample-messaging`: a Spring Integration application with two HTTP endpoints ("/" and "/xform")
@@ -20,7 +16,7 @@ The Ribbon sample makes an interesting demo or playground for learning about zip
=== Running samples with Zipkin
1. Optionally run the https://github.com/openzipkin/zipkin[Zipkin] Server, e.g. via docker compose (there's a `docker-compose.yml` in https://github.com/spring-cloud/spring-cloud-sleuth-samples/spring-cloud-sleuth-sample-zipkin[Spring Cloud Sleuth], or in https://github.com/openzipkin/docker-zipkin[Docker Zipkin]
1. Optionally run the https://github.com/openzipkin/zipkin[Zipkin] Server, e.g. via docker compose (there's a `docker-compose.yml` in https://github.com/spring-cloud/spring-cloud-sleuth-samples/spring-cloud-sleuth-sample-zipkin2[Spring Cloud Sleuth], or in https://github.com/openzipkin/docker-zipkin[Docker Zipkin]
7. Run the zipkin sample application (set `sample.zipkin.enabled=false` if you have no Zipkin running). If you are using a VM to run docker you might need to tunnel port 9411 to localhost, or change the `spring.zipkin.baseUrl`.
8. Hit `http://localhost:3380`, `http://localhost:3380/call`, `http://localhost:3380/async` for some interesting sample traces (the app callas back to itself).
9. Go to `http://localhost:9411` for Zipkin's UI (if you are using boot2docker the host will be different)
@@ -30,16 +26,3 @@ NOTE: You can see the zipkin spans without the UI (in logs) if you run the sampl
image::{github-raw}/docs/src/main/asciidoc/images/zipkin-trace-screenshot.png[Sample Zipkin Screenshot]
> The fact that the first trace in says "testSleuthMessaging" seems to be a bug in the UI (it has some annotations from that service, but it originates in the "testSleuthRibbon" service).
=== Running samples with Zipkin Stream
Instead of POSTing trace data directly to a Zipkin server, you can export them over https://raw.githubusercontent.com/spring-cloud/spring-cloud-stream[Spring Cloud Stream].
1. Run the RabbitMQ middleware for Zipkin (you can use `docker-compose.yml`).
2. Build the Zipkin Stream sample with Maven and run it.
7. Run the `spring-cloud-sleuth-sample-stream` app and interact with it in a browser, just like the vanilla sample. If you are using a VM to run docker you might need to tunnel port 5672 to localhost, or change the `spring.rabbbitmq.host`.
9. Go to `http://localhost:9411` for Zipkin's UI
The UI should look more or less like this:
image::{github-raw}/docs/src/main/asciidoc/images/zipkin-traces.png[Zipkin Web Screenshot]

View File

@@ -24,8 +24,6 @@
<module>spring-cloud-sleuth-sample-feign</module>
<module>spring-cloud-sleuth-sample-ribbon</module>
<module>spring-cloud-sleuth-sample-zipkin2</module>
<module>spring-cloud-sleuth-sample-stream</module>
<module>spring-cloud-sleuth-sample-zipkin-stream</module>
</modules>
<build>

View File

@@ -1,94 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
~ Copyright 2013-2017 the original author or authors.
~
~ Licensed under the Apache License, Version 2.0 (the "License");
~ you may not use this file except in compliance with the License.
~ You may obtain a copy of the License at
~
~ http://www.apache.org/licenses/LICENSE-2.0
~
~ Unless required by applicable law or agreed to in writing, software
~ distributed under the License is distributed on an "AS IS" BASIS,
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
~ See the License for the specific language governing permissions and
~ limitations under the License.
-->
<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>
<artifactId>spring-cloud-sleuth-sample-stream</artifactId>
<packaging>jar</packaging>
<name>spring-cloud-sleuth-sample-stream</name>
<description>Spring Cloud Sleuth Sample</description>
<parent>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-sleuth-samples</artifactId>
<version>2.0.0.BUILD-SNAPSHOT</version>
<relativePath>..</relativePath>
</parent>
<properties>
<sonar.skip>true</sonar.skip>
</properties>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<executions>
<execution>
<goals>
<goal>repackage</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<!--skip deploy -->
<artifactId>maven-deploy-plugin</artifactId>
<configuration>
<skip>true</skip>
</configuration>
</plugin>
</plugins>
</build>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-sleuth-stream</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.integration</groupId>
<artifactId>spring-integration-jmx</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-stream-binder-rabbit</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
</project>

View File

@@ -1,43 +0,0 @@
/*
* Copyright 2013-2015 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package sample;
import java.util.Random;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.sleuth.Tracer;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;
/**
* @author Spencer Gibb
*/
@Component
public class SampleBackground {
@Autowired
private Tracer tracer;
@Async
public void background() throws InterruptedException {
final Random random = new Random();
int millis = random.nextInt(1000);
Thread.sleep(millis);
this.tracer.addTag("background-sleep-millis", String.valueOf(millis));
}
}

View File

@@ -1,124 +0,0 @@
/*
* Copyright 2013-2015 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package sample;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.web.servlet.context.ServletWebServerInitializedEvent;
import org.springframework.cloud.sleuth.Span;
import org.springframework.cloud.sleuth.SpanAccessor;
import org.springframework.cloud.sleuth.Tracer;
import org.springframework.cloud.sleuth.sampler.AlwaysSampler;
import org.springframework.context.ApplicationListener;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;
import java.util.Random;
import java.util.concurrent.Callable;
/**
* @author Spencer Gibb
*/
@RestController
public class SampleController
implements ApplicationListener<ServletWebServerInitializedEvent> {
private static final Log log = LogFactory.getLog(SampleController.class);
@Autowired
private RestTemplate restTemplate;
@Autowired
private Tracer tracer;
@Autowired
private SpanAccessor accessor;
@Autowired
private SampleBackground controller;
final private Random random = new Random();
private int port;
@RequestMapping("/")
public String hi() throws InterruptedException {
Thread.sleep(this.random.nextInt(1000));
String s = this.restTemplate
.getForObject("http://localhost:" + this.port + "/hi2", String.class);
return "hi/" + s;
}
@RequestMapping("/call")
public Callable<String> call() {
return new Callable<String>() {
@Override
public String call() throws Exception {
int millis = SampleController.this.random.nextInt(1000);
Thread.sleep(millis);
SampleController.this.tracer.addTag("callable-sleep-millis",
String.valueOf(millis));
Span currentSpan = SampleController.this.accessor.getCurrentSpan();
return "async hi: " + currentSpan;
}
};
}
@RequestMapping("/async")
public String async() throws InterruptedException {
this.controller.background();
return "ho";
}
@RequestMapping("/hi2")
public String hi2() throws InterruptedException {
int millis = this.random.nextInt(1000);
Thread.sleep(millis);
this.tracer.addTag("random-sleep-millis", String.valueOf(millis));
return "hi2";
}
@RequestMapping("/traced")
public String traced() throws InterruptedException {
Span span = this.tracer.createSpan("http:customTraceEndpoint",
new AlwaysSampler());
int millis = this.random.nextInt(1000);
log.info(String.format("Sleeping for [%d] millis", millis));
Thread.sleep(millis);
this.tracer.addTag("random-sleep-millis", String.valueOf(millis));
String s = this.restTemplate
.getForObject("http://localhost:" + this.port + "/call", String.class);
this.tracer.close(span);
return "traced/" + s;
}
@RequestMapping("/start")
public String start() throws InterruptedException {
int millis = this.random.nextInt(1000);
log.info(String.format("Sleeping for [%d] millis", millis));
Thread.sleep(millis);
this.tracer.addTag("random-sleep-millis", String.valueOf(millis));
String s = this.restTemplate
.getForObject("http://localhost:" + this.port + "/call", String.class);
return "start/" + s;
}
@Override
public void onApplicationEvent(ServletWebServerInitializedEvent event) {
this.port = event.getSource().getPort();
}
}

View File

@@ -1,47 +0,0 @@
/*
* Copyright 2013-2015 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package sample;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.web.client.RestTemplate;
/**
* @author Spencer Gibb
*/
@SpringBootApplication
@EnableAsync
public class SampleSleuthApplication {
@Bean
public RestTemplate restTemplate() {
return new RestTemplate();
}
@Bean
public SampleController sampleController() {
return new SampleController();
}
public static void main(String[] args) {
SpringApplication.run(SampleSleuthApplication.class, args);
}
}

View File

@@ -1,9 +0,0 @@
server:
port: 3379
spring:
application:
name: testSleuthApp
sleuth:
sampler:
percentage: 1.0

View File

@@ -1,18 +0,0 @@
package sample;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.test.context.web.WebAppConfiguration;
@RunWith(SpringRunner.class)
@SpringBootTest(classes = SampleSleuthApplication.class)
@WebAppConfiguration
public class SampleSleuthApplicationTests {
@Test
public void contextLoads() {
}
}

View File

@@ -1,46 +0,0 @@
# Running a Zipkin Server
There are 3 parts to Zipkin:
- the instrumented client apps
- the backend database (defaults to in-memory db)
- the Zipkin server
## Zipkin Services
Run the Zipkin (remember to have RabbitMQ running) by
either running Spring Boot Maven plugin:
```
./mvnw spring-boot:run --projects spring-cloud-sleuth-samples/spring-cloud-sleuth-sample-zipkin-stream
```
or running the packaged app from the root:
```
./mvnw package --projects spring-cloud-sleuth-samples/spring-cloud-sleuth-sample-zipkin-stream
java -jar spring-cloud-sleuth-samples/spring-cloud-sleuth-sample-zipkin-stream/target/spring-cloud-sleuth-sample-zipkin-stream-1.0.0.BUILD-SNAPSHOT-exec.jar
```
and test it
```
$ curl localhost:9411/api/v1/services
["zipkin-server"]
```
## Instrumenting Apps
Depend on [Spring Cloud Sleuth Stream](https://github.com/spring-cloud-spring-cloud-sleuth) and the
rabbit binder (`spring-cloud-starter-stream-rabbit`).
Once the apps start publishing spans they will appear in the span store as well.
## Running in an IDE
You can run this app in an IDE and still use docker-compose to create the middleware:
```
$ docker-compose up rabbitmq
```

View File

@@ -1,7 +0,0 @@
rabbitmq:
image: rabbitmq:management
expose:
- 5672
ports:
- 5672:5672
- 15672:15672

View File

@@ -1,107 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
~ Copyright 2013-2017 the original author or authors.
~
~ Licensed under the Apache License, Version 2.0 (the "License");
~ you may not use this file except in compliance with the License.
~ You may obtain a copy of the License at
~
~ http://www.apache.org/licenses/LICENSE-2.0
~
~ Unless required by applicable law or agreed to in writing, software
~ distributed under the License is distributed on an "AS IS" BASIS,
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
~ See the License for the specific language governing permissions and
~ limitations under the License.
-->
<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>
<artifactId>spring-cloud-sleuth-sample-zipkin-stream</artifactId>
<packaging>jar</packaging>
<name>spring-cloud-sleuth-sample-zipkin-stream</name>
<description>Spring Boot Zipkin Server</description>
<parent>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-sleuth-samples</artifactId>
<version>2.0.0.BUILD-SNAPSHOT</version>
<relativePath>..</relativePath>
</parent>
<properties>
<docker.image.prefix>springio</docker.image.prefix>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<java.version>1.8</java.version>
<sonar.skip>true</sonar.skip>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-sleuth-zipkin-stream</artifactId>
</dependency>
<dependency>
<groupId>io.zipkin.java</groupId>
<artifactId>zipkin-autoconfigure-ui</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.integration</groupId>
<artifactId>spring-integration-jmx</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-stream-binder-rabbit</artifactId>
</dependency>
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-stream-test-support</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-sleuth-sample-test-core</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<classifier>exec</classifier>
</configuration>
</plugin>
</plugins>
</build>
</project>

View File

@@ -1,15 +0,0 @@
package example;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.sleuth.zipkin.stream.EnableZipkinStreamServer;
@SpringBootApplication
@EnableZipkinStreamServer
public class ZipkinStreamServerApplication {
public static void main(String[] args) throws Exception {
SpringApplication.run(ZipkinStreamServerApplication.class, args);
}
}

View File

@@ -1,25 +0,0 @@
server:
port: 9411
spring:
rabbitmq:
host: ${RABBIT_HOST:localhost}
datasource:
initialize: false
---
spring:
profiles: mysql
datasource:
schema: classpath:/mysql.sql
url: jdbc:mysql://${MYSQL_HOST:localhost}/test
username: root
password: root
# Switch this on to create the schema on startup:
initialize: true
continueOnError: true
sleuth:
enabled: false
zipkin:
storage:
type: mysql # default is mem (in-memory)

View File

@@ -1,106 +0,0 @@
package example;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mockito;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.context.SpringBootTest.WebEnvironment;
import org.springframework.cloud.sleuth.stream.SleuthSink;
import org.springframework.cloud.sleuth.zipkin.stream.ZipkinMessageListener;
import org.springframework.cloud.stream.annotation.EnableBinding;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.test.context.ActiveProfiles;
import org.springframework.test.context.junit4.SpringRunner;
import zipkin.collector.CollectorMetrics;
import zipkin.collector.CollectorSampler;
import zipkin.internal.V2StorageComponent;
import zipkin.server.ZipkinHttpCollector;
import zipkin.server.ZipkinQueryApiV1;
import zipkin.storage.StorageComponent;
import zipkin2.storage.InMemoryStorage;
import static org.junit.Assert.assertEquals;
@RunWith(SpringRunner.class)
@SpringBootTest(classes = ZipkinStreamTestsConfig.class,
webEnvironment = WebEnvironment.RANDOM_PORT, properties = {
"spring.datasource.initialize=true" })
@ActiveProfiles("test")
public class ZipkinServerApplicationTests {
@Autowired
private StorageComponent storage;
@Test
public void contextLoads() {
int count = this.storage.spanStore().getServiceNames().size();
assertEquals(0, count);
}
}
// TODO: Zipkin Server is not Boot 2.0 compatible
@Configuration
@SpringBootApplication
@EnableBoot2CompatibleZipkinServer
class ZipkinStreamTestsConfig {
}
//@EnableZipkinStreamServer
@EnableBinding(SleuthSink.class)
@Import({ZipkinMessageListener.class,
Boot2ZipkinCompatibleConfig.class,
ZipkinQueryApiV1.class,
ZipkinHttpCollector.class})
@interface EnableBoot2CompatibleZipkinServer {
}
// CollectorMetrics bean definition from `ZipkinServerConfiguration`
// is not Boot 2.0 compatible
@Configuration
class Boot2ZipkinCompatibleConfig {
@Bean CollectorMetrics collectorMetrics() {
CollectorMetrics mock = Mockito.mock(CollectorMetrics.class);
Mockito.when(mock.forTransport(Mockito.anyString())).thenReturn(mock);
return mock;
}
@Bean
@ConditionalOnMissingBean(CollectorSampler.class)
CollectorSampler traceIdSampler(@Value("${zipkin.collector.sample-rate:1.0}") float rate) {
return CollectorSampler.create(rate);
}
/**
* This is a special-case configuration if there's no StorageComponent of any kind. In-Mem can
* supply both read apis, so we add two beans here.
*/
@Configuration
// "matchIfMissing = true" ensures this is used when there's no configured storage type
@ConditionalOnProperty(name = "zipkin.storage.type", havingValue = "mem", matchIfMissing = true)
@ConditionalOnMissingBean(StorageComponent.class)
static class InMemoryConfiguration {
@Bean StorageComponent storage(
@Value("${zipkin.storage.strict-trace-id:true}") boolean strictTraceId,
@Value("${zipkin.storage.mem.max-spans:500000}") int maxSpans) {
return V2StorageComponent.create(InMemoryStorage.newBuilder()
.strictTraceId(strictTraceId)
.maxSpanCount(maxSpans)
.build());
}
@Bean InMemoryStorage v2Storage(V2StorageComponent component) {
return (InMemoryStorage) component.delegate();
}
}
}

View File

@@ -1,176 +0,0 @@
/*
* Copyright 2013-2015 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package integration;
import static java.util.concurrent.TimeUnit.SECONDS;
import java.util.Collections;
import java.util.Random;
import org.junit.Before;
import org.junit.Ignore;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mockito;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.cloud.sleuth.Span;
import org.springframework.cloud.sleuth.stream.Host;
import org.springframework.cloud.sleuth.stream.SleuthSink;
import org.springframework.cloud.sleuth.stream.Spans;
import org.springframework.cloud.sleuth.zipkin.stream.ZipkinMessageListener;
import org.springframework.cloud.stream.annotation.EnableBinding;
import org.springframework.cloud.stream.test.binder.TestSupportBinderAutoConfiguration;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.integration.support.MessageBuilder;
import org.springframework.messaging.Message;
import org.springframework.messaging.MessageChannel;
import org.springframework.test.context.ActiveProfiles;
import org.springframework.test.context.TestPropertySource;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import example.ZipkinStreamServerApplication;
import org.springframework.test.context.junit4.SpringRunner;
import tools.AbstractIntegrationTest;
import zipkin.collector.CollectorMetrics;
import zipkin.collector.CollectorSampler;
import zipkin.internal.V2StorageComponent;
import zipkin.server.ZipkinHttpCollector;
import zipkin.server.ZipkinQueryApiV1;
import zipkin.storage.StorageComponent;
import zipkin2.storage.InMemoryStorage;
@RunWith(SpringRunner.class)
// TODO: Without ZipkinStreamServerApplication.class cause Zipkin is not comp with Boot
@SpringBootTest(classes = { ZipkinStreamTestsConfig.class,
TestSupportBinderAutoConfiguration.class},
webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
@TestPropertySource(properties = { "server.port=0",
"management.health.rabbit.enabled=false" })
@ActiveProfiles("test")
public class ZipkinStreamTests extends AbstractIntegrationTest {
@Value("${local.server.port}")
private int zipkinServerPort = 9411;
long traceId = new Random().nextLong();
long spanId = new Random().nextLong();
@Autowired
@Qualifier(SleuthSink.INPUT)
private MessageChannel input;
@Before
public void setup() {
await().atMost(10, SECONDS)
.untilAsserted(() -> zipkinServerIsUp().run());
}
@Test
public void should_propagate_spans_to_zipkin() {
Span span = Span.builder().traceId(this.traceId).spanId(this.spanId).name("http:test").build();
span.tag(getRequiredBinaryAnnotationName(), "10131");
this.input.send(messageWithSpan(span));
await().atMost(5, SECONDS).untilAsserted(() ->
allSpansWereRegisteredInZipkinWithTraceIdEqualTo(this.traceId)
);
}
private Message<Spans> messageWithSpan(Span span) {
return MessageBuilder.withPayload(
new Spans(new Host(getAppName(), "127.0.0.1", 8080), Collections.singletonList(span)))
.build();
}
@Override
protected int getZipkinServerPort() {
return this.zipkinServerPort;
}
@Override
protected String getAppName() {
return "local";
}
}
// TODO: Zipkin Server is not Boot 2.0 compatible
@Configuration
@SpringBootApplication
@EnableBoot2CompatibleZipkinServer
class ZipkinStreamTestsConfig {
}
//@EnableZipkinStreamServer
@EnableBinding(SleuthSink.class)
@Import({ZipkinMessageListener.class,
Boot2ZipkinCompatibleConfig.class,
ZipkinQueryApiV1.class,
ZipkinHttpCollector.class})
@interface EnableBoot2CompatibleZipkinServer {
}
// CollectorMetrics bean definition from `ZipkinServerConfiguration`
// is not Boot 2.0 compatible
@Configuration
class Boot2ZipkinCompatibleConfig {
@Bean CollectorMetrics collectorMetrics() {
CollectorMetrics mock = Mockito.mock(CollectorMetrics.class);
Mockito.when(mock.forTransport(Mockito.anyString())).thenReturn(mock);
return mock;
}
@Bean
@ConditionalOnMissingBean(CollectorSampler.class)
CollectorSampler traceIdSampler(@Value("${zipkin.collector.sample-rate:1.0}") float rate) {
return CollectorSampler.create(rate);
}
/**
* This is a special-case configuration if there's no StorageComponent of any kind. In-Mem can
* supply both read apis, so we add two beans here.
*/
@Configuration
// "matchIfMissing = true" ensures this is used when there's no configured storage type
@ConditionalOnProperty(name = "zipkin.storage.type", havingValue = "mem", matchIfMissing = true)
@ConditionalOnMissingBean(StorageComponent.class)
static class InMemoryConfiguration {
@Bean StorageComponent storage(
@Value("${zipkin.storage.strict-trace-id:true}") boolean strictTraceId,
@Value("${zipkin.storage.mem.max-spans:500000}") int maxSpans) {
return V2StorageComponent.create(InMemoryStorage.newBuilder()
.strictTraceId(strictTraceId)
.maxSpanCount(maxSpans)
.build());
}
@Bean InMemoryStorage v2Storage(V2StorageComponent component) {
return (InMemoryStorage) component.delegate();
}
}
}

View File

@@ -1,5 +0,0 @@
zipkin:
storage:
type: mem # default is inMemory
spring.autoconfigure.exclude: org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration, org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration, org.springframework.boot.autoconfigure.security.SecurityAutoConfiguration

View File

@@ -1,5 +0,0 @@
drop table zipkin_spans;
drop table zipkin_annotations;
drop table zipkin_binary_annotations;
drop table zipkin_dependencies;
drop table zipkin_dependency_links;

View File

@@ -1,9 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<include resource="org/springframework/boot/logging/logback/base.xml"/>
<logger name="org.springframework.cloud.sleuth" level="DEBUG"/>
<root level="INFO">
<appender-ref ref="CONSOLE" />
<appender-ref ref="FILE" />
</root>
</configuration>

View File

@@ -24,7 +24,9 @@ import org.springframework.cloud.sleuth.Span;
*
* @author Dave Syer
* @since 1.0.0
* @deprecated Please use spring-cloud-sleuth-zipkin2 to report spans to Zipkin
*/
@Deprecated
public interface HostLocator {
Host locate(Span span);

View File

@@ -28,7 +28,9 @@ import org.springframework.messaging.SubscribableChannel;
* @since 1.0.0
*
* @see SleuthSource
* @deprecated Please use spring-cloud-sleuth-zipkin2 to report spans to Zipkin
*/
@Deprecated
public interface SleuthSink {
String INPUT = "sleuth";

View File

@@ -29,7 +29,9 @@ import org.springframework.messaging.MessageChannel;
* @since 1.0.0
*
* @see SleuthSink
* @deprecated Please use spring-cloud-sleuth-zipkin2 to report spans to Zipkin
*/
@Deprecated
public interface SleuthSource {
String OUTPUT = "sleuth";

View File

@@ -23,7 +23,9 @@ import zipkin.Endpoint;
*
* @author Dave Syer
* @since 1.0.0
* @deprecated Please use spring-cloud-sleuth-zipkin2 to report spans to Zipkin
*/
@Deprecated
public interface EndpointLocator {
Endpoint local();

View File

@@ -7,7 +7,9 @@ import java.net.URI;
*
* @author Marcin Grzejszczak
* @since 1.3.0
* @deprecated Please use spring-cloud-sleuth-zipkin2 to report spans to Zipkin
*/
@Deprecated
public interface ZipkinLoadBalancer {
/**

View File

@@ -28,7 +28,9 @@ import org.springframework.web.client.RestTemplate;
* @author Marcin Grzejszczak
*
* @since 1.1.0
* @deprecated Please use spring-cloud-sleuth-zipkin2 to report spans to Zipkin
*/
@Deprecated
public interface ZipkinRestTemplateCustomizer {
void customize(RestTemplate restTemplate);

View File

@@ -5,7 +5,9 @@ package org.springframework.cloud.sleuth.zipkin;
*
* @author Adrian Cole
* @since 1.0.0
* @deprecated Please use spring-cloud-sleuth-zipkin2 to report spans to Zipkin
*/
@Deprecated
public interface ZipkinSpanReporter {
/**
* Receives completed spans from {@link ZipkinSpanListener} and submits them to a Zipkin