Removed all Spring Cloud Sleuth code from the main branch

This commit is contained in:
Marcin Grzejszczak
2022-01-10 14:56:06 +01:00
parent c795675cf9
commit 86fce3e7de
1049 changed files with 2 additions and 114897 deletions

View File

@@ -1,45 +0,0 @@
# Contributing
Spring Cloud is released under the non-restrictive Apache 2.0 license,
and follows a very standard Github development process, using Github
tracker for issues and merging pull requests into master. If you want
to contribute even something trivial please do not hesitate, but
follow the guidelines below.
## Sign the Contributor License Agreement
Before we accept a non-trivial patch or pull request we will need you to sign the
[Contributor License Agreement](https://cla.pivotal.io/sign/spring).
Signing the contributor's agreement does not grant anyone commit rights to the main
repository, but it does mean that we can accept your contributions, and you will get an
author credit if we do. Active contributors might be asked to join the core team, and
given the ability to merge pull requests.
## Code of Conduct
This project adheres to the Contributor Covenant [code of
conduct](https://github.com/spring-cloud/spring-cloud-build/blob/main/docs/src/main/asciidoc/code-of-conduct.adoc). By participating, you are expected to uphold this code. Please report
unacceptable behavior to spring-code-of-conduct@pivotal.io.
## Code Conventions and Housekeeping
None of these is essential for a pull request, but they will all help. They can also be
added after the original pull request but before a merge.
* Use the Spring Framework code format conventions. If you use Eclipse
you can import formatter settings using the
`eclipse-code-formatter.xml` file from the
[Spring Cloud Build](https://raw.githubusercontent.com/spring-cloud/spring-cloud-build/main/spring-cloud-dependencies-parent/eclipse-code-formatter.xml) project. If using IntelliJ, you can use the
[Eclipse Code Formatter Plugin](https://plugins.jetbrains.com/plugin/6546) to import the same file.
* Make sure all new `.java` files to have a simple Javadoc class comment with at least an
`@author` tag identifying you, and preferably at least a paragraph on what the class is
for.
* Add the ASF license header comment to all new `.java` files (copy from existing files
in the project)
* Add yourself as an `@author` to the .java files that you modify substantially (more
than cosmetic changes).
* Add some Javadocs and, if you change the namespace, some XSD doc elements.
* A few unit tests would help a lot as well -- someone has to do it.
* If no-one else is using your branch, please rebase it against the current master (or
other target branch in the main project).
* When writing a commit message please follow [these conventions](https://tbaggery.com/2008/04/19/a-note-about-git-commit-messages.html),
if you are fixing an existing issue please add `Fixes gh-XXXX` at the end of the commit
message (where XXXX is the issue number).

View File

@@ -1,20 +0,0 @@
<!--
Thanks for raising a Spring Cloud issue. What sort of issue are you raising?
Question
Please ask questions about how to use something, or to understand why something isn't
working as you expect it to, on Stack Overflow using the spring-cloud tag.
Bug report
Please provide details of the problem, including the version of Spring Cloud that you
are using. If possible, please provide a test case or sample application that reproduces
the problem. This makes it much easier for us to diagnose the problem and to verify that
we have fixed it.
Enhancement
Please start by describing the problem that you are trying to solve. There may already
be a solution, or there may be a way to solve it that you hadn't considered.
-->

View File

@@ -1,17 +0,0 @@
---
name: Bug report
about: Create a report to help us improve
title: ''
labels: ''
assignees: ''
---
**Describe the bug**
Please provide details of the problem, including the version of Spring Cloud that you
are using.
**Sample**
If possible, please provide a test case or a minimal **Maven** sample written in **Java** that reproduces
the problem. This makes it much easier for us to diagnose the problem and to verify that
we have fixed it.

View File

@@ -1,20 +0,0 @@
---
name: Feature request
about: Suggest an idea for this project
title: ''
labels: ''
assignees: ''
---
**Is your feature request related to a problem? Please describe.**
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
**Describe the solution you'd like**
A clear and concise description of what you want to happen.
**Describe alternatives you've considered**
A clear and concise description of any alternative solutions or features you've considered.
**Additional context**
Add any other context or screenshots about the feature request here.

View File

@@ -1,32 +0,0 @@
name: Build
on:
push:
branches: [ main ]
pull_request:
branches: [ main ]
jobs:
build:
runs-on: ubuntu-latest
strategy:
matrix:
java: ["8", "11", "17"]
steps:
- uses: actions/checkout@v2
- name: Setup java
uses: actions/setup-java@v2
with:
distribution: 'zulu'
java-version: ${{ matrix.java }}
- name: Cache local Maven repository
uses: actions/cache@v2
with:
path: ~/.m2/repository
key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }}
restore-keys: |
${{ runner.os }}-maven-
- name: Build with Maven
run: ./mvnw clean install -B -U -Dhttp.keepAlive=false -Dmaven.wagon.http.pool=false

View File

@@ -1 +0,0 @@
-Xmx1024m -XX:CICompilerCount=1 -XX:TieredStopAtLevel=1 -Djava.security.egd=file:/dev/./urandom

View File

@@ -1 +0,0 @@
-P spring

Binary file not shown.

View File

@@ -1,16 +0,0 @@
#
# Copyright 2013-2018 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
#
# https://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.
#
distributionUrl=https://repo1.maven.org/maven2/org/apache/maven/apache-maven/3.5.0/apache-maven-3.5.0-bin.zip

View File

@@ -1,93 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
~ Copyright 2013-2018 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
~
~ https://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.
-->
<settings>
<servers>
<server>
<id>repo.spring.io</id>
<username>${env.CI_DEPLOY_USERNAME}</username>
<password>${env.CI_DEPLOY_PASSWORD}</password>
</server>
</servers>
<profiles>
<profile>
<!--
N.B. this profile is only here to support users and IDEs that do not use Maven 3.3.
It isn't needed on the command line if you use the wrapper script (mvnw) or if you use
a native Maven with the right version. Eclipse users should points their Maven tooling to
this settings file, or copy the profile into their ~/.m2/settings.xml.
-->
<id>spring</id>
<activation>
<activeByDefault>true</activeByDefault>
</activation>
<repositories>
<repository>
<id>spring-snapshots</id>
<name>Spring Snapshots</name>
<url>https://repo.spring.io/snapshot</url>
<snapshots>
<enabled>true</enabled>
</snapshots>
</repository>
<repository>
<id>spring-milestones</id>
<name>Spring Milestones</name>
<url>https://repo.spring.io/milestone</url>
<snapshots>
<enabled>false</enabled>
</snapshots>
</repository>
<repository>
<id>spring-releases</id>
<name>Spring Releases</name>
<url>https://repo.spring.io/release</url>
<snapshots>
<enabled>false</enabled>
</snapshots>
</repository>
</repositories>
<pluginRepositories>
<pluginRepository>
<id>spring-snapshots</id>
<name>Spring Snapshots</name>
<url>https://repo.spring.io/snapshot</url>
<snapshots>
<enabled>true</enabled>
</snapshots>
</pluginRepository>
<pluginRepository>
<id>spring-milestones</id>
<name>Spring Milestones</name>
<url>https://repo.spring.io/milestone</url>
<snapshots>
<enabled>false</enabled>
</snapshots>
</pluginRepository>
</pluginRepositories>
</profile>
<profile>
<!--
Turns on jdk8 for tests
-->
<id>ide</id>
<activation>
<activeByDefault>true</activeByDefault>
</activation>
</profile>
</profiles>
</settings>

View File

@@ -1 +0,0 @@

View File

@@ -1,400 +1,5 @@
////
DO NOT EDIT THIS FILE. IT WAS GENERATED.
Manual changes to this file will be lost when it is generated again.
Edit the files in the src/main/asciidoc/ directory instead.
////
:jdkversion: 1.8
image::https://github.com/spring-cloud/spring-cloud-sleuth/workflows/Build/badge.svg?style=svg["Build",link="https://github.com/spring-cloud/spring-cloud-sleuth/actions"]
image::https://badges.gitter.im/spring-cloud/spring-cloud-sleuth.svg[Gitter,link="https://gitter.im/spring-cloud/spring-cloud-sleuth?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge"]
== Spring Cloud Sleuth
Spring Cloud Sleuth provides Spring Boot auto-configuration for distributed tracing.
Sleuth configures everything you need to get started.
This includes where trace data (spans) are reported to, how many traces to keep (sampling), if remote fields (baggage) are sent, and which libraries are traced.
=== Quick Start
Add Spring Cloud Sleuth to the classpath of a Spring Boot application (together with a Tracer implementation) and you will see trace IDs in logs.
Example of Sleuth with Brave tracer:
[source,xml,indent=0,subs="verbatim,quotes,attributes"]
----
<!-- Spring Cloud Sleuth requires a Spring Cloud BOM -->
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<!-- Provide the latest stable Spring Cloud release train version (e.g. 2020.0.0) -->
<version>${release.train.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<!-- Boot's Web support -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- Sleuth with Brave tracer implementation -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-sleuth</artifactId>
</dependency>
</dependencies>
----
Consider the following HTTP handler:
[source,java,indent=0]
----
@RestController
public class DemoController {
private static Logger log = LoggerFactory.getLogger(DemoController.class);
@RequestMapping("/")
public String home() {
log.info("Handling home");
return "Hello World";
}
}
----
If you add that handler to a controller, you can see the calls to `home()`
being traced in the logs (notice the `0b6aaf642574edd3` ids).
[indent=0]
----
2020-10-21 12:01:16.285 INFO [,0b6aaf642574edd3,0b6aaf642574edd3,true] 289589 --- [nio-9000-exec-1] DemoController : Handling home!
----
NOTE: Instead of logging the request in the handler explicitly, you could set `logging.level.org.springframework.web.servlet.DispatcherServlet=DEBUG`.
NOTE: Set `spring.application.name=myService` (for instance) to see the service name as well as the trace and span IDs.
== Documentation
Please visit the https://docs.spring.io/spring-cloud-sleuth/docs/[documentation page] to read more about the project.
== Building
:jdkversion: 1.8
=== Basic Compile and Test
To build the source you will need to install JDK {jdkversion}.
Spring Cloud uses Maven for most build-related activities, and you
should be able to get off the ground quite quickly by cloning the
project you are interested in and typing
----
$ ./mvnw install
----
NOTE: You can also install Maven (>=3.3.3) yourself and run the `mvn` command
in place of `./mvnw` in the examples below. If you do that you also
might need to add `-P spring` if your local Maven settings do not
contain repository declarations for spring pre-release artifacts.
NOTE: Be aware that you might need to increase the amount of memory
available to Maven by setting a `MAVEN_OPTS` environment variable with
a value like `-Xmx512m -XX:MaxPermSize=128m`. We try to cover this in
the `.mvn` configuration, so if you find you have to do it to make a
build succeed, please raise a ticket to get the settings added to
source control.
The projects that require middleware (i.e. Redis) for testing generally
require that a local instance of [Docker](https://www.docker.com/get-started) is installed and running.
=== Documentation
The spring-cloud-build module has a "docs" profile, and if you switch
that on it will try to build asciidoc sources from
`src/main/asciidoc`. As part of that process it will look for a
`README.adoc` and process it by loading all the includes, but not
parsing or rendering it, just copying it to `${main.basedir}`
(defaults to `${basedir}`, i.e. the root of the project). If there are
any changes in the README it will then show up after a Maven build as
a modified file in the correct place. Just commit it and push the change.
=== Working with the code
If you don't have an IDE preference we would recommend that you use
https://www.springsource.com/developer/sts[Spring Tools Suite] or
https://eclipse.org[Eclipse] when working with the code. We use the
https://eclipse.org/m2e/[m2eclipse] eclipse plugin for maven support. Other IDEs and tools
should also work without issue as long as they use Maven 3.3.3 or better.
==== Activate the Spring Maven profile
Spring Cloud projects require the 'spring' Maven profile to be activated to resolve
the spring milestone and snapshot repositories. Use your preferred IDE to set this
profile to be active, or you may experience build errors.
==== Importing into eclipse with m2eclipse
We recommend the https://eclipse.org/m2e/[m2eclipse] eclipse plugin when working with
eclipse. If you don't already have m2eclipse installed it is available from the "eclipse
marketplace".
NOTE: Older versions of m2e do not support Maven 3.3, so once the
projects are imported into Eclipse you will also need to tell
m2eclipse to use the right profile for the projects. If you
see many different errors related to the POMs in the projects, check
that you have an up to date installation. If you can't upgrade m2e,
add the "spring" profile to your `settings.xml`. Alternatively you can
copy the repository settings from the "spring" profile of the parent
pom into your `settings.xml`.
==== Importing into eclipse without m2eclipse
If you prefer not to use m2eclipse you can generate eclipse project metadata using the
following command:
[indent=0]
----
$ ./mvnw eclipse:eclipse
----
The generated eclipse projects can be imported by selecting `import existing projects`
from the `file` menu.
== Contributing
:spring-cloud-build-branch: master
Spring Cloud is released under the non-restrictive Apache 2.0 license,
and follows a very standard Github development process, using Github
tracker for issues and merging pull requests into master. If you want
to contribute even something trivial please do not hesitate, but
follow the guidelines below.
=== Sign the Contributor License Agreement
Before we accept a non-trivial patch or pull request we will need you to sign the
https://cla.pivotal.io/sign/spring[Contributor License Agreement].
Signing the contributor's agreement does not grant anyone commit rights to the main
repository, but it does mean that we can accept your contributions, and you will get an
author credit if we do. Active contributors might be asked to join the core team, and
given the ability to merge pull requests.
=== Code of Conduct
This project adheres to the Contributor Covenant https://github.com/spring-cloud/spring-cloud-build/blob/master/docs/src/main/asciidoc/code-of-conduct.adoc[code of
conduct]. By participating, you are expected to uphold this code. Please report
unacceptable behavior to spring-code-of-conduct@pivotal.io.
=== Code Conventions and Housekeeping
None of these is essential for a pull request, but they will all help. They can also be
added after the original pull request but before a merge.
* Use the Spring Framework code format conventions. If you use Eclipse
you can import formatter settings using the
`eclipse-code-formatter.xml` file from the
https://raw.githubusercontent.com/spring-cloud/spring-cloud-build/master/spring-cloud-dependencies-parent/eclipse-code-formatter.xml[Spring
Cloud Build] project. If using IntelliJ, you can use the
https://plugins.jetbrains.com/plugin/6546[Eclipse Code Formatter
Plugin] to import the same file.
* Make sure all new `.java` files to have a simple Javadoc class comment with at least an
`@author` tag identifying you, and preferably at least a paragraph on what the class is
for.
* Add the ASF license header comment to all new `.java` files (copy from existing files
in the project)
* Add yourself as an `@author` to the .java files that you modify substantially (more
than cosmetic changes).
* Add some Javadocs and, if you change the namespace, some XSD doc elements.
* A few unit tests would help a lot as well -- someone has to do it.
* If no-one else is using your branch, please rebase it against the current master (or
other target branch in the main project).
* When writing a commit message please follow https://tbaggery.com/2008/04/19/a-note-about-git-commit-messages.html[these conventions],
if you are fixing an existing issue please add `Fixes gh-XXXX` at the end of the commit
message (where XXXX is the issue number).
=== Checkstyle
Spring Cloud Build comes with a set of checkstyle rules. You can find them in the `spring-cloud-build-tools` module. The most notable files under the module are:
.spring-cloud-build-tools/
----
└── src
   ├── checkstyle
   │   └── checkstyle-suppressions.xml <3>
   └── main
   └── resources
   ├── checkstyle-header.txt <2>
   └── checkstyle.xml <1>
----
<1> Default Checkstyle rules
<2> File header setup
<3> Default suppression rules
==== Checkstyle configuration
Checkstyle rules are *disabled by default*. To add checkstyle to your project just define the following properties and plugins.
.pom.xml
----
<properties>
<maven-checkstyle-plugin.failsOnError>true</maven-checkstyle-plugin.failsOnError> <1>
<maven-checkstyle-plugin.failsOnViolation>true
</maven-checkstyle-plugin.failsOnViolation> <2>
<maven-checkstyle-plugin.includeTestSourceDirectory>true
</maven-checkstyle-plugin.includeTestSourceDirectory> <3>
</properties>
<build>
<plugins>
<plugin> <4>
<groupId>io.spring.javaformat</groupId>
<artifactId>spring-javaformat-maven-plugin</artifactId>
</plugin>
<plugin> <5>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-checkstyle-plugin</artifactId>
</plugin>
</plugins>
<reporting>
<plugins>
<plugin> <5>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-checkstyle-plugin</artifactId>
</plugin>
</plugins>
</reporting>
</build>
----
<1> Fails the build upon Checkstyle errors
<2> Fails the build upon Checkstyle violations
<3> Checkstyle analyzes also the test sources
<4> Add the Spring Java Format plugin that will reformat your code to pass most of the Checkstyle formatting rules
<5> Add checkstyle plugin to your build and reporting phases
If you need to suppress some rules (e.g. line length needs to be longer), then it's enough for you to define a file under `${project.root}/src/checkstyle/checkstyle-suppressions.xml` with your suppressions. Example:
.projectRoot/src/checkstyle/checkstyle-suppresions.xml
----
<?xml version="1.0"?>
<!DOCTYPE suppressions PUBLIC
"-//Puppy Crawl//DTD Suppressions 1.1//EN"
"https://www.puppycrawl.com/dtds/suppressions_1_1.dtd">
<suppressions>
<suppress files=".*ConfigServerApplication\.java" checks="HideUtilityClassConstructor"/>
<suppress files=".*ConfigClientWatch\.java" checks="LineLengthCheck"/>
</suppressions>
----
It's advisable to copy the `${spring-cloud-build.rootFolder}/.editorconfig` and `${spring-cloud-build.rootFolder}/.springformat` to your project. That way, some default formatting rules will be applied. You can do so by running this script:
```bash
$ curl https://raw.githubusercontent.com/spring-cloud/spring-cloud-build/master/.editorconfig -o .editorconfig
$ touch .springformat
```
=== IDE setup
==== Intellij IDEA
In order to setup Intellij you should import our coding conventions, inspection profiles and set up the checkstyle plugin.
The following files can be found in the https://github.com/spring-cloud/spring-cloud-build/tree/master/spring-cloud-build-tools[Spring Cloud Build] project.
.spring-cloud-build-tools/
----
└── src
   ├── checkstyle
   │   └── checkstyle-suppressions.xml <3>
   └── main
   └── resources
   ├── checkstyle-header.txt <2>
   ├── checkstyle.xml <1>
   └── intellij
      ├── Intellij_Project_Defaults.xml <4>
      └── Intellij_Spring_Boot_Java_Conventions.xml <5>
----
<1> Default Checkstyle rules
<2> File header setup
<3> Default suppression rules
<4> Project defaults for Intellij that apply most of Checkstyle rules
<5> Project style conventions for Intellij that apply most of Checkstyle rules
.Code style
image::https://raw.githubusercontent.com/spring-cloud/spring-cloud-build/{spring-cloud-build-branch}/docs/src/main/asciidoc/images/intellij-code-style.png[Code style]
Go to `File` -> `Settings` -> `Editor` -> `Code style`. There click on the icon next to the `Scheme` section. There, click on the `Import Scheme` value and pick the `Intellij IDEA code style XML` option. Import the `spring-cloud-build-tools/src/main/resources/intellij/Intellij_Spring_Boot_Java_Conventions.xml` file.
.Inspection profiles
image::https://raw.githubusercontent.com/spring-cloud/spring-cloud-build/{spring-cloud-build-branch}/docs/src/main/asciidoc/images/intellij-inspections.png[Code style]
Go to `File` -> `Settings` -> `Editor` -> `Inspections`. There click on the icon next to the `Profile` section. There, click on the `Import Profile` and import the `spring-cloud-build-tools/src/main/resources/intellij/Intellij_Project_Defaults.xml` file.
.Checkstyle
To have Intellij work with Checkstyle, you have to install the `Checkstyle` plugin. It's advisable to also install the `Assertions2Assertj` to automatically convert the JUnit assertions
image::https://raw.githubusercontent.com/spring-cloud/spring-cloud-build/{spring-cloud-build-branch}/docs/src/main/asciidoc/images/intellij-checkstyle.png[Checkstyle]
Go to `File` -> `Settings` -> `Other settings` -> `Checkstyle`. There click on the `+` icon in the `Configuration file` section. There, you'll have to define where the checkstyle rules should be picked from. In the image above, we've picked the rules from the cloned Spring Cloud Build repository. However, you can point to the Spring Cloud Build's GitHub repository (e.g. for the `checkstyle.xml` : `https://raw.githubusercontent.com/spring-cloud/spring-cloud-build/master/spring-cloud-build-tools/src/main/resources/checkstyle.xml`). We need to provide the following variables:
- `checkstyle.header.file` - please point it to the Spring Cloud Build's, `spring-cloud-build-tools/src/main/resources/checkstyle-header.txt` file either in your cloned repo or via the `https://raw.githubusercontent.com/spring-cloud/spring-cloud-build/master/spring-cloud-build-tools/src/main/resources/checkstyle-header.txt` URL.
- `checkstyle.suppressions.file` - default suppressions. Please point it to the Spring Cloud Build's, `spring-cloud-build-tools/src/checkstyle/checkstyle-suppressions.xml` file either in your cloned repo or via the `https://raw.githubusercontent.com/spring-cloud/spring-cloud-build/master/spring-cloud-build-tools/src/checkstyle/checkstyle-suppressions.xml` URL.
- `checkstyle.additional.suppressions.file` - this variable corresponds to suppressions in your local project. E.g. you're working on `spring-cloud-contract`. Then point to the `project-root/src/checkstyle/checkstyle-suppressions.xml` folder. Example for `spring-cloud-contract` would be: `/home/username/spring-cloud-contract/src/checkstyle/checkstyle-suppressions.xml`.
IMPORTANT: Remember to set the `Scan Scope` to `All sources` since we apply checkstyle rules for production and test sources.
=== Duplicate Finder
Spring Cloud Build brings along the `basepom:duplicate-finder-maven-plugin`, that enables flagging duplicate and conflicting classes and resources on the java classpath.
==== Duplicate Finder configuration
Duplicate finder is *enabled by default* and will run in the `verify` phase of your Maven build, but it will only take effect in your project if you add the `duplicate-finder-maven-plugin` to the `build` section of the projecst's `pom.xml`.
.pom.xml
[source,xml]
----
<build>
<plugins>
<plugin>
<groupId>org.basepom.maven</groupId>
<artifactId>duplicate-finder-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
----
For other properties, we have set defaults as listed in the https://github.com/basepom/duplicate-finder-maven-plugin/wiki[plugin documentation].
You can easily override them but setting the value of the selected property prefixed with `duplicate-finder-maven-plugin`. For example, set `duplicate-finder-maven-plugin.skip` to `true` in order to skip duplicates check in your build.
If you need to add `ignoredClassPatterns` or `ignoredResourcePatterns` to your setup, make sure to add them in the plugin configuration section of your project:
[source,xml]
----
<build>
<plugins>
<plugin>
<groupId>org.basepom.maven</groupId>
<artifactId>duplicate-finder-maven-plugin</artifactId>
<configuration>
<ignoredClassPatterns>
<ignoredClassPattern>org.joda.time.base.BaseDateTime</ignoredClassPattern>
<ignoredClassPattern>.*module-info</ignoredClassPattern>
</ignoredClassPatterns>
<ignoredResourcePatterns>
<ignoredResourcePattern>changelog.txt</ignoredResourcePattern>
</ignoredResourcePatterns>
</configuration>
</plugin>
</plugins>
</build>
----
Spring Cloud Sleuth's last minor version is 3.1. You can check the https://github.com/spring-cloud/spring-cloud-sleuth/tree/3.1.x[3.1.x] branch for the latest commits.
The core of this project got moved to https://micrometer.io/docs/tracing[Micrometer Tracing] project and the instrumentations will be moved to https://micrometer.io/[Micrometer] and all respective projects (no longer all instrumentations will be done in a single repository.

File diff suppressed because it is too large Load Diff

View File

@@ -1,38 +0,0 @@
== Spring Cloud Sleuth Benchmarks
This module can run benchmarks using the following tools
- JMH
- JMeter
=== How to run it?
In the root folder inside the `scripts` folder there are the following benchmark scripts:
- runJmhBenchmark.sh
- runJmeterBenchmarks.sh
Just execute them from the root folder like this:
[source]
----
./scripts/runJmeterBenchmarks.sh
./scripts/runJmhBenchmarks.sh
----
=== How do they work?
For JMH we're building a shaded JAR file that is next executed.
For JMeter we're running two applications, one with Sleuth, one without with Spring Boot Maven Plugin.
Next a Maven JMeter plugin is executed that loads the `*.jmx` files, starts JMeter and prints out the results.
At the end Spring Boot Maven Plugin stops the applications.
=== What are we testing?
For now we're testing the performance impact of the following:
- our custom Trace HTTP filter
- instrumentation of controllers - `@Callable` returning and the sync one
- instrumentation of RestTemplate
- `@Async` annotated methods

View File

@@ -1,598 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
~ Copyright 2013-2018 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
~
~ https://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:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://maven.apache.org/POM/4.0.0"
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>
<name>Benchmarks</name>
<description>Benchmarks (JMH)</description>
<groupId>org.springframework.cloud</groupId>
<version>3.1.1-SNAPSHOT</version>
<artifactId>benchmarks</artifactId>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.6.1</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<properties>
<main.basedir>${project.basedir}/..</main.basedir>
<maven-shade-plugin.version>3.2.1</maven-shade-plugin.version>
<sonar.skip>true</sonar.skip>
<maven.compiler.target>1.8</maven.compiler.target>
<maven.compiler.source>1.8</maven.compiler.source>
<okhttp.version>4.9.0</okhttp.version>
<microbenchmark-runner.version>c5f1e7d047</microbenchmark-runner.version>
<jmh.version>1.26</jmh.version>
</properties>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-sleuth-dependencies</artifactId>
<version>${project.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-sleuth</artifactId>
<version>${project.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-sleuth</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-webflux</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjrt</artifactId>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
</dependency>
<dependency>
<groupId>org.assertj</groupId>
<artifactId>assertj-core</artifactId>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-stream-kafka</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-stream</artifactId>
<type>test-jar</type>
<scope>compile</scope>
<classifier>test-binder</classifier>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>com.github.mp911de.microbenchmark-runner</groupId>
<artifactId>microbenchmark-runner-junit5</artifactId>
<version>${microbenchmark-runner.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.github.mp911de.microbenchmark-runner</groupId>
<artifactId>microbenchmark-runner-extras</artifactId>
<version>${microbenchmark-runner.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.openjdk.jmh</groupId>
<artifactId>jmh-generator-annprocess</artifactId>
<version>${jmh.version}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.squareup.okhttp3</groupId>
<artifactId>okhttp</artifactId>
<version>${okhttp.version}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>io.zipkin.brave</groupId>
<artifactId>brave-instrumentation-httpclient</artifactId>
</dependency>
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
</dependency>
<dependency>
<groupId>org.awaitility</groupId>
<artifactId>awaitility</artifactId>
<scope>compile</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.1</version>
<configuration>
<source>${maven.compiler.source}</source>
<target>${maven.compiler.target}</target>
</configuration>
</plugin>
</plugins>
</build>
<repositories>
<repository>
<id>jitpack.io</id>
<url>https://jitpack.io</url>
</repository>
<repository>
<id>spring-snapshots</id>
<name>Spring Snapshots</name>
<url>https://repo.spring.io/snapshot</url>
<snapshots>
<enabled>true</enabled>
</snapshots>
<releases>
<enabled>false</enabled>
</releases>
</repository>
<!-- ONLY FOR BRAVE -->
<repository>
<id>jfrog-snapshots</id>
<name>JFrog Snapshots</name>
<url>https://oss.jfrog.org/oss-snapshot-local/</url>
<snapshots>
<enabled>true</enabled>
</snapshots>
<releases>
<enabled>false</enabled>
</releases>
</repository>
<repository>
<id>spring-milestones</id>
<name>Spring Milestones</name>
<url>https://repo.spring.io/milestone</url>
<snapshots>
<enabled>false</enabled>
</snapshots>
</repository>
<repository>
<id>spring-releases</id>
<name>Spring Releases</name>
<url>https://repo.spring.io/release</url>
<snapshots>
<enabled>false</enabled>
</snapshots>
</repository>
</repositories>
<pluginRepositories>
<pluginRepository>
<id>spring-snapshots</id>
<name>Spring Snapshots</name>
<url>https://repo.spring.io/snapshot</url>
<snapshots>
<enabled>true</enabled>
</snapshots>
<releases>
<enabled>false</enabled>
</releases>
</pluginRepository>
<pluginRepository>
<id>spring-milestones</id>
<name>Spring Milestones</name>
<url>https://repo.spring.io/milestone</url>
<snapshots>
<enabled>false</enabled>
</snapshots>
</pluginRepository>
<pluginRepository>
<id>spring-releases</id>
<name>Spring Releases</name>
<url>https://repo.spring.io/release</url>
<snapshots>
<enabled>false</enabled>
</snapshots>
</pluginRepository>
</pluginRepositories>
<profiles>
<profile>
<id>jmeter</id>
<activation>
<activeByDefault>false</activeByDefault>
</activation>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<version>${spring-boot.version}</version>
<executions>
<execution>
<goals>
<goal>repackage</goal>
</goals>
</execution>
<execution>
<id>start-non-sleuth-app</id>
<phase>pre-integration-test</phase>
<goals>
<goal>start</goal>
</goals>
<configuration>
<jvmArguments>"-Dserver.port=9875"
"-Dspring.sleuth.enabled=false"
</jvmArguments>
<jmxPort>8875</jmxPort>
<fork>true</fork>
</configuration>
</execution>
<execution>
<id>stop-non-sleuth-app</id>
<phase>post-integration-test</phase>
<goals>
<goal>stop</goal>
</goals>
<configuration>
<jmxPort>8875</jmxPort>
<fork>true</fork>
</configuration>
</execution>
<execution>
<id>start-sleuth-app</id>
<phase>pre-integration-test</phase>
<goals>
<goal>start</goal>
</goals>
<configuration>
<jvmArguments>"-Dserver.port=9876"</jvmArguments>
<jmxPort>8876</jmxPort>
<fork>true</fork>
</configuration>
</execution>
<execution>
<id>stop-sleuth-app</id>
<phase>post-integration-test</phase>
<goals>
<goal>stop</goal>
</goals>
<configuration>
<jmxPort>8876</jmxPort>
<fork>true</fork>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<artifactId>maven-failsafe-plugin</artifactId>
<version>2.22.2</version>
<executions>
<execution>
<goals>
<goal>integration-test</goal>
<goal>verify</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>com.lazerycode.jmeter</groupId>
<artifactId>jmeter-maven-plugin</artifactId>
<version>3.1.1</version>
<configuration>
<testResultsTimestamp>false</testResultsTimestamp>
<suppressJMeterOutput>false</suppressJMeterOutput>
<ignoreResultFailures>true</ignoreResultFailures>
<propertiesJMeter>
<jmeter.save.saveservice.thread_counts>true
</jmeter.save.saveservice.thread_counts>
<sampleresult.useNanoTime>true</sampleresult.useNanoTime>
</propertiesJMeter>
<jmeterPlugins>
<plugin>
<groupId>kg.apc</groupId>
<artifactId>jmeter-plugins</artifactId>
</plugin>
</jmeterPlugins>
</configuration>
<executions>
<execution>
<id>execute-jmeter-tests</id>
<goals>
<goal>jmeter</goal>
</goals>
<phase>integration-test</phase>
</execution>
</executions>
<dependencies>
<dependency>
<groupId>kg.apc</groupId>
<artifactId>jmeter-plugins</artifactId>
<version>1.0.0</version>
<exclusions>
<!--
Unfortunately some transitive dependencies cannot be found on mvncentral
and we have to explicitly exclude them.
For a complete list, see https://github.com/mlex/jmeter-maven-example/
-->
<exclusion>
<groupId>kg.apc</groupId>
<artifactId>perfmon</artifactId>
</exclusion>
<exclusion>
<groupId>org.apache.hadoop</groupId>
<artifactId>hadoop-core</artifactId>
</exclusion>
<exclusion>
<groupId>org.apache.hbase</groupId>
<artifactId>hbase</artifactId>
</exclusion>
<!--
These dependencies would override direct JMeter dependencies,
which results in version conflicts (e.g. NoSuchMethodError on jmeter startup
-->
<exclusion>
<groupId>org.apache.jmeter</groupId>
<artifactId>jorphan</artifactId>
</exclusion>
<exclusion>
<groupId>org.apache.bsf</groupId>
<artifactId>bsf-api</artifactId>
</exclusion>
<exclusion>
<groupId>org.bouncycastle</groupId>
<artifactId>bcmail-jdk15</artifactId>
</exclusion>
<exclusion>
<groupId>org.bouncycastle</groupId>
<artifactId>bcprov-jdk15</artifactId>
</exclusion>
<exclusion>
<groupId>javax.activation</groupId>
<artifactId>activation</artifactId>
</exclusion>
<exclusion>
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
</exclusion>
</exclusions>
</dependency>
</dependencies>
</plugin>
<plugin>
<groupId>com.lazerycode.jmeter</groupId>
<artifactId>jmeter-analysis-maven-plugin</artifactId>
<version>1.0.6</version>
<configuration>
<targetDirectory>
${project.build.directory}/jmeter/results/analysis/
</targetDirectory>
</configuration>
<executions>
<execution>
<id>create-html-report-for-asynchttp</id>
<phase>verify</phase>
<goals>
<goal>analyze</goal>
</goals>
<configuration>
<source>
${project.build.directory}/jmeter/results/AsyncHttpBenchmarks.jtl
</source>
</configuration>
</execution>
<execution>
<id>create-html-report-for-async-method</id>
<phase>verify</phase>
<goals>
<goal>analyze</goal>
</goals>
<configuration>
<source>
${project.build.directory}/jmeter/results/AsyncMethodBenchmarks.jtl
</source>
</configuration>
</execution>
<execution>
<id>create-html-report-for-sync-http</id>
<phase>verify</phase>
<goals>
<goal>analyze</goal>
</goals>
<configuration>
<source>
${project.build.directory}/jmeter/results/SyncHttpBenchmarks.jtl
</source>
</configuration>
</execution>
<execution>
<id>create-html-report-for-nice-index-html</id>
<phase>verify</phase>
<goals>
<goal>analyze</goal>
</goals>
<configuration>
<source>
${project.build.directory}/jmeter/results/*.jtl
</source>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<groupId>de.codecentric</groupId>
<artifactId>jmeter-graph-maven-plugin</artifactId>
<version>0.1.0</version>
<executions>
<execution>
<id>create-graph-threads-for-asynchttp</id>
<goals>
<goal>create-graph</goal>
</goals>
<phase>verify</phase>
<configuration>
<inputFile>
${project.build.directory}/jmeter/results/AsyncHttpBenchmarks.jtl
</inputFile>
<graphs>
<graph>
<pluginType>ResponseTimesOverTime</pluginType>
<width>800</width>
<height>600</height>
<outputFile>
${project.build.directory}/jmeter/results/AsyncHttpBenchmarks-ResponseTimesOverTime.png
</outputFile>
</graph>
<graph>
<pluginType>ResponseTimesPercentiles
</pluginType>
<width>800</width>
<height>600</height>
<outputFile>
${project.build.directory}/jmeter/results/AsyncHttpBenchmarks-ResponseTimesPercentiles.png
</outputFile>
</graph>
<graph>
<pluginType>LatenciesOverTime</pluginType>
<width>800</width>
<height>600</height>
<outputFile>
${project.build.directory}/jmeter/results/AsyncHttpBenchmarks-LatenciesOverTime.png
</outputFile>
</graph>
</graphs>
</configuration>
</execution>
<execution>
<id>create-graph-threads-for-async-method</id>
<goals>
<goal>create-graph</goal>
</goals>
<phase>verify</phase>
<configuration>
<inputFile>
${project.build.directory}/jmeter/results/AsyncMethodBenchmarks.jtl
</inputFile>
<graphs>
<graph>
<pluginType>ResponseTimesOverTime</pluginType>
<width>800</width>
<height>600</height>
<outputFile>
${project.build.directory}/jmeter/results/AsyncMethodBenchmarks-ResponseTimesOverTime.png
</outputFile>
</graph>
<graph>
<pluginType>ResponseTimesPercentiles
</pluginType>
<width>800</width>
<height>600</height>
<outputFile>
${project.build.directory}/jmeter/results/AsyncMethodBenchmarks-ResponseTimesPercentiles.png
</outputFile>
</graph>
<graph>
<pluginType>LatenciesOverTime</pluginType>
<width>800</width>
<height>600</height>
<outputFile>
${project.build.directory}/jmeter/results/AsyncMethodBenchmarks-LatenciesOverTime.png
</outputFile>
</graph>
</graphs>
</configuration>
</execution>
<execution>
<id>create-graph-threads-for-sync-http</id>
<goals>
<goal>create-graph</goal>
</goals>
<phase>verify</phase>
<configuration>
<inputFile>
${project.build.directory}/jmeter/results/SyncHttpBenchmarks.jtl
</inputFile>
<graphs>
<graph>
<pluginType>ResponseTimesOverTime</pluginType>
<width>800</width>
<height>600</height>
<outputFile>
${project.build.directory}/jmeter/results/SyncHttpBenchmarks-ResponseTimesOverTime.png
</outputFile>
</graph>
<graph>
<pluginType>ResponseTimesPercentiles
</pluginType>
<width>800</width>
<height>600</height>
<outputFile>
${project.build.directory}/jmeter/results/SyncHttpBenchmarks-ResponseTimesPercentiles.png
</outputFile>
</graph>
<graph>
<pluginType>LatenciesOverTime</pluginType>
<width>800</width>
<height>600</height>
<outputFile>
${project.build.directory}/jmeter/results/SyncHttpBenchmarks-LatenciesOverTime.png
</outputFile>
</graph>
</graphs>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</profile>
</profiles>
</project>

View File

@@ -1,181 +0,0 @@
/*
* Copyright 2013-2021 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
*
* https://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 org.springframework.cloud.sleuth.benchmarks.app.mvc;
import java.util.concurrent.Future;
import java.util.regex.Pattern;
import javax.annotation.PreDestroy;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory;
import org.springframework.boot.web.servlet.context.ServletWebServerInitializedEvent;
import org.springframework.boot.web.servlet.server.ServletWebServerFactory;
import org.springframework.cloud.sleuth.Span;
import org.springframework.cloud.sleuth.Tracer;
import org.springframework.cloud.sleuth.annotation.ContinueSpan;
import org.springframework.cloud.sleuth.annotation.NewSpan;
import org.springframework.cloud.sleuth.annotation.SpanTag;
import org.springframework.cloud.sleuth.benchmarks.app.mvc.controller.AsyncSimulationController;
import org.springframework.cloud.sleuth.instrument.web.SkipPatternProvider;
import org.springframework.context.ApplicationListener;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.util.SocketUtils;
/**
* @author Marcin Grzejszczak
*/
@SpringBootApplication
@EnableAsync
public class SleuthBenchmarkingSpringApp implements ApplicationListener<ServletWebServerInitializedEvent> {
private static final Log log = LogFactory.getLog(SleuthBenchmarkingSpringApp.class);
/**
* Port of the app.
*/
public int port;
@Autowired(required = false)
Tracer tracer;
@Autowired
AClass aClass;
@Autowired
AsyncSimulationController controller;
public static void main(String... args) {
SpringApplication.run(SleuthBenchmarkingSpringApp.class, args);
}
@PreDestroy
public void clean() {
this.controller.clean();
}
public String manualSpan() {
return this.aClass.manualSpan();
}
public String newSpan() {
return this.aClass.newSpan();
}
@Override
public void onApplicationEvent(ServletWebServerInitializedEvent event) {
this.port = event.getSource().getPort();
}
public Future<String> async() {
return this.controller.async();
}
@Configuration
static class Config {
@Autowired(required = false)
Tracer tracer;
@Bean
AnotherClass anotherClass() {
return new AnotherClass(this.tracer);
}
@Bean
AClass aClass() {
return new AClass(this.tracer, anotherClass());
}
@Bean
SkipPatternProvider patternProvider() {
return new SkipPatternProvider() {
@Override
public Pattern skipPattern() {
return Pattern.compile("");
}
};
}
@Bean
public ServletWebServerFactory servletContainer(@Value("${server.port:0}") int serverPort) {
log.info("Starting container at port [" + serverPort + "]");
return new TomcatServletWebServerFactory(serverPort == 0 ? SocketUtils.findAvailableTcpPort() : serverPort);
}
}
}
class AClass {
private final Tracer tracer;
private final AnotherClass anotherClass;
AClass(Tracer tracer, AnotherClass anotherClass) {
this.tracer = tracer;
this.anotherClass = anotherClass;
}
public String manualSpan() {
Span manual = this.tracer.nextSpan().name("span-name");
try (Tracer.SpanInScope ws = this.tracer.withSpan(manual.start())) {
return this.anotherClass.continuedSpan();
}
finally {
manual.end();
}
}
@NewSpan
public String newSpan() {
return this.anotherClass.continuedAnnotation("bar");
}
}
class AnotherClass {
private final Tracer tracer;
AnotherClass(Tracer tracer) {
this.tracer = tracer;
}
@ContinueSpan(log = "continuedspan")
public String continuedAnnotation(@SpanTag("foo") String tagValue) {
return "continued";
}
public String continuedSpan() {
Span span = this.tracer.currentSpan();
span.tag("foo", "bar");
span.event("continuedspan.before");
String response = "continued";
span.event("continuedspan.after");
return response;
}
}

View File

@@ -1,50 +0,0 @@
package org.springframework.cloud.sleuth.benchmarks.app.mvc.controller;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import javax.annotation.PreDestroy;
import org.springframework.scheduling.annotation.Async;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* @author Marcin Grzejszczak
*/
@RestController
public class AsyncSimulationController {
private final ExecutorService pool = Executors.newWorkStealingPool();
@RequestMapping("/foo")
public String foo() {
return "foo";
}
@RequestMapping("/bar")
public Callable<String> bar() {
return () -> "bar";
}
@RequestMapping("/async")
public String asyncHttp() throws ExecutionException, InterruptedException {
return this.async().get();
}
@Async
public Future<String> async() {
return this.pool.submit(() -> "async");
}
@PreDestroy
public void clean() {
this.pool.shutdownNow();
}
public ExecutorService getPool() {
return this.pool;
}
}

View File

@@ -1,287 +0,0 @@
/*
* Copyright 2013-2021 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
*
* https://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 org.springframework.cloud.sleuth.benchmarks.app.stream;
import java.io.IOException;
import java.time.Duration;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import java.util.function.Function;
import org.awaitility.Awaitility;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
import reactor.core.scheduler.Scheduler;
import reactor.core.scheduler.Schedulers;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.cloud.sleuth.instrument.messaging.MessagingSleuthOperators;
import org.springframework.cloud.stream.binder.test.InputDestination;
import org.springframework.cloud.stream.binder.test.OutputDestination;
import org.springframework.cloud.stream.binder.test.TestChannelBinderConfiguration;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Import;
import org.springframework.messaging.Message;
import org.springframework.messaging.support.MessageBuilder;
import static org.assertj.core.api.Assertions.assertThat;
@SpringBootApplication
@Import(TestChannelBinderConfiguration.class)
public class SleuthBenchmarkingStreamApplication {
private static final Logger log = LoggerFactory.getLogger(SleuthBenchmarkingStreamApplication.class);
public static void main(String[] args) throws InterruptedException, IOException {
// System.setProperty("spring.sleuth.enabled", "false");
// System.setProperty("spring.sleuth.reactor.instrumentation-type",
// "DECORATE_ON_EACH");
// System.setProperty("spring.sleuth.reactor.instrumentation-type",
// "DECORATE_ON_LAST");
// System.setProperty("spring.sleuth.reactor.instrumentation-type", "MANUAL");
System.setProperty("spring.sleuth.reactor.instrumentation-type", "DECORATE_QUEUES");
System.setProperty("spring.sleuth.integration.enabled", "true");
System.setProperty("spring.sleuth.function.type", "DECORATE_QUEUES");
ConfigurableApplicationContext context = SpringApplication.run(SleuthBenchmarkingStreamApplication.class, args);
InputDestination input = context.getBean(InputDestination.class);
input.send(MessageBuilder.withPayload("hello".getBytes())
.setHeader("b3", "4883117762eb9420-4883117762eb9420-1").build());
log.info("Retrieving the message for tests");
OutputDestination output = context.getBean(OutputDestination.class);
Awaitility.await().untilAsserted( () -> {
Message<byte[]> message = output.receive(1L);
log.info("Got the message from output");
assertThat(message).isNotNull();
log.info("Message is not null");
assertThat(message.getPayload()).isEqualTo("HELLO".getBytes());
log.info("Payload is HELLO");
String b3 = message.getHeaders().get("b3", String.class);
log.info("Checking the b3 header [" + b3 + "]");
assertThat(b3).startsWith("4883117762eb9420");
});
context.close();
System.exit(0);
}
@Bean
ExecutorService sleuthExecutorService() {
return Executors.newCachedThreadPool();
}
@Bean(name = "myFlux")
@ConditionalOnProperty(value = "spring.sleuth.function.type", havingValue = "simple")
public Function<String, String> simple() {
log.info("simple_function");
return new SimpleFunction();
}
@Bean(name = "myFlux")
@ConditionalOnProperty(value = "spring.sleuth.function.type", havingValue = "reactive_simple")
public Function<Flux<String>, Flux<String>> reactiveSimple() {
log.info("simple_reactive_function");
return new SimpleReactiveFunction();
}
@Bean(name = "myFlux")
@ConditionalOnProperty(value = "spring.sleuth.function.type", havingValue = "simple_function_with_around")
public Function<Message<String>, Message<String>> simpleFunctionWithAround() {
log.info("simple_function_with_around");
return new SimpleMessageFunction();
}
@Bean(name = "myFlux")
@ConditionalOnProperty(value = "spring.sleuth.function.type", havingValue = "simple_manual")
public Function<Message<String>, Message<String>> simpleManual(BeanFactory beanFactory) {
log.info("simple_manual_function");
return new SimpleManualFunction(beanFactory);
}
@Bean(name = "myFlux")
@ConditionalOnProperty(value = "spring.sleuth.function.type", havingValue = "reactive_simple_manual")
public Function<Flux<Message<String>>, Flux<Message<String>>> reactiveSimpleManual(BeanFactory beanFactory) {
log.info("simple_reactive_manual_function");
return new SimpleReactiveManualFunction(beanFactory);
}
@Bean(name = "myFlux")
@ConditionalOnProperty(value = "spring.sleuth.nonreactive.function.enabled", havingValue = "true")
public Function<String, String> nonReactiveFunction(ExecutorService executorService) {
log.info("no sleuth non reactive function");
return new SleuthNonReactiveFunction(executorService);
}
@Bean(name = "myFlux")
@ConditionalOnProperty(value = "spring.sleuth.function.type", havingValue = "DECORATE_ON_EACH",
matchIfMissing = true)
public Function<Flux<String>, Flux<String>> onEachFunction() {
log.info("on each function");
return new SleuthFunction();
}
@Bean(name = "myFlux")
@ConditionalOnProperty(value = "spring.sleuth.function.type", havingValue = "DECORATE_QUEUES",
matchIfMissing = true)
public Function<Flux<String>, Flux<String>> decorateQueuesFunction() {
log.info("decorate queues function");
return new SleuthFunction();
}
@Bean(name = "myFlux")
@ConditionalOnProperty(value = "spring.sleuth.function.type", havingValue = "DECORATE_ON_LAST")
public Function<Flux<String>, Flux<String>> onLastFunction() {
log.info("on last function");
return new SleuthFunction();
}
}
class SimpleFunction implements Function<String, String> {
private static final Logger log = LoggerFactory.getLogger(SimpleFunction.class);
@Override
public String apply(String input) {
// tracing works cause headers from the input message get propagated to the output
// message
log.info("Hello from simple [{}]", input);
return input.toUpperCase();
}
}
class SimpleReactiveFunction implements Function<Flux<String>, Flux<String>> {
private static final Logger log = LoggerFactory.getLogger(SimpleReactiveFunction.class);
@Override
public Flux<String> apply(Flux<String> input) {
return input.doOnNext(s -> log.info("Hello from simple [{}]", s)).map(String::toUpperCase);
}
}
class SimpleManualFunction implements Function<Message<String>, Message<String>> {
private static final Logger log = LoggerFactory.getLogger(SimpleFunction.class);
private final BeanFactory beanFactory;
SimpleManualFunction(BeanFactory beanFactory) {
this.beanFactory = beanFactory;
}
@Override
public Message<String> apply(Message<String> input) {
return (MessagingSleuthOperators.asFunction(this.beanFactory, input)
.andThen(msg -> MessagingSleuthOperators.withSpanInScope(this.beanFactory, msg, stringMessage -> {
log.info("Hello from simple manual [{}]", stringMessage.getPayload());
return stringMessage;
})).andThen(msg -> MessagingSleuthOperators.afterMessageHandled(this.beanFactory, msg, null))
.andThen(msg -> MessagingSleuthOperators.handleOutputMessage(this.beanFactory, msg))
.andThen(msg -> MessageBuilder.createMessage(msg.getPayload().toUpperCase(), msg.getHeaders()))
.andThen(msg -> MessagingSleuthOperators.afterMessageHandled(this.beanFactory, msg, null))
.apply(input));
}
}
class SimpleMessageFunction implements Function<Message<String>, Message<String>> {
private static final Logger log = LoggerFactory.getLogger(SimpleFunction.class);
@Override
public Message<String> apply(Message<String> input) {
log.info("Hello from message simple [{}]", input.getPayload());
return MessageBuilder.withPayload(input.getPayload().toUpperCase()).build();
}
}
// tag::simple_reactive[]
class SimpleReactiveManualFunction implements Function<Flux<Message<String>>, Flux<Message<String>>> {
private static final Logger log = LoggerFactory.getLogger(SimpleReactiveFunction.class);
private final BeanFactory beanFactory;
SimpleReactiveManualFunction(BeanFactory beanFactory) {
this.beanFactory = beanFactory;
}
@Override
public Flux<Message<String>> apply(Flux<Message<String>> input) {
return input.map(message -> (MessagingSleuthOperators.asFunction(this.beanFactory, message))
.andThen(msg -> MessagingSleuthOperators.withSpanInScope(this.beanFactory, msg, stringMessage -> {
log.info("Hello from simple manual [{}]", stringMessage.getPayload());
return stringMessage;
})).andThen(msg -> MessagingSleuthOperators.afterMessageHandled(this.beanFactory, msg, null))
.andThen(msg -> MessageBuilder.createMessage(msg.getPayload().toUpperCase(), msg.getHeaders()))
.andThen(msg -> MessagingSleuthOperators.handleOutputMessage(this.beanFactory, msg)).apply(message));
}
}
// end::simple_reactive[]
class SleuthNonReactiveFunction implements Function<String, String> {
private static final Logger log = LoggerFactory.getLogger(SleuthNonReactiveFunction.class);
private final ExecutorService executorService;
SleuthNonReactiveFunction(ExecutorService executorService) {
this.executorService = executorService;
}
@Override
public String apply(String input) {
log.info("Got a message");
try {
return this.executorService.submit(() -> {
log.info("Logging [{}] from a new thread", input);
return input.toUpperCase();
}).get(20, TimeUnit.MILLISECONDS);
}
catch (Exception e) {
throw new IllegalStateException(e);
}
}
}
class SleuthFunction implements Function<Flux<String>, Flux<String>> {
private static final Logger log = LoggerFactory.getLogger(SleuthFunction.class);
static final Scheduler SCHEDULER = Schedulers.newParallel("sleuthFunction");
@Override
public Flux<String> apply(Flux<String> input) {
return input.doOnEach(signal -> log.info("Got a message"))
.flatMap(s -> Mono.delay(Duration.ofMillis(1), SCHEDULER).map(aLong -> {
log.info("Logging [{}] from flat map", s);
return s.toUpperCase();
}));
}
}

View File

@@ -1,153 +0,0 @@
/*
* Copyright 2013-2021 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
*
* https://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 org.springframework.cloud.sleuth.benchmarks.app.webflux;
import java.time.Duration;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
import reactor.core.publisher.SignalType;
import reactor.core.scheduler.Scheduler;
import reactor.core.scheduler.Schedulers;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.WebApplicationType;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.boot.web.embedded.netty.NettyReactiveWebServerFactory;
import org.springframework.boot.web.reactive.context.ReactiveWebServerInitializedEvent;
import org.springframework.cloud.sleuth.TraceContext;
import org.springframework.cloud.sleuth.instrument.web.SkipPatternProvider;
import org.springframework.cloud.sleuth.instrument.web.WebFluxSleuthOperators;
import org.springframework.context.ApplicationListener;
import org.springframework.context.annotation.Bean;
import org.springframework.util.Assert;
import org.springframework.util.SocketUtils;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* @author alvin
*/
@SpringBootApplication
@RestController
public class SleuthBenchmarkingSpringWebFluxApp implements ApplicationListener<ReactiveWebServerInitializedEvent> {
static final Scheduler FOO_SCHEDULER = Schedulers.newParallel("foo");
private static final Logger log = LoggerFactory.getLogger(SleuthBenchmarkingSpringWebFluxApp.class);
/**
* Port to set.
*/
public int port;
public static void main(String... args) {
new SpringApplicationBuilder(SleuthBenchmarkingSpringWebFluxApp.class).web(WebApplicationType.REACTIVE)
.application().run(args);
}
@RequestMapping("/foo")
public Mono<String> foo() {
return Mono.just("foo");
}
@Bean
SkipPatternProvider patternProvider() {
return () -> Pattern.compile("");
}
@Bean
NettyReactiveWebServerFactory nettyReactiveWebServerFactory(@Value("${server.port:0}") int serverPort) {
log.info("Starting container at port [" + serverPort + "]");
return new NettyReactiveWebServerFactory(serverPort == 0 ? SocketUtils.findAvailableTcpPort() : serverPort);
}
@Override
public void onApplicationEvent(ReactiveWebServerInitializedEvent event) {
this.port = event.getWebServer().getPort();
}
@GetMapping("/simple")
public Mono<String> simple() {
return Mono.just("hello").map(String::toUpperCase).doOnNext(s -> log.info("Hello from simple [{}]", s));
}
// tag::simple_manual[]
@GetMapping("/simpleManual")
public Mono<String> simpleManual() {
return Mono.just("hello").map(String::toUpperCase).doOnEach(WebFluxSleuthOperators
.withSpanInScope(SignalType.ON_NEXT, signal -> log.info("Hello from simple [{}]", signal.get())));
}
// end::simple_manual[]
@GetMapping("/complexNoSleuth")
public Mono<String> complexNoSleuth() {
return Flux.range(1, 10).map(String::valueOf).collect(Collectors.toList())
.doOnEach(signal -> log.info("Got a request"))
.flatMap(s -> Mono.delay(Duration.ofMillis(1), FOO_SCHEDULER).map(aLong -> {
log.info("Logging [{}] from flat map", s);
return "";
}));
}
@GetMapping("/complex")
public Mono<String> complex() {
return Flux.range(1, 10).map(String::valueOf).collect(Collectors.toList())
.doOnEach(signal -> log.info("Got a request"))
.flatMap(s -> Mono.delay(Duration.ofMillis(1), FOO_SCHEDULER).map(aLong -> {
log.info("Logging [{}] from flat map", s);
return "";
})).doOnEach(signal -> {
log.info("Doing assertions");
TraceContext traceContext = signal.getContext().get(TraceContext.class);
Assert.notNull(traceContext, "Context must be set by Sleuth instrumentation");
if (traceContext.traceId().startsWith("0000000000000000")) {
Assert.state(traceContext.traceId().equals("00000000000000004883117762eb9420"), "TraceId must be propagated");
} else {
Assert.state(traceContext.traceId().equals("4883117762eb9420"), "TraceId must be propagated");
}
log.info("Assertions passed");
});
}
@GetMapping("/complexManual")
public Mono<String> complexManual() {
return Flux.range(1, 10).map(String::valueOf).collect(Collectors.toList())
.doOnEach(WebFluxSleuthOperators.withSpanInScope(SignalType.ON_NEXT, () -> log.info("Got a request")))
.flatMap(s -> Mono.subscriberContext().delayElement(Duration.ofMillis(1), FOO_SCHEDULER).map(ctx -> {
WebFluxSleuthOperators.withSpanInScope(ctx, () -> log.info("Logging [{}] from flat map", s));
return "";
})).doOnEach(signal -> {
WebFluxSleuthOperators.withSpanInScope(signal.getContext(), () -> log.info("Doing assertions"));
TraceContext traceContext = signal.getContext().get(TraceContext.class);
Assert.notNull(traceContext, "Context must be set by Sleuth instrumentation");
if (traceContext.traceId().startsWith("0000000000000000")) {
Assert.state(traceContext.traceId().equals("00000000000000004883117762eb9420"), "TraceId must be propagated");
} else {
Assert.state(traceContext.traceId().equals("4883117762eb9420"), "TraceId must be propagated");
}
log.info("Assertions passed");
});
}
}

View File

@@ -1,5 +0,0 @@
logging.level:
org.springframework: ERROR
org.springframework.sleuth: ERROR
org.springframework.sleuth.benchmarks: INFO
brave: ERROR

View File

@@ -1,61 +0,0 @@
/*
* Copyright 2016-2021 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
*
* https://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 org.springframework.cloud.sleuth.benchmarks.jmh;
import org.springframework.cloud.sleuth.autoconfig.instrument.reactor.SleuthReactorProperties;
public class Pair {
final String key;
final String value;
public Pair(String key, String value) {
this.key = key;
this.value = value;
}
public String asProp() {
return this.key + "=" + this.value;
}
public static Pair of(String key, String value) {
return new Pair(key, value);
}
public static Pair onHook() {
return new Pair("spring.sleuth.reactor.instrumentation-type", SleuthReactorProperties.InstrumentationType.DECORATE_QUEUES.name());
}
public static Pair noSleuth() {
return new Pair("spring.sleuth.enabled", "false");
}
public static Pair onEach() {
return new Pair("spring.sleuth.reactor.instrumentation-type", SleuthReactorProperties.InstrumentationType.DECORATE_ON_EACH.name());
}
public static Pair decorateQueues() {
return new Pair("spring.sleuth.reactor.instrumentation-type", SleuthReactorProperties.InstrumentationType.DECORATE_QUEUES.name());
}
public static Pair manual() {
return new Pair("spring.sleuth.reactor.instrumentation-type", SleuthReactorProperties.InstrumentationType.MANUAL.name());
}
public static Pair onLast() {
return new Pair("spring.sleuth.reactor.instrumentation-type", SleuthReactorProperties.InstrumentationType.DECORATE_ON_LAST.name());
}
}

View File

@@ -1,148 +0,0 @@
/*
* Copyright 2016-2021 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
*
* https://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 org.springframework.cloud.sleuth.benchmarks.jmh;
import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import org.openjdk.jmh.util.FileUtils;
import org.openjdk.jmh.util.Utils;
import org.springframework.cloud.sleuth.benchmarks.app.mvc.SleuthBenchmarkingSpringApp;
public class ProcessLauncherState {
private Process started;
private List<String> args;
private List<String> extraArgs;
private File home;
private String mainClass = SleuthBenchmarkingSpringApp.class.getName();
private int length;
public ProcessLauncherState(String dir, String... args) {
this.args = new ArrayList<>(Arrays.asList(args));
int count = 0;
this.args.add(count++, System.getProperty("java.home") + "/bin/java");
this.args.add(count++, "-Xmx128m");
this.args.add(count++, "-cp");
this.args.add(count++, getClasspath());
this.args.add(count++, "-Djava.security.egd=file:/dev/./urandom");
this.args.add(count++, "-XX:TieredStopAtLevel=1"); // zoom
if (System.getProperty("bench.args") != null) {
this.args.addAll(count++, Arrays.asList(System.getProperty("bench.args").split(" ")));
}
this.length = args.length;
this.home = new File(dir);
}
protected static String output(InputStream inputStream, String marker) throws IOException {
StringBuilder sb = new StringBuilder();
BufferedReader br = null;
br = new BufferedReader(new InputStreamReader(inputStream));
String line = null;
while ((line = br.readLine()) != null && !line.contains(marker)) {
sb.append(line + System.getProperty("line.separator"));
}
if (line != null) {
sb.append(line + System.getProperty("line.separator"));
}
return sb.toString();
}
public void setMainClass(String mainClass) {
this.mainClass = mainClass;
}
public void setExtraArgs(String... extraArgs) {
this.extraArgs = Arrays.asList(extraArgs);
}
private String getClasspath() {
StringBuilder builder = new StringBuilder();
for (URL url : ((URLClassLoader) getClass().getClassLoader()).getURLs()) {
if (builder.length() > 0) {
builder.append(File.pathSeparator);
}
builder.append(url.toString());
}
return builder.toString();
}
public void after() throws Exception {
if (started != null && started.isAlive()) {
System.err.println("Stopped " + mainClass + ": " + started.destroyForcibly().waitFor());
}
}
public Collection<String> capture(String... additional) throws Exception {
List<String> args = new ArrayList<>(this.args);
args.addAll(Arrays.asList(additional));
ProcessBuilder builder = new ProcessBuilder(args);
builder.directory(home);
builder.redirectErrorStream(true);
customize(builder);
if (!"false".equals(System.getProperty("debug", "false"))) {
System.err.println("Running: " + Utils.join(args, " "));
}
started = builder.start();
return FileUtils.readAllLines(started.getInputStream());
}
public void run() throws Exception {
System.out.println("Running process");
List<String> args = new ArrayList<>(this.args);
args.add(args.size() - this.length, this.mainClass);
if (extraArgs != null) {
args.addAll(extraArgs);
}
ProcessBuilder builder = new ProcessBuilder(args);
builder.directory(home);
builder.redirectErrorStream(true);
customize(builder);
if (!"false".equals(System.getProperty("debug", "false"))) {
System.err.println("Running: " + Utils.join(args, " "));
}
started = builder.start();
monitor();
}
protected void customize(ProcessBuilder builder) {
}
protected void monitor() throws IOException {
System.out.println(output(started.getInputStream(), "Started"));
}
public File getHome() {
return home;
}
}

View File

@@ -1,163 +0,0 @@
/*
* Copyright 2013-2021 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
*
* https://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 org.springframework.cloud.sleuth.benchmarks.jmh;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
import brave.Tracing;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
import org.openjdk.jmh.annotations.Param;
import org.openjdk.jmh.annotations.Setup;
import org.openjdk.jmh.annotations.TearDown;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.WebApplicationType;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.cloud.sleuth.benchmarks.app.stream.SleuthBenchmarkingStreamApplication;
import org.springframework.cloud.stream.binder.test.InputDestination;
import org.springframework.cloud.stream.binder.test.OutputDestination;
import org.springframework.cloud.stream.binder.test.TestChannelBinderConfiguration;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.messaging.Message;
import org.springframework.messaging.support.MessageBuilder;
import org.springframework.util.StringUtils;
import static org.assertj.core.api.Assertions.assertThat;
@Disabled
public class SampleTests {
@Test
public void testStream() throws Exception {
for (BenchmarkContext.Instrumentation value : BenchmarkContext.Instrumentation.values()) {
run(value);
}
// run(BenchmarkContext.Instrumentation.sleuthReactiveSimpleManual);
}
private void run(BenchmarkContext.Instrumentation value) throws Exception {
BenchmarkContext context = new BenchmarkContext();
System.out.println("\n\n\n\n WILL WORK WITH [" + value + "]\n\n\n\n");
context.instrumentation = value;
context.setup();
try {
context.run(value);
}
finally {
context.clean();
}
System.out.println("\n\n FINISHED WITH [" + value + "]\n\n\n\n");
}
public static class BenchmarkContext {
volatile ConfigurableApplicationContext applicationContext;
volatile InputDestination input;
volatile OutputDestination output;
@Param
private Instrumentation instrumentation;
@Setup
public void setup() {
this.applicationContext = initContext();
this.input = this.applicationContext.getBean(InputDestination.class);
this.output = this.applicationContext.getBean(OutputDestination.class);
}
protected ConfigurableApplicationContext initContext() {
SpringApplication application = new SpringApplicationBuilder(SleuthBenchmarkingStreamApplication.class)
.web(WebApplicationType.REACTIVE).application();
return application.run(runArgs());
}
protected String[] runArgs() {
List<String> strings = new ArrayList<>();
strings.addAll(Arrays.asList("--spring.jmx.enabled=false",
"--spring.application.name=defaultTraceContextForStream" + instrumentation.name()));
strings.addAll(instrumentation.entires.stream().map(s -> "--" + s).collect(Collectors.toList()));
return strings.toArray(new String[0]);
}
void run(Instrumentation value) {
System.out.println("Sending the message to input");
input.send(MessageBuilder.withPayload("hello".getBytes())
.setHeader("b3", "4883117762eb9420-4883117762eb9420-1").build());
System.out.println("Retrieving the message for tests");
Message<byte[]> message = output.receive(200L);
System.out.println("Got the message from output");
assertThat(message).isNotNull();
System.out.println("Message is not null");
assertThat(message.getPayload()).isEqualTo("HELLO".getBytes());
System.out.println("Payload is HELLO");
if (!value.toString().toLowerCase().contains("nosleuth")) {
String b3 = message.getHeaders().get("b3", String.class);
System.out.println("Checking the b3 header [" + b3 + "]");
assertThat(b3).startsWith("4883117762eb9420");
}
}
@TearDown
public void clean() throws Exception {
Tracing current = Tracing.current();
if (current != null) {
current.close();
}
try {
this.applicationContext.close();
}
catch (Exception ig) {
}
}
public enum Instrumentation {
noSleuthSimple("spring.sleuth.enabled=false,spring.sleuth.function.type=simple");
private Set<String> entires = new HashSet<>();
Instrumentation(String key, String value) {
this.entires.add(key + "=" + value);
}
Instrumentation(String commaSeparated) {
this.entires.addAll(StringUtils.commaDelimitedListToSet(commaSeparated));
}
}
}
@Configuration(proxyBeanMethods = false)
@Import(TestChannelBinderConfiguration.class)
static class TestConfiguration {
}
}

View File

@@ -1,28 +0,0 @@
/*
* Copyright 2016-2021 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
*
* https://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 org.springframework.cloud.sleuth.benchmarks.jmh;
public enum TracerImplementation {
brave;
@Override
public String toString() {
return this.name();
}
}

View File

@@ -1,128 +0,0 @@
/*
* Copyright 2016-2021 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
*
* https://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 org.springframework.cloud.sleuth.benchmarks.jmh.bridge;
import java.util.concurrent.TimeUnit;
import jmh.mbr.junit5.Microbenchmark;
import org.openjdk.jmh.annotations.Benchmark;
import org.openjdk.jmh.annotations.BenchmarkMode;
import org.openjdk.jmh.annotations.Fork;
import org.openjdk.jmh.annotations.Measurement;
import org.openjdk.jmh.annotations.Mode;
import org.openjdk.jmh.annotations.OutputTimeUnit;
import org.openjdk.jmh.annotations.Param;
import org.openjdk.jmh.annotations.Scope;
import org.openjdk.jmh.annotations.Setup;
import org.openjdk.jmh.annotations.State;
import org.openjdk.jmh.annotations.TearDown;
import org.openjdk.jmh.annotations.Warmup;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.WebApplicationType;
import org.springframework.boot.autoconfigure.ImportAutoConfiguration;
import org.springframework.cloud.sleuth.Span;
import org.springframework.cloud.sleuth.Tracer;
import org.springframework.cloud.sleuth.autoconfig.brave.BraveAutoConfiguration;
import org.springframework.cloud.sleuth.benchmarks.jmh.TracerImplementation;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.Configuration;
import static org.assertj.core.api.BDDAssertions.then;
@Measurement(iterations = 5, time = 1)
@Warmup(iterations = 5, time = 1)
@Fork(2)
@BenchmarkMode(Mode.SampleTime)
@OutputTimeUnit(TimeUnit.MILLISECONDS)
@Microbenchmark
public class BridgeTests {
@Benchmark
public void should_create_next_span(BenchmarkContext context) throws Exception {
Tracer tracer = context.tracer;
Span span = tracer.nextSpan().start();
try {
then(span).isNotNull();
}
finally {
if (span != null) {
span.end();
}
}
}
@Benchmark
public void should_create_next_span_with_parent(BenchmarkContext context) throws Exception {
Tracer tracer = context.tracer;
Span span = tracer.nextSpan(context.parent).start();
try {
then(span).isNotNull();
}
finally {
if (span != null) {
span.end();
}
}
}
@Benchmark
public void should_retrieve_current_span_from_scope(BenchmarkContext context) throws Exception {
Tracer tracer = context.tracer;
Span span = context.parent;
try (Tracer.SpanInScope ws = tracer.withSpan(span)) {
then(tracer.currentSpan().context().spanId()).isEqualTo(span.context().spanId());
}
}
@State(Scope.Benchmark)
public static class BenchmarkContext {
volatile ConfigurableApplicationContext withSleuth;
volatile Tracer tracer;
volatile Span parent;
@Param
private TracerImplementation tracerImplementation;
@Setup
public void setup() {
SpringApplication application = new SpringApplication(TestConfiguration.class);
application.setWebApplicationType(WebApplicationType.NONE);
this.withSleuth = application.run("--spring.jmx.enabled=false",
"--spring.application.name=withSleuth_" + this.tracerImplementation.name());
this.tracer = this.withSleuth.getBean(Tracer.class);
this.parent = this.tracer.nextSpan().name("name").start();
}
@TearDown
public void clean() {
this.withSleuth.close();
this.parent.end();
}
@Configuration(proxyBeanMethods = false)
@ImportAutoConfiguration(BraveAutoConfiguration.class)
static class TestConfiguration {
}
}
}

View File

@@ -1,88 +0,0 @@
/*
* Copyright 2013-2021 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
*
* https://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 org.springframework.cloud.sleuth.benchmarks.jmh.mvc;
import java.util.concurrent.TimeUnit;
import jmh.mbr.junit5.Microbenchmark;
import org.openjdk.jmh.annotations.Benchmark;
import org.openjdk.jmh.annotations.BenchmarkMode;
import org.openjdk.jmh.annotations.Fork;
import org.openjdk.jmh.annotations.Measurement;
import org.openjdk.jmh.annotations.Mode;
import org.openjdk.jmh.annotations.OutputTimeUnit;
import org.openjdk.jmh.annotations.Param;
import org.openjdk.jmh.annotations.Scope;
import org.openjdk.jmh.annotations.Setup;
import org.openjdk.jmh.annotations.State;
import org.openjdk.jmh.annotations.TearDown;
import org.openjdk.jmh.annotations.Threads;
import org.openjdk.jmh.annotations.Warmup;
import org.springframework.boot.SpringApplication;
import org.springframework.cloud.sleuth.benchmarks.app.mvc.SleuthBenchmarkingSpringApp;
import org.springframework.cloud.sleuth.benchmarks.jmh.TracerImplementation;
import org.springframework.context.ConfigurableApplicationContext;
import static org.assertj.core.api.BDDAssertions.then;
@Measurement(iterations = 10, time = 1)
@Warmup(iterations = 10, time = 1)
@Fork(4)
@BenchmarkMode(Mode.SampleTime)
@OutputTimeUnit(TimeUnit.MICROSECONDS)
@Threads(Threads.MAX)
@Microbenchmark
public class AnnotationBenchmarksTests {
@Benchmark
public void manuallyCreatedSpans(BenchmarkContext context) throws Exception {
then(context.sleuth.manualSpan()).isEqualTo("continued");
}
@Benchmark
public void spanCreatedWithAnnotations(BenchmarkContext context) throws Exception {
then(context.sleuth.newSpan()).isEqualTo("continued");
}
@State(Scope.Benchmark)
public static class BenchmarkContext {
volatile ConfigurableApplicationContext withSleuth;
volatile SleuthBenchmarkingSpringApp sleuth;
@Param
private TracerImplementation tracerImplementation;
@Setup
public void setup() {
this.withSleuth = new SpringApplication(SleuthBenchmarkingSpringApp.class).run("--spring.jmx.enabled=false",
"--spring.application.name=withSleuth_" + this.tracerImplementation.name());
this.sleuth = this.withSleuth.getBean(SleuthBenchmarkingSpringApp.class);
}
@TearDown
public void clean() {
this.sleuth.clean();
this.withSleuth.close();
}
}
}

View File

@@ -1,81 +0,0 @@
/*
* Copyright 2013-2021 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
*
* https://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 org.springframework.cloud.sleuth.benchmarks.jmh.mvc;
import java.util.concurrent.TimeUnit;
import jmh.mbr.junit5.Microbenchmark;
import org.openjdk.jmh.annotations.Benchmark;
import org.openjdk.jmh.annotations.BenchmarkMode;
import org.openjdk.jmh.annotations.Fork;
import org.openjdk.jmh.annotations.Measurement;
import org.openjdk.jmh.annotations.Mode;
import org.openjdk.jmh.annotations.OutputTimeUnit;
import org.openjdk.jmh.annotations.Param;
import org.openjdk.jmh.annotations.Scope;
import org.openjdk.jmh.annotations.Setup;
import org.openjdk.jmh.annotations.State;
import org.openjdk.jmh.annotations.TearDown;
import org.openjdk.jmh.annotations.Threads;
import org.openjdk.jmh.annotations.Warmup;
import org.springframework.boot.SpringApplication;
import org.springframework.cloud.sleuth.benchmarks.app.mvc.SleuthBenchmarkingSpringApp;
import org.springframework.cloud.sleuth.benchmarks.jmh.TracerImplementation;
import org.springframework.context.ConfigurableApplicationContext;
import static org.assertj.core.api.BDDAssertions.then;
@Measurement(iterations = 5, time = 1)
@Warmup(iterations = 5, time = 1)
@Fork(2)
@BenchmarkMode(Mode.SampleTime)
@OutputTimeUnit(TimeUnit.MICROSECONDS)
@Threads(Threads.MAX)
@Microbenchmark
public class AsyncWithSleuthBenchmarksTests {
@Benchmark
public void asyncMethodWithSleuth(BenchmarkContext context) throws Exception {
then(context.app.async().get()).isEqualTo("async");
}
@State(Scope.Benchmark)
public static class BenchmarkContext {
volatile ConfigurableApplicationContext context;
volatile SleuthBenchmarkingSpringApp app;
@Param
private TracerImplementation tracerImplementation;
@Setup
public void setup() {
this.context = new SpringApplication(SleuthBenchmarkingSpringApp.class).run(
"--spring.jmx.enabled=false",
"--spring.application.name=withSleuth_" + this.tracerImplementation.name()
);
this.app = this.context.getBean(SleuthBenchmarkingSpringApp.class);
}
@TearDown
public void clean() {
this.app.clean();
this.context.close();
}
}
}

View File

@@ -1,78 +0,0 @@
/*
* Copyright 2013-2021 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
*
* https://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 org.springframework.cloud.sleuth.benchmarks.jmh.mvc;
import java.util.concurrent.TimeUnit;
import jmh.mbr.junit5.Microbenchmark;
import org.openjdk.jmh.annotations.Benchmark;
import org.openjdk.jmh.annotations.BenchmarkMode;
import org.openjdk.jmh.annotations.Fork;
import org.openjdk.jmh.annotations.Measurement;
import org.openjdk.jmh.annotations.Mode;
import org.openjdk.jmh.annotations.OutputTimeUnit;
import org.openjdk.jmh.annotations.Scope;
import org.openjdk.jmh.annotations.Setup;
import org.openjdk.jmh.annotations.State;
import org.openjdk.jmh.annotations.TearDown;
import org.openjdk.jmh.annotations.Threads;
import org.openjdk.jmh.annotations.Warmup;
import org.springframework.boot.SpringApplication;
import org.springframework.cloud.sleuth.benchmarks.app.mvc.SleuthBenchmarkingSpringApp;
import org.springframework.context.ConfigurableApplicationContext;
import static org.assertj.core.api.BDDAssertions.then;
@Measurement(iterations = 5, time = 1)
@Warmup(iterations = 5, time = 1)
@Fork(2)
@BenchmarkMode(Mode.SampleTime)
@OutputTimeUnit(TimeUnit.MICROSECONDS)
@Threads(Threads.MAX)
@Microbenchmark
public class AsyncWithoutSleuthBenchmarksTests {
@Benchmark
public void asyncMethodWithoutSleuth(BenchmarkContext context) throws Exception {
then(context.app.async().get()).isEqualTo("async");
}
@State(Scope.Benchmark)
public static class BenchmarkContext {
volatile ConfigurableApplicationContext context;
volatile SleuthBenchmarkingSpringApp app;
@Setup
public void setup() {
this.context = new SpringApplication(SleuthBenchmarkingSpringApp.class).run(
"--spring.jmx.enabled=false",
"--spring.application.name=withoutSleuth",
"--spring.sleuth.enabled=false",
"--spring.sleuth.async.enabled=false"
);
this.app = this.context.getBean(SleuthBenchmarkingSpringApp.class);
}
@TearDown
public void clean() {
this.app.clean();
this.context.close();
}
}
}

View File

@@ -1,167 +0,0 @@
/*
* Copyright 2013-2021 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
*
* https://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 org.springframework.cloud.sleuth.benchmarks.jmh.mvc;
import java.io.IOException;
import java.util.concurrent.Callable;
import java.util.concurrent.TimeUnit;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import jmh.mbr.junit5.Microbenchmark;
import org.openjdk.jmh.annotations.Benchmark;
import org.openjdk.jmh.annotations.BenchmarkMode;
import org.openjdk.jmh.annotations.Fork;
import org.openjdk.jmh.annotations.Measurement;
import org.openjdk.jmh.annotations.Mode;
import org.openjdk.jmh.annotations.OutputTimeUnit;
import org.openjdk.jmh.annotations.Param;
import org.openjdk.jmh.annotations.Scope;
import org.openjdk.jmh.annotations.Setup;
import org.openjdk.jmh.annotations.State;
import org.openjdk.jmh.annotations.TearDown;
import org.openjdk.jmh.annotations.Threads;
import org.openjdk.jmh.annotations.Warmup;
import org.springframework.boot.SpringApplication;
import org.springframework.cloud.sleuth.CurrentTraceContext;
import org.springframework.cloud.sleuth.Tracer;
import org.springframework.cloud.sleuth.benchmarks.app.mvc.SleuthBenchmarkingSpringApp;
import org.springframework.cloud.sleuth.benchmarks.jmh.TracerImplementation;
import org.springframework.cloud.sleuth.benchmarks.app.mvc.controller.AsyncSimulationController;
import org.springframework.cloud.sleuth.http.HttpServerHandler;
import org.springframework.cloud.sleuth.instrument.web.servlet.TracingFilter;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.http.MediaType;
import org.springframework.mock.web.MockFilterChain;
import org.springframework.mock.web.MockHttpServletRequest;
import org.springframework.mock.web.MockHttpServletResponse;
import org.springframework.mock.web.MockServletContext;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.MvcResult;
import org.springframework.test.web.servlet.request.MockHttpServletRequestBuilder;
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import static org.assertj.core.api.Assertions.assertThat;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.asyncDispatch;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.request;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
@Warmup(iterations = 5)
@Measurement(iterations = 10, time = 1)
@Fork(2)
@BenchmarkMode(Mode.SampleTime)
@OutputTimeUnit(TimeUnit.MICROSECONDS)
@Threads(Threads.MAX)
@Microbenchmark
public class HttpFilterBenchmarksTests {
@Benchmark
public void filterWithSleuth(BenchmarkContext context) throws ServletException, IOException {
MockHttpServletRequest request = builder().buildRequest(new MockServletContext());
MockHttpServletResponse response = new MockHttpServletResponse();
response.setContentType(MediaType.APPLICATION_JSON_VALUE);
context.tracingFilter.doFilter(request, response, new MockFilterChain());
}
@Benchmark
public void asyncWithSleuth(BenchmarkContext context) throws Exception {
performRequest(context.mockMvcForTracedController, "bar", "bar");
}
private MockHttpServletRequestBuilder builder() {
return get("/").accept(MediaType.APPLICATION_JSON).header("User-Agent", "MockMvc");
}
private void performRequest(MockMvc mockMvc, String url, String expectedResult) throws Exception {
MvcResult mvcResult = mockMvc.perform(get("/" + url)).andExpect(status().isOk())
.andExpect(request().asyncStarted()).andReturn();
mockMvc.perform(asyncDispatch(mvcResult)).andExpect(status().isOk())
.andExpect(content().string(expectedResult));
}
@State(Scope.Benchmark)
public static class BenchmarkContext {
volatile ConfigurableApplicationContext withSleuth;
volatile TracingFilter tracingFilter;
volatile MockMvc mockMvcForTracedController;
@Param
private TracerImplementation tracerImplementation;
@Setup
public void setup() {
this.withSleuth = new SpringApplication(SleuthBenchmarkingSpringApp.class).run("--spring.jmx.enabled=false",
"--spring.application.name=withSleuth_" + this.tracerImplementation.name());
assertThat(this.withSleuth.getBeanProvider(Tracer.class).getIfAvailable(() -> null)).isNotNull();
this.tracingFilter = TracingFilter.create(this.withSleuth.getBean(CurrentTraceContext.class), this.withSleuth.getBean(HttpServerHandler.class));
this.mockMvcForTracedController = MockMvcBuilders
.standaloneSetup(this.withSleuth.getBean(AsyncSimulationController.class)).build();
}
@TearDown
public void clean() {
this.withSleuth.getBean(SleuthBenchmarkingSpringApp.class).clean();
this.withSleuth.close();
}
}
private static class DummyFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
chain.doFilter(request, response);
}
@Override
public void destroy() {
}
}
@RestController
private static class VanillaController {
@RequestMapping("/vanilla")
public Callable<String> vanilla() {
return () -> "vanilla";
}
}
}

View File

@@ -1,161 +0,0 @@
/*
* Copyright 2013-2021 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
*
* https://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 org.springframework.cloud.sleuth.benchmarks.jmh.mvc;
import java.io.IOException;
import java.util.concurrent.Callable;
import java.util.concurrent.TimeUnit;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import jmh.mbr.junit5.Microbenchmark;
import org.openjdk.jmh.annotations.Benchmark;
import org.openjdk.jmh.annotations.BenchmarkMode;
import org.openjdk.jmh.annotations.Fork;
import org.openjdk.jmh.annotations.Measurement;
import org.openjdk.jmh.annotations.Mode;
import org.openjdk.jmh.annotations.OutputTimeUnit;
import org.openjdk.jmh.annotations.Param;
import org.openjdk.jmh.annotations.Scope;
import org.openjdk.jmh.annotations.Setup;
import org.openjdk.jmh.annotations.State;
import org.openjdk.jmh.annotations.TearDown;
import org.openjdk.jmh.annotations.Threads;
import org.openjdk.jmh.annotations.Warmup;
import org.springframework.boot.SpringApplication;
import org.springframework.cloud.sleuth.Tracer;
import org.springframework.cloud.sleuth.benchmarks.app.mvc.SleuthBenchmarkingSpringApp;
import org.springframework.cloud.sleuth.benchmarks.jmh.TracerImplementation;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.http.MediaType;
import org.springframework.mock.web.MockFilterChain;
import org.springframework.mock.web.MockHttpServletRequest;
import org.springframework.mock.web.MockHttpServletResponse;
import org.springframework.mock.web.MockServletContext;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.MvcResult;
import org.springframework.test.web.servlet.request.MockHttpServletRequestBuilder;
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import static org.assertj.core.api.Assertions.assertThat;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.asyncDispatch;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.request;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
@Warmup(iterations = 5)
@Measurement(iterations = 10, time = 1)
@Fork(2)
@BenchmarkMode(Mode.SampleTime)
@OutputTimeUnit(TimeUnit.MICROSECONDS)
@Threads(Threads.MAX)
@Microbenchmark
public class HttpFilterNoSleuthBenchmarksTests {
@Benchmark
public void filterWithoutSleuth(BenchmarkContext context) throws IOException, ServletException {
MockHttpServletRequest request = builder().buildRequest(new MockServletContext());
MockHttpServletResponse response = new MockHttpServletResponse();
response.setContentType(MediaType.APPLICATION_JSON_VALUE);
context.dummyFilter.doFilter(request, response, new MockFilterChain());
}
@Benchmark
public void asyncWithoutSleuth(BenchmarkContext context) throws Exception {
performRequest(context.mockMvcForUntracedController, "vanilla", "vanilla");
}
private MockHttpServletRequestBuilder builder() {
return get("/").accept(MediaType.APPLICATION_JSON).header("User-Agent", "MockMvc");
}
private void performRequest(MockMvc mockMvc, String url, String expectedResult) throws Exception {
MvcResult mvcResult = mockMvc.perform(get("/" + url)).andExpect(status().isOk())
.andExpect(request().asyncStarted()).andReturn();
mockMvc.perform(asyncDispatch(mvcResult)).andExpect(status().isOk())
.andExpect(content().string(expectedResult));
}
@State(Scope.Benchmark)
public static class BenchmarkContext {
volatile ConfigurableApplicationContext app;
volatile DummyFilter dummyFilter = new DummyFilter();
volatile MockMvc mockMvcForUntracedController;
@Param
private TracerImplementation tracerImplementation;
@Setup
public void setup() {
this.app = new SpringApplication(SleuthBenchmarkingSpringApp.class).run("--spring.jmx.enabled=false", "--spring.sleuth.enabled=false",
"--spring.application.name=noSleuth_" + this.tracerImplementation.name());
assertThat(this.app.getBeanProvider(Tracer.class).getIfAvailable(() -> null)).isNull();
this.mockMvcForUntracedController = MockMvcBuilders.standaloneSetup(new VanillaController()).build();
}
@TearDown
public void clean() {
this.app.getBean(SleuthBenchmarkingSpringApp.class).clean();
this.app.close();
}
}
private static class DummyFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
chain.doFilter(request, response);
}
@Override
public void destroy() {
}
}
@RestController
private static class VanillaController {
@RequestMapping("/vanilla")
public Callable<String> vanilla() {
return () -> "vanilla";
}
}
}

View File

@@ -1,111 +0,0 @@
/*
* Copyright 2013-2021 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
*
* https://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 org.springframework.cloud.sleuth.benchmarks.jmh.mvc;
import java.io.IOException;
import java.util.Collections;
import java.util.concurrent.TimeUnit;
import javax.servlet.ServletException;
import jmh.mbr.junit5.Microbenchmark;
import org.openjdk.jmh.annotations.Benchmark;
import org.openjdk.jmh.annotations.BenchmarkMode;
import org.openjdk.jmh.annotations.Fork;
import org.openjdk.jmh.annotations.Measurement;
import org.openjdk.jmh.annotations.Mode;
import org.openjdk.jmh.annotations.OutputTimeUnit;
import org.openjdk.jmh.annotations.Param;
import org.openjdk.jmh.annotations.Scope;
import org.openjdk.jmh.annotations.Setup;
import org.openjdk.jmh.annotations.State;
import org.openjdk.jmh.annotations.TearDown;
import org.openjdk.jmh.annotations.Threads;
import org.openjdk.jmh.annotations.Warmup;
import org.springframework.boot.SpringApplication;
import org.springframework.cloud.sleuth.benchmarks.app.mvc.SleuthBenchmarkingSpringApp;
import org.springframework.cloud.sleuth.benchmarks.app.mvc.controller.AsyncSimulationController;
import org.springframework.cloud.sleuth.benchmarks.jmh.TracerImplementation;
import org.springframework.cloud.sleuth.instrument.web.mvc.TracingClientHttpRequestInterceptor;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.test.web.client.MockMvcClientHttpRequestFactory;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
import org.springframework.web.client.RestTemplate;
import static org.assertj.core.api.BDDAssertions.then;
/**
* We're checking how much overhead does the instrumentation of the RestTemplate take
*/
@Measurement(iterations = 5, time = 1)
@Warmup(iterations = 5, time = 1)
@Fork(2)
@BenchmarkMode(Mode.SampleTime)
@OutputTimeUnit(TimeUnit.MICROSECONDS)
@Threads(Threads.MAX)
@Microbenchmark
public class RestTemplateBenchmarkTests {
@Benchmark
public void syncEndpointWithoutSleuth(BenchmarkContext context) throws IOException, ServletException {
then(context.untracedTemplate.getForObject("/foo", String.class)).isEqualTo("foo");
}
@Benchmark
public void syncEndpointWithSleuth(BenchmarkContext context) throws ServletException, IOException {
then(context.tracedTemplate.getForObject("/foo", String.class)).isEqualTo("foo");
}
@State(Scope.Benchmark)
public static class BenchmarkContext {
volatile ConfigurableApplicationContext withSleuth;
volatile MockMvc mockMvc;
volatile RestTemplate tracedTemplate;
volatile RestTemplate untracedTemplate;
@Param
private TracerImplementation tracerImplementation;
@Setup
public void setup() {
this.withSleuth = new SpringApplication(SleuthBenchmarkingSpringApp.class).run(
"--spring.jmx.enabled=false",
"--spring.application.name=withSleuth_" + this.tracerImplementation.name()
);
this.mockMvc = MockMvcBuilders.standaloneSetup(this.withSleuth.getBean(AsyncSimulationController.class))
.build();
this.tracedTemplate = new RestTemplate(new MockMvcClientHttpRequestFactory(this.mockMvc));
this.tracedTemplate.setInterceptors(
Collections.singletonList(this.withSleuth.getBean(TracingClientHttpRequestInterceptor.class)));
this.untracedTemplate = new RestTemplate(new MockMvcClientHttpRequestFactory(this.mockMvc));
}
@TearDown
public void clean() {
this.withSleuth.getBean(SleuthBenchmarkingSpringApp.class).clean();
this.withSleuth.close();
}
}
}

View File

@@ -1,92 +0,0 @@
/*
* Copyright 2016-2021 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
*
* https://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 org.springframework.cloud.sleuth.benchmarks.jmh.mvc;
import jmh.mbr.junit5.Microbenchmark;
import org.junit.jupiter.api.Disabled;
import org.openjdk.jmh.annotations.Benchmark;
import org.openjdk.jmh.annotations.BenchmarkMode;
import org.openjdk.jmh.annotations.Fork;
import org.openjdk.jmh.annotations.Level;
import org.openjdk.jmh.annotations.Measurement;
import org.openjdk.jmh.annotations.Mode;
import org.openjdk.jmh.annotations.Param;
import org.openjdk.jmh.annotations.Scope;
import org.openjdk.jmh.annotations.State;
import org.openjdk.jmh.annotations.TearDown;
import org.openjdk.jmh.annotations.Warmup;
import org.springframework.cloud.sleuth.benchmarks.jmh.ProcessLauncherState;
import org.springframework.cloud.sleuth.benchmarks.jmh.TracerImplementation;
@Measurement(iterations = 5)
@Warmup(iterations = 1)
@Fork(value = 2, warmups = 0)
@BenchmarkMode(Mode.AverageTime)
@Microbenchmark
@Disabled("Process doesn't stop")
public class StartupBenchmarkTests {
@Benchmark
public void withAnnotations(ApplicationState state) throws Exception {
state.run();
}
@Benchmark
public void withoutAnnotations(ApplicationState state) throws Exception {
state.setExtraArgs("--spring.sleuth.annotation.enabled=false");
state.run();
}
@Benchmark
public void withoutAsync(ApplicationState state) throws Exception {
state.setExtraArgs("--spring.sleuth.async.enabled=false", "--spring.sleuth.annotation.enabled=false");
state.run();
}
@Benchmark
public void withoutScheduled(ApplicationState state) throws Exception {
state.setExtraArgs("--spring.sleuth.scheduled.enabled=false", "--spring.sleuth.async.enabled=false",
"--spring.sleuth.annotation.enabled=false");
state.run();
}
@Benchmark
public void withoutWeb(ApplicationState state) throws Exception {
state.setExtraArgs("--spring.sleuth.web.enabled=false", "--spring.sleuth.scheduled.enabled=false",
"--spring.sleuth.async.enabled=false", "--spring.sleuth.annotation.enabled=false");
state.run();
}
@State(Scope.Benchmark)
public static class ApplicationState extends ProcessLauncherState {
@Param
private TracerImplementation tracerImplementation;
public ApplicationState() {
super("target", "--server.port=0");
}
@TearDown(Level.Iteration)
public void stop() throws Exception {
super.after();
}
}
}

View File

@@ -1,208 +0,0 @@
/*
* Copyright 2013-2021 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
*
* https://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 org.springframework.cloud.sleuth.benchmarks.jmh.stream;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.TimeUnit;
import brave.Tracing;
import jmh.mbr.junit5.Microbenchmark;
import org.awaitility.Awaitility;
import org.junit.platform.commons.annotation.Testable;
import org.openjdk.jmh.annotations.Benchmark;
import org.openjdk.jmh.annotations.BenchmarkMode;
import org.openjdk.jmh.annotations.Fork;
import org.openjdk.jmh.annotations.Measurement;
import org.openjdk.jmh.annotations.Mode;
import org.openjdk.jmh.annotations.OutputTimeUnit;
import org.openjdk.jmh.annotations.Param;
import org.openjdk.jmh.annotations.Scope;
import org.openjdk.jmh.annotations.Setup;
import org.openjdk.jmh.annotations.State;
import org.openjdk.jmh.annotations.TearDown;
import org.openjdk.jmh.annotations.Warmup;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.WebApplicationType;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.cloud.sleuth.Tracer;
import org.springframework.cloud.sleuth.benchmarks.app.stream.SleuthBenchmarkingStreamApplication;
import org.springframework.cloud.sleuth.benchmarks.jmh.Pair;
import org.springframework.cloud.sleuth.benchmarks.jmh.TracerImplementation;
import org.springframework.cloud.stream.binder.test.InputDestination;
import org.springframework.cloud.stream.binder.test.OutputDestination;
import org.springframework.cloud.stream.binder.test.TestChannelBinderConfiguration;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.messaging.Message;
import org.springframework.messaging.support.MessageBuilder;
import static org.assertj.core.api.Assertions.assertThat;
@Measurement(iterations = 10, time = 1)
@Warmup(iterations = 10, time = 1)
@Fork(4)
@BenchmarkMode(Mode.SampleTime)
@OutputTimeUnit(TimeUnit.MILLISECONDS)
@Microbenchmark
public class MicroBenchmarkStreamTests {
@Benchmark
@Testable
public void testStream(BenchmarkContext context) throws Exception {
context.run();
}
@State(Scope.Benchmark)
public static class BenchmarkContext {
volatile ConfigurableApplicationContext applicationContext;
volatile InputDestination input;
volatile OutputDestination output;
@Param
private Instrumentation instrumentation;
@Param
private TracerImplementation tracerImplementation;
@Setup
public void setup() {
this.applicationContext = initContext();
this.input = this.applicationContext.getBean(InputDestination.class);
this.output = this.applicationContext.getBean(OutputDestination.class);
}
private void sendInputMessage() {
// System.out.println("Sending the message to input");
input.send(MessageBuilder.withPayload("hello".getBytes())
.setHeader("b3", "4883117762eb9420-4883117762eb9420-1").build());
}
protected ConfigurableApplicationContext initContext() {
SpringApplication application = new SpringApplicationBuilder(SleuthBenchmarkingStreamApplication.class)
.web(WebApplicationType.NONE).application();
return application.run(runArgs());
}
protected String[] runArgs() {
List<String> strings = new ArrayList<>();
strings.addAll(Arrays.asList("--spring.jmx.enabled=false",
"--spring.application.name=defaultTraceContextForStream" + instrumentation.name() + "_"
+ tracerImplementation.name()));
strings.addAll(Arrays.asList(instrumentation.asParams()));
return strings.toArray(new String[0]);
}
void run() {
sendInputMessage();
Awaitility.await().untilAsserted(this::assertThatOutputMessageGotReceived);
}
private void assertThatOutputMessageGotReceived() {
// System.out.println("Retrieving the message for tests");
Message<byte[]> message = output.receive(1L);
// System.out.println("Got the message from output");
assertThat(message).isNotNull();
// System.out.println("Message is not null");
assertThat(message.getPayload()).isEqualTo("HELLO".getBytes());
// System.out.println("Payload is HELLO");
if (!instrumentation.toString().toLowerCase().contains("nosleuth")) {
String b3 = message.getHeaders().get("b3", String.class);
// System.out.println("Checking the b3 header [" + b3 + "]");
assertThat(b3).isNotEmpty();
if (b3.startsWith("0000000000000000")) {
assertThat(b3).startsWith("00000000000000004883117762eb9420");
} else {
assertThat(b3).startsWith("4883117762eb9420");
}
assertThat(this.applicationContext.getBean(Tracer.class).currentSpan()).isNull();
}
}
@TearDown
public void clean() throws Exception {
Tracing current = Tracing.current();
if (current != null) {
current.close();
}
try {
this.applicationContext.close();
}
catch (Exception ig) {
}
}
public enum Instrumentation {
// @formatter:off
// noSleuthSimple(Pair.noSleuth(), function("simple")),
// sleuthSimpleOnQueues(function("simple"), Pair.onHook()),
// sleuthSimpleManual(function("simple_manual"), Pair.manual(), functionDisabled(), integrationDisabled()),
// sleuthSimpleNoFunctionInstrumentationManual(function("simple_manual"), Pair.manual(), functionDisabled(), integrationDisabled()),
// sleuthSimpleOnEach(function("simple"), Pair.onEach()),
// sleuthSimpleOnLast(function("simple"), Pair.onLast()),
// sleuthSimpleWithAroundOnQueues(function("simple_function_with_around")),
// noSleuthReactiveSimple(function("reactive_simple"), Pair.noSleuth()),
sleuthReactiveSimpleOnQueues(function("DECORATE_QUEUES"), Pair.decorateQueues()),
sleuthReactiveSimpleOnEach(function("DECORATE_ON_EACH"), Pair.onEach()),
sleuthReactiveSimpleManual(function("reactive_simple_manual"), Pair.manual()),
sleuthReactiveSimpleNoFunctionInstrumentationManual(function("reactive_simple_manual"), Pair.manual(), integrationDisabled(), functionDisabled());
// @formatter:on
private final List<Pair> pairs;
Instrumentation(Pair... pairs) {
this.pairs = Arrays.asList(pairs);
}
String[] asParams() {
return this.pairs.stream().map(p -> "--" + p.asProp()).toArray(String[]::new);
}
static Pair function(String type) {
return Pair.of("spring.sleuth.function.type", type);
}
static Pair integrationEnabled() {
return Pair.of("spring.sleuth.integration.enabled", "true");
}
static Pair integrationDisabled() {
return Pair.of("spring.sleuth.integration.enabled", "false");
}
static Pair functionDisabled() {
return Pair.of("spring.sleuth.function.enabled", "false");
}
}
}
@Configuration(proxyBeanMethods = false)
@Import(TestChannelBinderConfiguration.class)
static class TestConfiguration {
}
}

View File

@@ -1,156 +0,0 @@
/*
* Copyright 2013-2021 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
*
* https://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 org.springframework.cloud.sleuth.benchmarks.jmh.webflux;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
import brave.Tracing;
import jmh.mbr.junit5.Microbenchmark;
import org.junit.platform.commons.annotation.Testable;
import org.openjdk.jmh.annotations.Benchmark;
import org.openjdk.jmh.annotations.BenchmarkMode;
import org.openjdk.jmh.annotations.Fork;
import org.openjdk.jmh.annotations.Measurement;
import org.openjdk.jmh.annotations.Mode;
import org.openjdk.jmh.annotations.OutputTimeUnit;
import org.openjdk.jmh.annotations.Param;
import org.openjdk.jmh.annotations.Scope;
import org.openjdk.jmh.annotations.Setup;
import org.openjdk.jmh.annotations.State;
import org.openjdk.jmh.annotations.TearDown;
import org.openjdk.jmh.annotations.Warmup;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.WebApplicationType;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.cloud.sleuth.Tracer;
import org.springframework.cloud.sleuth.benchmarks.app.webflux.SleuthBenchmarkingSpringWebFluxApp;
import org.springframework.cloud.sleuth.benchmarks.jmh.Pair;
import org.springframework.cloud.sleuth.benchmarks.jmh.TracerImplementation;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.test.web.reactive.server.WebTestClient;
import static org.assertj.core.api.Assertions.assertThat;
@Measurement(iterations = 10, time = 1)
@Warmup(iterations = 10, time = 1)
@Fork(4)
@BenchmarkMode(Mode.SampleTime)
@OutputTimeUnit(TimeUnit.MILLISECONDS)
@Microbenchmark
public class MicroBenchmarkHttpTests {
@Benchmark
@Testable
public void test(BenchmarkContext context) throws Exception {
context.run();
}
@State(Scope.Benchmark)
public static class BenchmarkContext {
volatile ConfigurableApplicationContext applicationContext;
volatile WebTestClient webTestClient;
@Param
private Instrumentation instrumentation;
@Param
private TracerImplementation tracerImplementation;
@Setup
public void setup() {
this.applicationContext = initContext();
this.webTestClient = WebTestClient.bindToApplicationContext(applicationContext).build();
}
protected ConfigurableApplicationContext initContext() {
SpringApplication application = new SpringApplicationBuilder(SleuthBenchmarkingSpringWebFluxApp.class)
.web(WebApplicationType.REACTIVE).application();
return application.run(runArgs());
}
protected String[] runArgs() {
String[] defaultArgs = new String[] { "--spring.jmx.enabled=false",
"--spring.application.name=defaultTraceContext" + instrumentation.name() + "_"
+ tracerImplementation.name() };
List<String> list = new ArrayList<>(Arrays.asList(defaultArgs));
list.addAll(Arrays.asList(instrumentation.asParams()));
return list.toArray(new String[0]);
}
void run() {
this.webTestClient.get().uri(instrumentation.url).header("X-B3-TraceId", "4883117762eb9420")
.header("X-B3-SpanId", "4883117762eb9420").exchange().expectStatus().isOk();
if (this.instrumentation.name().toLowerCase().contains("nosleuth")) {
assertThat(this.applicationContext.getBeanProvider(Tracer.class).getIfAvailable(() -> null)).isNull();
} else {
assertThat(this.applicationContext.getBean(Tracer.class).currentSpan()).isNull();
}
}
@TearDown
public void clean() throws Exception {
Tracing current = Tracing.current();
if (current != null) {
current.close();
}
try {
this.applicationContext.close();
}
catch (Exception ig) {
}
}
public enum Instrumentation {
// @formatter:off
noSleuthSimple("/simple", Pair.noSleuth()),
onQueuesSimple("/simple", Pair.onHook()),
onManualSimple("/simpleManual", Pair.manual()),
onEachSimple("/simple", Pair.onEach()),
onLastSimple("/simple", Pair.onLast()),
noSleuthComplex("/complexNoSleuth", Pair.noSleuth()),
onQueueComplex("/complex", Pair.onHook()),
onManualComplex("/complexManual", Pair.manual()),
onEachComplex("/complex", Pair.onEach()),
onLastComplex("/complex", Pair.onLast());
// @formatter:on
private String url;
private List<Pair> pairs;
Instrumentation(String url, Pair... pairs) {
this.url = url;
this.pairs = Arrays.asList(pairs);
}
String[] asParams() {
return this.pairs.stream().map(p -> "--" + p.asProp()).collect(Collectors.toList()).toArray(new String[0]);
}
}
}
}

View File

@@ -1,183 +0,0 @@
/*
* Copyright 2013-2021 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
*
* https://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 org.springframework.cloud.sleuth.benchmarks.jmh.webflux;
import java.io.IOException;
import java.util.concurrent.TimeUnit;
import brave.Tracing;
import brave.handler.SpanHandler;
import brave.http.HttpTracing;
import brave.httpclient.TracingHttpClientBuilder;
import brave.propagation.CurrentTraceContext;
import brave.propagation.TraceContext;
import brave.sampler.Sampler;
import jmh.mbr.junit5.Microbenchmark;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;
import org.openjdk.jmh.annotations.Benchmark;
import org.openjdk.jmh.annotations.BenchmarkMode;
import org.openjdk.jmh.annotations.Fork;
import org.openjdk.jmh.annotations.Measurement;
import org.openjdk.jmh.annotations.Mode;
import org.openjdk.jmh.annotations.OutputTimeUnit;
import org.openjdk.jmh.annotations.Scope;
import org.openjdk.jmh.annotations.Setup;
import org.openjdk.jmh.annotations.State;
import org.openjdk.jmh.annotations.TearDown;
import org.openjdk.jmh.annotations.Threads;
import org.openjdk.jmh.annotations.Warmup;
import org.openjdk.jmh.runner.Runner;
import org.openjdk.jmh.runner.RunnerException;
import org.openjdk.jmh.runner.options.Options;
import org.openjdk.jmh.runner.options.OptionsBuilder;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.WebApplicationType;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.cloud.sleuth.benchmarks.app.webflux.SleuthBenchmarkingSpringWebFluxApp;
import org.springframework.cloud.sleuth.benchmarks.jmh.TracerImplementation;
import org.springframework.context.ConfigurableApplicationContext;
@Measurement(iterations = 5, time = 1)
@Warmup(iterations = 5, time = 1)
@Fork(2)
@BenchmarkMode(Mode.SampleTime)
@OutputTimeUnit(TimeUnit.MICROSECONDS)
@Threads(2)
@State(Scope.Benchmark)
@Microbenchmark
public abstract class SpringWebFluxBenchmarksTests {
static final SpanHandler FAKE_SPAN_HANDLER = new SpanHandler() {
// intentionally anonymous to prevent logging fallback on NOOP
};
protected static TraceContext defaultTraceContext = TraceContext.newBuilder().traceIdHigh(333L).traceId(444L)
.spanId(3).sampled(true).build();
protected ConfigurableApplicationContext applicationContext;
protected SleuthBenchmarkingSpringWebFluxApp springWebFluxApp;
CloseableHttpClient client;
CloseableHttpClient tracedClient;
CloseableHttpClient unsampledClient;
private String baseUrl;
public static void main(String[] args) throws RunnerException {
Options opt = new OptionsBuilder().include(".*" + SpringWebFluxBenchmarksTests.class.getSimpleName() + ".*")
.build();
new Runner(opt).run();
}
public String getBaseUrl() {
return baseUrl;
}
protected CloseableHttpClient newClient(HttpTracing httpTracing) {
return TracingHttpClientBuilder.create(httpTracing).disableAutomaticRetries().build();
}
protected CloseableHttpClient newClient() {
return HttpClients.custom().disableAutomaticRetries().build();
}
protected void get(CloseableHttpClient client) throws Exception {
EntityUtils.consume(client.execute(new HttpGet(getBaseUrl())).getEntity());
}
protected void close(CloseableHttpClient client) throws IOException {
client.close();
}
@Setup
public void setup() {
ConfigurableApplicationContext context = initContext();
this.applicationContext = context;
this.springWebFluxApp = this.applicationContext.getBean(SleuthBenchmarkingSpringWebFluxApp.class);
baseUrl = "http://127.0.0.1:" + springWebFluxApp.port + "/foo";
client = newClient();
tracedClient = newClient(HttpTracing.create(Tracing.newBuilder().addSpanHandler(FAKE_SPAN_HANDLER).build()));
unsampledClient = newClient(HttpTracing
.create(Tracing.newBuilder().sampler(Sampler.NEVER_SAMPLE).addSpanHandler(FAKE_SPAN_HANDLER).build()));
postSetUp();
}
protected ConfigurableApplicationContext initContext() {
SpringApplication application = new SpringApplicationBuilder(SleuthBenchmarkingSpringWebFluxApp.class)
.web(WebApplicationType.REACTIVE).application();
customSpringApplication(application);
return application.run(runArgs());
}
protected void customSpringApplication(SpringApplication springApplication) {
}
protected void postSetUp() {
}
protected String[] runArgs() {
return new String[] { "--spring.jmx.enabled=false", "--spring.application.name=defaultTraceContext",
TracerImplementation.brave.toString(), "--spring.sleuth.enabled=true" };
}
@TearDown
public void clean() throws Exception {
close(client);
close(unsampledClient);
close(tracedClient);
Tracing.current().close();
try {
this.applicationContext.close();
}
catch (Exception ig) {
}
}
@Benchmark
public void client_get() throws Exception {
get(client);
}
@Benchmark
public void unsampledClient_get() throws Exception {
get(unsampledClient);
}
@Benchmark
public void tracedClient_get() throws Exception {
get(tracedClient);
}
@Benchmark
public void tracedClient_get_resumeTrace() throws Exception {
try (CurrentTraceContext.Scope scope = Tracing.current().currentTraceContext().newScope(defaultTraceContext)) {
get(tracedClient);
}
}
}

View File

@@ -1,54 +0,0 @@
/*
* Copyright 2013-2021 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
*
* https://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 org.springframework.cloud.sleuth.benchmarks.jmh.webflux;
import jmh.mbr.junit5.Microbenchmark;
import org.openjdk.jmh.runner.Runner;
import org.openjdk.jmh.runner.RunnerException;
import org.openjdk.jmh.runner.options.Options;
import org.openjdk.jmh.runner.options.OptionsBuilder;
import org.springframework.cloud.sleuth.benchmarks.jmh.TracerImplementation;
/**
* @author alvin
*/
@Microbenchmark
public class WithOutReactorSleuthSpringWebFluxBenchmarksTests extends SpringWebFluxBenchmarksTests {
public static void main(String[] args) throws RunnerException {
Options opt = new OptionsBuilder()
.include(".*" + WithOutReactorSleuthSpringWebFluxBenchmarksTests.class.getSimpleName() + ".*").build();
new Runner(opt).run();
}
@Override
protected String[] runArgs() {
return new String[] { "--spring.jmx.enabled=false", "--spring.application.name=defaultTraceContext",
TracerImplementation.brave.toString(), "--spring.sleuth.enabled=true",
"--spring.sleuth.reactor.enabled=false"
};
}
@Override
protected void postSetUp() {
super.postSetUp();
}
}

View File

@@ -1,51 +0,0 @@
/*
* Copyright 2013-2021 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
*
* https://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 org.springframework.cloud.sleuth.benchmarks.jmh.webflux;
import jmh.mbr.junit5.Microbenchmark;
import org.openjdk.jmh.runner.Runner;
import org.openjdk.jmh.runner.RunnerException;
import org.openjdk.jmh.runner.options.Options;
import org.openjdk.jmh.runner.options.OptionsBuilder;
import org.springframework.cloud.sleuth.benchmarks.jmh.TracerImplementation;
/**
* @author alvin
*/
@Microbenchmark
public class WithOutSleuthSpringWebFluxBenchmarksTests extends SpringWebFluxBenchmarksTests {
public static void main(String[] args) throws RunnerException {
Options opt = new OptionsBuilder()
.include(".*" + WithOutSleuthSpringWebFluxBenchmarksTests.class.getSimpleName() + ".*").build();
new Runner(opt).run();
}
@Override
protected String[] runArgs() {
return new String[] { "--spring.jmx.enabled=false", "--spring.application.name=defaultTraceContext",
TracerImplementation.brave.toString(), "--spring.sleuth.enabled=false" };
}
@Override
protected void postSetUp() {
super.postSetUp();
}
}

View File

@@ -1,334 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<jmeterTestPlan version="1.2" properties="2.8" jmeter="2.13 r1665067">
<hashTree>
<TestPlan guiclass="TestPlanGui" testclass="TestPlan" testname="Sleuth performance tests" enabled="true">
<stringProp name="TestPlan.comments"></stringProp>
<boolProp name="TestPlan.functional_mode">false</boolProp>
<boolProp name="TestPlan.serialize_threadgroups">false</boolProp>
<elementProp name="TestPlan.user_defined_variables" elementType="Arguments" guiclass="ArgumentsPanel" testclass="Arguments" testname="User Defined Variables" enabled="true">
<collectionProp name="Arguments.arguments"/>
</elementProp>
<stringProp name="TestPlan.user_define_classpath"></stringProp>
</TestPlan>
<hashTree>
<ConfigTestElement guiclass="HttpDefaultsGui" testclass="ConfigTestElement" testname="Localhost default" enabled="true">
<elementProp name="HTTPsampler.Arguments" elementType="Arguments" guiclass="HTTPArgumentsPanel" testclass="Arguments" testname="User Defined Variables" enabled="true">
<collectionProp name="Arguments.arguments"/>
</elementProp>
<stringProp name="HTTPSampler.domain">localhost</stringProp>
<stringProp name="HTTPSampler.port"></stringProp>
<stringProp name="HTTPSampler.connect_timeout"></stringProp>
<stringProp name="HTTPSampler.response_timeout"></stringProp>
<stringProp name="HTTPSampler.protocol"></stringProp>
<stringProp name="HTTPSampler.contentEncoding"></stringProp>
<stringProp name="HTTPSampler.path"></stringProp>
<stringProp name="HTTPSampler.concurrentPool">4</stringProp>
</ConfigTestElement>
<hashTree/>
<ThreadGroup guiclass="ThreadGroupGui" testclass="ThreadGroup" testname="Async_HTTP" enabled="true">
<stringProp name="ThreadGroup.on_sample_error">continue</stringProp>
<elementProp name="ThreadGroup.main_controller" elementType="LoopController" guiclass="LoopControlPanel" testclass="LoopController" testname="Loop Controller" enabled="true">
<boolProp name="LoopController.continue_forever">false</boolProp>
<stringProp name="LoopController.loops">1000</stringProp>
</elementProp>
<stringProp name="ThreadGroup.num_threads">100</stringProp>
<stringProp name="ThreadGroup.ramp_time">5</stringProp>
<longProp name="ThreadGroup.start_time">1458745466000</longProp>
<longProp name="ThreadGroup.end_time">1458745466000</longProp>
<boolProp name="ThreadGroup.scheduler">false</boolProp>
<stringProp name="ThreadGroup.duration"></stringProp>
<stringProp name="ThreadGroup.delay"></stringProp>
</ThreadGroup>
<hashTree>
<HTTPSamplerProxy guiclass="HttpTestSampleGui" testclass="HTTPSamplerProxy" testname="Async HTTP without Sleuth" enabled="true">
<elementProp name="HTTPsampler.Arguments" elementType="Arguments" guiclass="HTTPArgumentsPanel" testclass="Arguments" testname="User Defined Variables" enabled="true">
<collectionProp name="Arguments.arguments"/>
</elementProp>
<stringProp name="HTTPSampler.domain"></stringProp>
<stringProp name="HTTPSampler.port">9875</stringProp>
<stringProp name="HTTPSampler.connect_timeout"></stringProp>
<stringProp name="HTTPSampler.response_timeout"></stringProp>
<stringProp name="HTTPSampler.protocol"></stringProp>
<stringProp name="HTTPSampler.contentEncoding"></stringProp>
<stringProp name="HTTPSampler.path">/bar</stringProp>
<stringProp name="HTTPSampler.method">GET</stringProp>
<boolProp name="HTTPSampler.follow_redirects">true</boolProp>
<boolProp name="HTTPSampler.auto_redirects">false</boolProp>
<boolProp name="HTTPSampler.use_keepalive">true</boolProp>
<boolProp name="HTTPSampler.DO_MULTIPART_POST">false</boolProp>
<boolProp name="HTTPSampler.monitor">false</boolProp>
<stringProp name="HTTPSampler.embedded_url_re"></stringProp>
</HTTPSamplerProxy>
<hashTree/>
<HTTPSamplerProxy guiclass="HttpTestSampleGui" testclass="HTTPSamplerProxy" testname="Async HTTP with Sleuth" enabled="true">
<elementProp name="HTTPsampler.Arguments" elementType="Arguments" guiclass="HTTPArgumentsPanel" testclass="Arguments" testname="User Defined Variables" enabled="true">
<collectionProp name="Arguments.arguments"/>
</elementProp>
<stringProp name="HTTPSampler.domain"></stringProp>
<stringProp name="HTTPSampler.port">9876</stringProp>
<stringProp name="HTTPSampler.connect_timeout"></stringProp>
<stringProp name="HTTPSampler.response_timeout"></stringProp>
<stringProp name="HTTPSampler.protocol"></stringProp>
<stringProp name="HTTPSampler.contentEncoding"></stringProp>
<stringProp name="HTTPSampler.path">/bar</stringProp>
<stringProp name="HTTPSampler.method">GET</stringProp>
<boolProp name="HTTPSampler.follow_redirects">true</boolProp>
<boolProp name="HTTPSampler.auto_redirects">false</boolProp>
<boolProp name="HTTPSampler.use_keepalive">true</boolProp>
<boolProp name="HTTPSampler.DO_MULTIPART_POST">false</boolProp>
<boolProp name="HTTPSampler.monitor">false</boolProp>
<stringProp name="HTTPSampler.embedded_url_re"></stringProp>
</HTTPSamplerProxy>
<hashTree/>
<ResponseAssertion guiclass="AssertionGui" testclass="ResponseAssertion" testname="Response Assertion" enabled="true">
<collectionProp name="Asserion.test_strings">
<stringProp name="97299">bar</stringProp>
</collectionProp>
<stringProp name="Assertion.test_field">Assertion.response_data</stringProp>
<boolProp name="Assertion.assume_success">false</boolProp>
<intProp name="Assertion.test_type">8</intProp>
<stringProp name="Assertion.scope">all</stringProp>
</ResponseAssertion>
<hashTree/>
<ResultCollector guiclass="RespTimeGraphVisualizer" testclass="ResultCollector" testname="Response Time Graph" enabled="true">
<boolProp name="ResultCollector.error_logging">false</boolProp>
<objProp>
<name>saveConfig</name>
<value class="SampleSaveConfiguration">
<time>true</time>
<latency>true</latency>
<timestamp>true</timestamp>
<success>true</success>
<label>true</label>
<code>true</code>
<message>true</message>
<threadName>true</threadName>
<dataType>true</dataType>
<encoding>false</encoding>
<assertions>true</assertions>
<subresults>true</subresults>
<responseData>false</responseData>
<samplerData>false</samplerData>
<xml>false</xml>
<fieldNames>false</fieldNames>
<responseHeaders>false</responseHeaders>
<requestHeaders>false</requestHeaders>
<responseDataOnError>false</responseDataOnError>
<saveAssertionResultsFailureMessage>false</saveAssertionResultsFailureMessage>
<assertionsResultsToSave>0</assertionsResultsToSave>
<bytes>true</bytes>
<threadCounts>true</threadCounts>
</value>
</objProp>
<stringProp name="filename"></stringProp>
<stringProp name="RespTimeGraph.interval">100</stringProp>
<intProp name="RespTimeGraph.linestrockwidth">0</intProp>
<intProp name="RespTimeGraph.lineshapepoint">4</intProp>
<stringProp name="RespTimeGraph.xaxistimeformat">HH:mm:ss.SSS</stringProp>
<stringProp name="RespTimeGraph.yaxisscaleincrement">10</stringProp>
</ResultCollector>
<hashTree/>
<ResultCollector guiclass="TableVisualizer" testclass="ResultCollector" testname="View Results in Table" enabled="true">
<boolProp name="ResultCollector.error_logging">false</boolProp>
<objProp>
<name>saveConfig</name>
<value class="SampleSaveConfiguration">
<time>true</time>
<latency>true</latency>
<timestamp>true</timestamp>
<success>true</success>
<label>true</label>
<code>true</code>
<message>true</message>
<threadName>true</threadName>
<dataType>true</dataType>
<encoding>false</encoding>
<assertions>true</assertions>
<subresults>true</subresults>
<responseData>false</responseData>
<samplerData>false</samplerData>
<xml>false</xml>
<fieldNames>false</fieldNames>
<responseHeaders>false</responseHeaders>
<requestHeaders>false</requestHeaders>
<responseDataOnError>false</responseDataOnError>
<saveAssertionResultsFailureMessage>false</saveAssertionResultsFailureMessage>
<assertionsResultsToSave>0</assertionsResultsToSave>
<bytes>true</bytes>
<threadCounts>true</threadCounts>
</value>
</objProp>
<stringProp name="filename"></stringProp>
</ResultCollector>
<hashTree/>
<ResultCollector guiclass="StatGraphVisualizer" testclass="ResultCollector" testname="Aggregate Graph" enabled="true">
<boolProp name="ResultCollector.error_logging">false</boolProp>
<objProp>
<name>saveConfig</name>
<value class="SampleSaveConfiguration">
<time>true</time>
<latency>true</latency>
<timestamp>true</timestamp>
<success>true</success>
<label>true</label>
<code>true</code>
<message>true</message>
<threadName>true</threadName>
<dataType>true</dataType>
<encoding>false</encoding>
<assertions>true</assertions>
<subresults>true</subresults>
<responseData>false</responseData>
<samplerData>false</samplerData>
<xml>false</xml>
<fieldNames>false</fieldNames>
<responseHeaders>false</responseHeaders>
<requestHeaders>false</requestHeaders>
<responseDataOnError>false</responseDataOnError>
<saveAssertionResultsFailureMessage>false</saveAssertionResultsFailureMessage>
<assertionsResultsToSave>0</assertionsResultsToSave>
<bytes>true</bytes>
<threadCounts>true</threadCounts>
</value>
</objProp>
<stringProp name="filename"></stringProp>
</ResultCollector>
<hashTree/>
<ResultCollector guiclass="StatVisualizer" testclass="ResultCollector" testname="Aggregate Report" enabled="true">
<boolProp name="ResultCollector.error_logging">false</boolProp>
<objProp>
<name>saveConfig</name>
<value class="SampleSaveConfiguration">
<time>true</time>
<latency>true</latency>
<timestamp>true</timestamp>
<success>true</success>
<label>true</label>
<code>true</code>
<message>true</message>
<threadName>true</threadName>
<dataType>true</dataType>
<encoding>false</encoding>
<assertions>true</assertions>
<subresults>true</subresults>
<responseData>false</responseData>
<samplerData>false</samplerData>
<xml>false</xml>
<fieldNames>false</fieldNames>
<responseHeaders>false</responseHeaders>
<requestHeaders>false</requestHeaders>
<responseDataOnError>false</responseDataOnError>
<saveAssertionResultsFailureMessage>false</saveAssertionResultsFailureMessage>
<assertionsResultsToSave>0</assertionsResultsToSave>
<bytes>true</bytes>
<threadCounts>true</threadCounts>
</value>
</objProp>
<stringProp name="filename"></stringProp>
</ResultCollector>
<hashTree/>
<Summariser guiclass="SummariserGui" testclass="Summariser" testname="Async HTTP Results" enabled="true"/>
<hashTree/>
</hashTree>
<ResultCollector guiclass="SummaryReport" testclass="ResultCollector" testname="Summary Report" enabled="true">
<boolProp name="ResultCollector.error_logging">false</boolProp>
<objProp>
<name>saveConfig</name>
<value class="SampleSaveConfiguration">
<time>true</time>
<latency>true</latency>
<timestamp>true</timestamp>
<success>true</success>
<label>true</label>
<code>true</code>
<message>true</message>
<threadName>true</threadName>
<dataType>true</dataType>
<encoding>false</encoding>
<assertions>true</assertions>
<subresults>true</subresults>
<responseData>false</responseData>
<samplerData>false</samplerData>
<xml>false</xml>
<fieldNames>false</fieldNames>
<responseHeaders>false</responseHeaders>
<requestHeaders>false</requestHeaders>
<responseDataOnError>false</responseDataOnError>
<saveAssertionResultsFailureMessage>false</saveAssertionResultsFailureMessage>
<assertionsResultsToSave>0</assertionsResultsToSave>
<bytes>true</bytes>
<threadCounts>true</threadCounts>
</value>
</objProp>
<stringProp name="filename"></stringProp>
</ResultCollector>
<hashTree/>
<ResultCollector guiclass="StatVisualizer" testclass="ResultCollector" testname="Aggregate Report" enabled="true">
<boolProp name="ResultCollector.error_logging">false</boolProp>
<objProp>
<name>saveConfig</name>
<value class="SampleSaveConfiguration">
<time>true</time>
<latency>true</latency>
<timestamp>true</timestamp>
<success>true</success>
<label>true</label>
<code>true</code>
<message>true</message>
<threadName>true</threadName>
<dataType>true</dataType>
<encoding>false</encoding>
<assertions>true</assertions>
<subresults>true</subresults>
<responseData>false</responseData>
<samplerData>false</samplerData>
<xml>false</xml>
<fieldNames>false</fieldNames>
<responseHeaders>false</responseHeaders>
<requestHeaders>false</requestHeaders>
<responseDataOnError>false</responseDataOnError>
<saveAssertionResultsFailureMessage>false</saveAssertionResultsFailureMessage>
<assertionsResultsToSave>0</assertionsResultsToSave>
<bytes>true</bytes>
<threadCounts>true</threadCounts>
</value>
</objProp>
<stringProp name="filename"></stringProp>
</ResultCollector>
<hashTree/>
<ResultCollector guiclass="ViewResultsFullVisualizer" testclass="ResultCollector" testname="View Results Tree" enabled="true">
<boolProp name="ResultCollector.error_logging">false</boolProp>
<objProp>
<name>saveConfig</name>
<value class="SampleSaveConfiguration">
<time>true</time>
<latency>true</latency>
<timestamp>true</timestamp>
<success>true</success>
<label>true</label>
<code>true</code>
<message>true</message>
<threadName>true</threadName>
<dataType>true</dataType>
<encoding>false</encoding>
<assertions>true</assertions>
<subresults>true</subresults>
<responseData>false</responseData>
<samplerData>false</samplerData>
<xml>false</xml>
<fieldNames>false</fieldNames>
<responseHeaders>false</responseHeaders>
<requestHeaders>false</requestHeaders>
<responseDataOnError>false</responseDataOnError>
<saveAssertionResultsFailureMessage>false</saveAssertionResultsFailureMessage>
<assertionsResultsToSave>0</assertionsResultsToSave>
<bytes>true</bytes>
<threadCounts>true</threadCounts>
</value>
</objProp>
<stringProp name="filename"></stringProp>
</ResultCollector>
<hashTree/>
</hashTree>
</hashTree>
</jmeterTestPlan>

View File

@@ -1,334 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<jmeterTestPlan version="1.2" properties="2.8" jmeter="2.13 r1665067">
<hashTree>
<TestPlan guiclass="TestPlanGui" testclass="TestPlan" testname="Sleuth performance tests" enabled="true">
<stringProp name="TestPlan.comments"></stringProp>
<boolProp name="TestPlan.functional_mode">false</boolProp>
<boolProp name="TestPlan.serialize_threadgroups">false</boolProp>
<elementProp name="TestPlan.user_defined_variables" elementType="Arguments" guiclass="ArgumentsPanel" testclass="Arguments" testname="User Defined Variables" enabled="true">
<collectionProp name="Arguments.arguments"/>
</elementProp>
<stringProp name="TestPlan.user_define_classpath"></stringProp>
</TestPlan>
<hashTree>
<ConfigTestElement guiclass="HttpDefaultsGui" testclass="ConfigTestElement" testname="Localhost default" enabled="true">
<elementProp name="HTTPsampler.Arguments" elementType="Arguments" guiclass="HTTPArgumentsPanel" testclass="Arguments" testname="User Defined Variables" enabled="true">
<collectionProp name="Arguments.arguments"/>
</elementProp>
<stringProp name="HTTPSampler.domain">localhost</stringProp>
<stringProp name="HTTPSampler.port"></stringProp>
<stringProp name="HTTPSampler.connect_timeout"></stringProp>
<stringProp name="HTTPSampler.response_timeout"></stringProp>
<stringProp name="HTTPSampler.protocol"></stringProp>
<stringProp name="HTTPSampler.contentEncoding"></stringProp>
<stringProp name="HTTPSampler.path"></stringProp>
<stringProp name="HTTPSampler.concurrentPool">4</stringProp>
</ConfigTestElement>
<hashTree/>
<ThreadGroup guiclass="ThreadGroupGui" testclass="ThreadGroup" testname="Async_method" enabled="true">
<stringProp name="ThreadGroup.on_sample_error">continue</stringProp>
<elementProp name="ThreadGroup.main_controller" elementType="LoopController" guiclass="LoopControlPanel" testclass="LoopController" testname="Loop Controller" enabled="true">
<boolProp name="LoopController.continue_forever">false</boolProp>
<stringProp name="LoopController.loops">1000</stringProp>
</elementProp>
<stringProp name="ThreadGroup.num_threads">100</stringProp>
<stringProp name="ThreadGroup.ramp_time">20</stringProp>
<longProp name="ThreadGroup.start_time">1458745466000</longProp>
<longProp name="ThreadGroup.end_time">1458745466000</longProp>
<boolProp name="ThreadGroup.scheduler">false</boolProp>
<stringProp name="ThreadGroup.duration"></stringProp>
<stringProp name="ThreadGroup.delay"></stringProp>
</ThreadGroup>
<hashTree>
<HTTPSamplerProxy guiclass="HttpTestSampleGui" testclass="HTTPSamplerProxy" testname="Async method without Sleuth" enabled="true">
<elementProp name="HTTPsampler.Arguments" elementType="Arguments" guiclass="HTTPArgumentsPanel" testclass="Arguments" testname="User Defined Variables" enabled="true">
<collectionProp name="Arguments.arguments"/>
</elementProp>
<stringProp name="HTTPSampler.domain"></stringProp>
<stringProp name="HTTPSampler.port">9875</stringProp>
<stringProp name="HTTPSampler.connect_timeout"></stringProp>
<stringProp name="HTTPSampler.response_timeout"></stringProp>
<stringProp name="HTTPSampler.protocol"></stringProp>
<stringProp name="HTTPSampler.contentEncoding"></stringProp>
<stringProp name="HTTPSampler.path">/async</stringProp>
<stringProp name="HTTPSampler.method">GET</stringProp>
<boolProp name="HTTPSampler.follow_redirects">true</boolProp>
<boolProp name="HTTPSampler.auto_redirects">false</boolProp>
<boolProp name="HTTPSampler.use_keepalive">true</boolProp>
<boolProp name="HTTPSampler.DO_MULTIPART_POST">false</boolProp>
<boolProp name="HTTPSampler.monitor">false</boolProp>
<stringProp name="HTTPSampler.embedded_url_re"></stringProp>
</HTTPSamplerProxy>
<hashTree/>
<HTTPSamplerProxy guiclass="HttpTestSampleGui" testclass="HTTPSamplerProxy" testname="Async method with Sleuth" enabled="true">
<elementProp name="HTTPsampler.Arguments" elementType="Arguments" guiclass="HTTPArgumentsPanel" testclass="Arguments" testname="User Defined Variables" enabled="true">
<collectionProp name="Arguments.arguments"/>
</elementProp>
<stringProp name="HTTPSampler.domain"></stringProp>
<stringProp name="HTTPSampler.port">9876</stringProp>
<stringProp name="HTTPSampler.connect_timeout"></stringProp>
<stringProp name="HTTPSampler.response_timeout"></stringProp>
<stringProp name="HTTPSampler.protocol"></stringProp>
<stringProp name="HTTPSampler.contentEncoding"></stringProp>
<stringProp name="HTTPSampler.path">/async</stringProp>
<stringProp name="HTTPSampler.method">GET</stringProp>
<boolProp name="HTTPSampler.follow_redirects">true</boolProp>
<boolProp name="HTTPSampler.auto_redirects">false</boolProp>
<boolProp name="HTTPSampler.use_keepalive">true</boolProp>
<boolProp name="HTTPSampler.DO_MULTIPART_POST">false</boolProp>
<boolProp name="HTTPSampler.monitor">false</boolProp>
<stringProp name="HTTPSampler.embedded_url_re"></stringProp>
</HTTPSamplerProxy>
<hashTree/>
<ResponseAssertion guiclass="AssertionGui" testclass="ResponseAssertion" testname="Response Assertion" enabled="true">
<collectionProp name="Asserion.test_strings">
<stringProp name="93127292">async</stringProp>
</collectionProp>
<stringProp name="Assertion.test_field">Assertion.response_data</stringProp>
<boolProp name="Assertion.assume_success">false</boolProp>
<intProp name="Assertion.test_type">8</intProp>
<stringProp name="Assertion.scope">all</stringProp>
</ResponseAssertion>
<hashTree/>
<ResultCollector guiclass="RespTimeGraphVisualizer" testclass="ResultCollector" testname="Response Time Graph" enabled="true">
<boolProp name="ResultCollector.error_logging">false</boolProp>
<objProp>
<name>saveConfig</name>
<value class="SampleSaveConfiguration">
<time>true</time>
<latency>true</latency>
<timestamp>true</timestamp>
<success>true</success>
<label>true</label>
<code>true</code>
<message>true</message>
<threadName>true</threadName>
<dataType>true</dataType>
<encoding>false</encoding>
<assertions>true</assertions>
<subresults>true</subresults>
<responseData>false</responseData>
<samplerData>false</samplerData>
<xml>false</xml>
<fieldNames>false</fieldNames>
<responseHeaders>false</responseHeaders>
<requestHeaders>false</requestHeaders>
<responseDataOnError>false</responseDataOnError>
<saveAssertionResultsFailureMessage>false</saveAssertionResultsFailureMessage>
<assertionsResultsToSave>0</assertionsResultsToSave>
<bytes>true</bytes>
<threadCounts>true</threadCounts>
</value>
</objProp>
<stringProp name="filename"></stringProp>
<stringProp name="RespTimeGraph.interval">100</stringProp>
<intProp name="RespTimeGraph.linestrockwidth">0</intProp>
<intProp name="RespTimeGraph.lineshapepoint">4</intProp>
<stringProp name="RespTimeGraph.xaxistimeformat">HH:mm:ss.SSS</stringProp>
<stringProp name="RespTimeGraph.yaxisscaleincrement">10</stringProp>
</ResultCollector>
<hashTree/>
<ResultCollector guiclass="TableVisualizer" testclass="ResultCollector" testname="View Results in Table" enabled="true">
<boolProp name="ResultCollector.error_logging">false</boolProp>
<objProp>
<name>saveConfig</name>
<value class="SampleSaveConfiguration">
<time>true</time>
<latency>true</latency>
<timestamp>true</timestamp>
<success>true</success>
<label>true</label>
<code>true</code>
<message>true</message>
<threadName>true</threadName>
<dataType>true</dataType>
<encoding>false</encoding>
<assertions>true</assertions>
<subresults>true</subresults>
<responseData>false</responseData>
<samplerData>false</samplerData>
<xml>false</xml>
<fieldNames>false</fieldNames>
<responseHeaders>false</responseHeaders>
<requestHeaders>false</requestHeaders>
<responseDataOnError>false</responseDataOnError>
<saveAssertionResultsFailureMessage>false</saveAssertionResultsFailureMessage>
<assertionsResultsToSave>0</assertionsResultsToSave>
<bytes>true</bytes>
<threadCounts>true</threadCounts>
</value>
</objProp>
<stringProp name="filename"></stringProp>
</ResultCollector>
<hashTree/>
<ResultCollector guiclass="StatGraphVisualizer" testclass="ResultCollector" testname="Aggregate Graph" enabled="true">
<boolProp name="ResultCollector.error_logging">false</boolProp>
<objProp>
<name>saveConfig</name>
<value class="SampleSaveConfiguration">
<time>true</time>
<latency>true</latency>
<timestamp>true</timestamp>
<success>true</success>
<label>true</label>
<code>true</code>
<message>true</message>
<threadName>true</threadName>
<dataType>true</dataType>
<encoding>false</encoding>
<assertions>true</assertions>
<subresults>true</subresults>
<responseData>false</responseData>
<samplerData>false</samplerData>
<xml>false</xml>
<fieldNames>false</fieldNames>
<responseHeaders>false</responseHeaders>
<requestHeaders>false</requestHeaders>
<responseDataOnError>false</responseDataOnError>
<saveAssertionResultsFailureMessage>false</saveAssertionResultsFailureMessage>
<assertionsResultsToSave>0</assertionsResultsToSave>
<bytes>true</bytes>
<threadCounts>true</threadCounts>
</value>
</objProp>
<stringProp name="filename"></stringProp>
</ResultCollector>
<hashTree/>
<ResultCollector guiclass="StatVisualizer" testclass="ResultCollector" testname="Aggregate Report" enabled="true">
<boolProp name="ResultCollector.error_logging">false</boolProp>
<objProp>
<name>saveConfig</name>
<value class="SampleSaveConfiguration">
<time>true</time>
<latency>true</latency>
<timestamp>true</timestamp>
<success>true</success>
<label>true</label>
<code>true</code>
<message>true</message>
<threadName>true</threadName>
<dataType>true</dataType>
<encoding>false</encoding>
<assertions>true</assertions>
<subresults>true</subresults>
<responseData>false</responseData>
<samplerData>false</samplerData>
<xml>false</xml>
<fieldNames>false</fieldNames>
<responseHeaders>false</responseHeaders>
<requestHeaders>false</requestHeaders>
<responseDataOnError>false</responseDataOnError>
<saveAssertionResultsFailureMessage>false</saveAssertionResultsFailureMessage>
<assertionsResultsToSave>0</assertionsResultsToSave>
<bytes>true</bytes>
<threadCounts>true</threadCounts>
</value>
</objProp>
<stringProp name="filename"></stringProp>
</ResultCollector>
<hashTree/>
<Summariser guiclass="SummariserGui" testclass="Summariser" testname="Async method Results" enabled="true"/>
<hashTree/>
</hashTree>
<ResultCollector guiclass="SummaryReport" testclass="ResultCollector" testname="Summary Report" enabled="true">
<boolProp name="ResultCollector.error_logging">false</boolProp>
<objProp>
<name>saveConfig</name>
<value class="SampleSaveConfiguration">
<time>true</time>
<latency>true</latency>
<timestamp>true</timestamp>
<success>true</success>
<label>true</label>
<code>true</code>
<message>true</message>
<threadName>true</threadName>
<dataType>true</dataType>
<encoding>false</encoding>
<assertions>true</assertions>
<subresults>true</subresults>
<responseData>false</responseData>
<samplerData>false</samplerData>
<xml>false</xml>
<fieldNames>false</fieldNames>
<responseHeaders>false</responseHeaders>
<requestHeaders>false</requestHeaders>
<responseDataOnError>false</responseDataOnError>
<saveAssertionResultsFailureMessage>false</saveAssertionResultsFailureMessage>
<assertionsResultsToSave>0</assertionsResultsToSave>
<bytes>true</bytes>
<threadCounts>true</threadCounts>
</value>
</objProp>
<stringProp name="filename"></stringProp>
</ResultCollector>
<hashTree/>
<ResultCollector guiclass="StatVisualizer" testclass="ResultCollector" testname="Aggregate Report" enabled="true">
<boolProp name="ResultCollector.error_logging">false</boolProp>
<objProp>
<name>saveConfig</name>
<value class="SampleSaveConfiguration">
<time>true</time>
<latency>true</latency>
<timestamp>true</timestamp>
<success>true</success>
<label>true</label>
<code>true</code>
<message>true</message>
<threadName>true</threadName>
<dataType>true</dataType>
<encoding>false</encoding>
<assertions>true</assertions>
<subresults>true</subresults>
<responseData>false</responseData>
<samplerData>false</samplerData>
<xml>false</xml>
<fieldNames>false</fieldNames>
<responseHeaders>false</responseHeaders>
<requestHeaders>false</requestHeaders>
<responseDataOnError>false</responseDataOnError>
<saveAssertionResultsFailureMessage>false</saveAssertionResultsFailureMessage>
<assertionsResultsToSave>0</assertionsResultsToSave>
<bytes>true</bytes>
<threadCounts>true</threadCounts>
</value>
</objProp>
<stringProp name="filename"></stringProp>
</ResultCollector>
<hashTree/>
<ResultCollector guiclass="ViewResultsFullVisualizer" testclass="ResultCollector" testname="View Results Tree" enabled="true">
<boolProp name="ResultCollector.error_logging">false</boolProp>
<objProp>
<name>saveConfig</name>
<value class="SampleSaveConfiguration">
<time>true</time>
<latency>true</latency>
<timestamp>true</timestamp>
<success>true</success>
<label>true</label>
<code>true</code>
<message>true</message>
<threadName>true</threadName>
<dataType>true</dataType>
<encoding>false</encoding>
<assertions>true</assertions>
<subresults>true</subresults>
<responseData>false</responseData>
<samplerData>false</samplerData>
<xml>false</xml>
<fieldNames>false</fieldNames>
<responseHeaders>false</responseHeaders>
<requestHeaders>false</requestHeaders>
<responseDataOnError>false</responseDataOnError>
<saveAssertionResultsFailureMessage>false</saveAssertionResultsFailureMessage>
<assertionsResultsToSave>0</assertionsResultsToSave>
<bytes>true</bytes>
<threadCounts>true</threadCounts>
</value>
</objProp>
<stringProp name="filename"></stringProp>
</ResultCollector>
<hashTree/>
</hashTree>
</hashTree>
</jmeterTestPlan>

View File

@@ -1,334 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<jmeterTestPlan version="1.2" properties="2.8" jmeter="2.13 r1665067">
<hashTree>
<TestPlan guiclass="TestPlanGui" testclass="TestPlan" testname="Sleuth performance tests" enabled="true">
<stringProp name="TestPlan.comments"></stringProp>
<boolProp name="TestPlan.functional_mode">false</boolProp>
<boolProp name="TestPlan.serialize_threadgroups">false</boolProp>
<elementProp name="TestPlan.user_defined_variables" elementType="Arguments" guiclass="ArgumentsPanel" testclass="Arguments" testname="User Defined Variables" enabled="true">
<collectionProp name="Arguments.arguments"/>
</elementProp>
<stringProp name="TestPlan.user_define_classpath"></stringProp>
</TestPlan>
<hashTree>
<ConfigTestElement guiclass="HttpDefaultsGui" testclass="ConfigTestElement" testname="Localhost default" enabled="true">
<elementProp name="HTTPsampler.Arguments" elementType="Arguments" guiclass="HTTPArgumentsPanel" testclass="Arguments" testname="User Defined Variables" enabled="true">
<collectionProp name="Arguments.arguments"/>
</elementProp>
<stringProp name="HTTPSampler.domain">localhost</stringProp>
<stringProp name="HTTPSampler.port"></stringProp>
<stringProp name="HTTPSampler.connect_timeout"></stringProp>
<stringProp name="HTTPSampler.response_timeout"></stringProp>
<stringProp name="HTTPSampler.protocol"></stringProp>
<stringProp name="HTTPSampler.contentEncoding"></stringProp>
<stringProp name="HTTPSampler.path"></stringProp>
<stringProp name="HTTPSampler.concurrentPool">4</stringProp>
</ConfigTestElement>
<hashTree/>
<ThreadGroup guiclass="ThreadGroupGui" testclass="ThreadGroup" testname="Sync_HTTP" enabled="true">
<stringProp name="ThreadGroup.on_sample_error">continue</stringProp>
<elementProp name="ThreadGroup.main_controller" elementType="LoopController" guiclass="LoopControlPanel" testclass="LoopController" testname="Loop Controller" enabled="true">
<boolProp name="LoopController.continue_forever">false</boolProp>
<stringProp name="LoopController.loops">1000</stringProp>
</elementProp>
<stringProp name="ThreadGroup.num_threads">100</stringProp>
<stringProp name="ThreadGroup.ramp_time">20</stringProp>
<longProp name="ThreadGroup.start_time">1458745466000</longProp>
<longProp name="ThreadGroup.end_time">1458745466000</longProp>
<boolProp name="ThreadGroup.scheduler">false</boolProp>
<stringProp name="ThreadGroup.duration"></stringProp>
<stringProp name="ThreadGroup.delay"></stringProp>
</ThreadGroup>
<hashTree>
<HTTPSamplerProxy guiclass="HttpTestSampleGui" testclass="HTTPSamplerProxy" testname="Sync HTTP without Sleuth" enabled="true">
<elementProp name="HTTPsampler.Arguments" elementType="Arguments" guiclass="HTTPArgumentsPanel" testclass="Arguments" testname="User Defined Variables" enabled="true">
<collectionProp name="Arguments.arguments"/>
</elementProp>
<stringProp name="HTTPSampler.domain"></stringProp>
<stringProp name="HTTPSampler.port">9875</stringProp>
<stringProp name="HTTPSampler.connect_timeout"></stringProp>
<stringProp name="HTTPSampler.response_timeout"></stringProp>
<stringProp name="HTTPSampler.protocol"></stringProp>
<stringProp name="HTTPSampler.contentEncoding"></stringProp>
<stringProp name="HTTPSampler.path">/foo</stringProp>
<stringProp name="HTTPSampler.method">GET</stringProp>
<boolProp name="HTTPSampler.follow_redirects">true</boolProp>
<boolProp name="HTTPSampler.auto_redirects">false</boolProp>
<boolProp name="HTTPSampler.use_keepalive">true</boolProp>
<boolProp name="HTTPSampler.DO_MULTIPART_POST">false</boolProp>
<boolProp name="HTTPSampler.monitor">false</boolProp>
<stringProp name="HTTPSampler.embedded_url_re"></stringProp>
</HTTPSamplerProxy>
<hashTree/>
<HTTPSamplerProxy guiclass="HttpTestSampleGui" testclass="HTTPSamplerProxy" testname="Sync HTTP with Sleuth" enabled="true">
<elementProp name="HTTPsampler.Arguments" elementType="Arguments" guiclass="HTTPArgumentsPanel" testclass="Arguments" testname="User Defined Variables" enabled="true">
<collectionProp name="Arguments.arguments"/>
</elementProp>
<stringProp name="HTTPSampler.domain"></stringProp>
<stringProp name="HTTPSampler.port">9876</stringProp>
<stringProp name="HTTPSampler.connect_timeout"></stringProp>
<stringProp name="HTTPSampler.response_timeout"></stringProp>
<stringProp name="HTTPSampler.protocol"></stringProp>
<stringProp name="HTTPSampler.contentEncoding"></stringProp>
<stringProp name="HTTPSampler.path">/foo</stringProp>
<stringProp name="HTTPSampler.method">GET</stringProp>
<boolProp name="HTTPSampler.follow_redirects">true</boolProp>
<boolProp name="HTTPSampler.auto_redirects">false</boolProp>
<boolProp name="HTTPSampler.use_keepalive">true</boolProp>
<boolProp name="HTTPSampler.DO_MULTIPART_POST">false</boolProp>
<boolProp name="HTTPSampler.monitor">false</boolProp>
<stringProp name="HTTPSampler.embedded_url_re"></stringProp>
</HTTPSamplerProxy>
<hashTree/>
<ResponseAssertion guiclass="AssertionGui" testclass="ResponseAssertion" testname="Response Assertion" enabled="true">
<collectionProp name="Asserion.test_strings">
<stringProp name="101574">foo</stringProp>
</collectionProp>
<stringProp name="Assertion.test_field">Assertion.response_data</stringProp>
<boolProp name="Assertion.assume_success">false</boolProp>
<intProp name="Assertion.test_type">8</intProp>
<stringProp name="Assertion.scope">all</stringProp>
</ResponseAssertion>
<hashTree/>
<ResultCollector guiclass="RespTimeGraphVisualizer" testclass="ResultCollector" testname="Response Time Graph" enabled="true">
<boolProp name="ResultCollector.error_logging">false</boolProp>
<objProp>
<name>saveConfig</name>
<value class="SampleSaveConfiguration">
<time>true</time>
<latency>true</latency>
<timestamp>true</timestamp>
<success>true</success>
<label>true</label>
<code>true</code>
<message>true</message>
<threadName>true</threadName>
<dataType>true</dataType>
<encoding>false</encoding>
<assertions>true</assertions>
<subresults>true</subresults>
<responseData>false</responseData>
<samplerData>false</samplerData>
<xml>false</xml>
<fieldNames>false</fieldNames>
<responseHeaders>false</responseHeaders>
<requestHeaders>false</requestHeaders>
<responseDataOnError>false</responseDataOnError>
<saveAssertionResultsFailureMessage>false</saveAssertionResultsFailureMessage>
<assertionsResultsToSave>0</assertionsResultsToSave>
<bytes>true</bytes>
<threadCounts>true</threadCounts>
</value>
</objProp>
<stringProp name="filename"></stringProp>
<stringProp name="RespTimeGraph.interval">100</stringProp>
<intProp name="RespTimeGraph.linestrockwidth">0</intProp>
<intProp name="RespTimeGraph.lineshapepoint">4</intProp>
<stringProp name="RespTimeGraph.xaxistimeformat">HH:mm:ss.SSS</stringProp>
<stringProp name="RespTimeGraph.yaxisscaleincrement">10</stringProp>
</ResultCollector>
<hashTree/>
<ResultCollector guiclass="TableVisualizer" testclass="ResultCollector" testname="View Results in Table" enabled="true">
<boolProp name="ResultCollector.error_logging">false</boolProp>
<objProp>
<name>saveConfig</name>
<value class="SampleSaveConfiguration">
<time>true</time>
<latency>true</latency>
<timestamp>true</timestamp>
<success>true</success>
<label>true</label>
<code>true</code>
<message>true</message>
<threadName>true</threadName>
<dataType>true</dataType>
<encoding>false</encoding>
<assertions>true</assertions>
<subresults>true</subresults>
<responseData>false</responseData>
<samplerData>false</samplerData>
<xml>false</xml>
<fieldNames>false</fieldNames>
<responseHeaders>false</responseHeaders>
<requestHeaders>false</requestHeaders>
<responseDataOnError>false</responseDataOnError>
<saveAssertionResultsFailureMessage>false</saveAssertionResultsFailureMessage>
<assertionsResultsToSave>0</assertionsResultsToSave>
<bytes>true</bytes>
<threadCounts>true</threadCounts>
</value>
</objProp>
<stringProp name="filename"></stringProp>
</ResultCollector>
<hashTree/>
<ResultCollector guiclass="StatGraphVisualizer" testclass="ResultCollector" testname="Aggregate Graph" enabled="true">
<boolProp name="ResultCollector.error_logging">false</boolProp>
<objProp>
<name>saveConfig</name>
<value class="SampleSaveConfiguration">
<time>true</time>
<latency>true</latency>
<timestamp>true</timestamp>
<success>true</success>
<label>true</label>
<code>true</code>
<message>true</message>
<threadName>true</threadName>
<dataType>true</dataType>
<encoding>false</encoding>
<assertions>true</assertions>
<subresults>true</subresults>
<responseData>false</responseData>
<samplerData>false</samplerData>
<xml>false</xml>
<fieldNames>false</fieldNames>
<responseHeaders>false</responseHeaders>
<requestHeaders>false</requestHeaders>
<responseDataOnError>false</responseDataOnError>
<saveAssertionResultsFailureMessage>false</saveAssertionResultsFailureMessage>
<assertionsResultsToSave>0</assertionsResultsToSave>
<bytes>true</bytes>
<threadCounts>true</threadCounts>
</value>
</objProp>
<stringProp name="filename"></stringProp>
</ResultCollector>
<hashTree/>
<ResultCollector guiclass="StatVisualizer" testclass="ResultCollector" testname="Aggregate Report" enabled="true">
<boolProp name="ResultCollector.error_logging">false</boolProp>
<objProp>
<name>saveConfig</name>
<value class="SampleSaveConfiguration">
<time>true</time>
<latency>true</latency>
<timestamp>true</timestamp>
<success>true</success>
<label>true</label>
<code>true</code>
<message>true</message>
<threadName>true</threadName>
<dataType>true</dataType>
<encoding>false</encoding>
<assertions>true</assertions>
<subresults>true</subresults>
<responseData>false</responseData>
<samplerData>false</samplerData>
<xml>false</xml>
<fieldNames>false</fieldNames>
<responseHeaders>false</responseHeaders>
<requestHeaders>false</requestHeaders>
<responseDataOnError>false</responseDataOnError>
<saveAssertionResultsFailureMessage>false</saveAssertionResultsFailureMessage>
<assertionsResultsToSave>0</assertionsResultsToSave>
<bytes>true</bytes>
<threadCounts>true</threadCounts>
</value>
</objProp>
<stringProp name="filename"></stringProp>
</ResultCollector>
<hashTree/>
<Summariser guiclass="SummariserGui" testclass="Summariser" testname="Sync HTTP Results" enabled="true"/>
<hashTree/>
</hashTree>
<ResultCollector guiclass="SummaryReport" testclass="ResultCollector" testname="Summary Report" enabled="true">
<boolProp name="ResultCollector.error_logging">false</boolProp>
<objProp>
<name>saveConfig</name>
<value class="SampleSaveConfiguration">
<time>true</time>
<latency>true</latency>
<timestamp>true</timestamp>
<success>true</success>
<label>true</label>
<code>true</code>
<message>true</message>
<threadName>true</threadName>
<dataType>true</dataType>
<encoding>false</encoding>
<assertions>true</assertions>
<subresults>true</subresults>
<responseData>false</responseData>
<samplerData>false</samplerData>
<xml>false</xml>
<fieldNames>false</fieldNames>
<responseHeaders>false</responseHeaders>
<requestHeaders>false</requestHeaders>
<responseDataOnError>false</responseDataOnError>
<saveAssertionResultsFailureMessage>false</saveAssertionResultsFailureMessage>
<assertionsResultsToSave>0</assertionsResultsToSave>
<bytes>true</bytes>
<threadCounts>true</threadCounts>
</value>
</objProp>
<stringProp name="filename"></stringProp>
</ResultCollector>
<hashTree/>
<ResultCollector guiclass="StatVisualizer" testclass="ResultCollector" testname="Aggregate Report" enabled="true">
<boolProp name="ResultCollector.error_logging">false</boolProp>
<objProp>
<name>saveConfig</name>
<value class="SampleSaveConfiguration">
<time>true</time>
<latency>true</latency>
<timestamp>true</timestamp>
<success>true</success>
<label>true</label>
<code>true</code>
<message>true</message>
<threadName>true</threadName>
<dataType>true</dataType>
<encoding>false</encoding>
<assertions>true</assertions>
<subresults>true</subresults>
<responseData>false</responseData>
<samplerData>false</samplerData>
<xml>false</xml>
<fieldNames>false</fieldNames>
<responseHeaders>false</responseHeaders>
<requestHeaders>false</requestHeaders>
<responseDataOnError>false</responseDataOnError>
<saveAssertionResultsFailureMessage>false</saveAssertionResultsFailureMessage>
<assertionsResultsToSave>0</assertionsResultsToSave>
<bytes>true</bytes>
<threadCounts>true</threadCounts>
</value>
</objProp>
<stringProp name="filename"></stringProp>
</ResultCollector>
<hashTree/>
<ResultCollector guiclass="ViewResultsFullVisualizer" testclass="ResultCollector" testname="View Results Tree" enabled="true">
<boolProp name="ResultCollector.error_logging">false</boolProp>
<objProp>
<name>saveConfig</name>
<value class="SampleSaveConfiguration">
<time>true</time>
<latency>true</latency>
<timestamp>true</timestamp>
<success>true</success>
<label>true</label>
<code>true</code>
<message>true</message>
<threadName>true</threadName>
<dataType>true</dataType>
<encoding>false</encoding>
<assertions>true</assertions>
<subresults>true</subresults>
<responseData>false</responseData>
<samplerData>false</samplerData>
<xml>false</xml>
<fieldNames>false</fieldNames>
<responseHeaders>false</responseHeaders>
<requestHeaders>false</requestHeaders>
<responseDataOnError>false</responseDataOnError>
<saveAssertionResultsFailureMessage>false</saveAssertionResultsFailureMessage>
<assertionsResultsToSave>0</assertionsResultsToSave>
<bytes>true</bytes>
<threadCounts>true</threadCounts>
</value>
</objProp>
<stringProp name="filename"></stringProp>
</ResultCollector>
<hashTree/>
</hashTree>
</hashTree>
</jmeterTestPlan>

View File

@@ -1,16 +0,0 @@
#
# Copyright 2013-2018 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
#
# https://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.
#
sampleresult.useNanoTime=true

View File

@@ -1,12 +0,0 @@
// +++++++++++++++++++++++++++++++++++++++++++++++++++++++
// + Initial AsciiDoc editor configuration file - V1.0 +
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++
//
// Did not found any configuration files, so create this at project root level.
// If you do not like those files to be generated - you can turn it off inside Asciidoctor Editor preferences.
//
// You can define editor specific parts here.
// For example: with next line you could set imagesdir attribute to subfolder "images" relative to the folder where this config file is located.
// :imagesdir: {asciidoctorconfigdir}/images
//
// For more information please take a look at https://github.com/de-jcup/eclipse-asciidoctor-editor/wiki/Asciidoctor-configfiles

View File

@@ -1,139 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
~ Copyright 2013-2018 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
~
~ https://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:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://maven.apache.org/POM/4.0.0"
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.cloud</groupId>
<artifactId>spring-cloud-sleuth</artifactId>
<version>3.1.1-SNAPSHOT</version>
</parent>
<artifactId>spring-cloud-sleuth-docs</artifactId>
<packaging>jar</packaging>
<name>Spring Cloud Sleuth Docs</name>
<description>Spring Sleuth Docs</description>
<properties>
<docs.main>spring-cloud-sleuth</docs.main>
<main.basedir>${basedir}/..</main.basedir>
<configprops.inclusionPattern>spring.sleuth.*|spring.zipkin.*</configprops.inclusionPattern>
<upload-docs-zip.phase>deploy</upload-docs-zip.phase>
<!-- Tag generation script -->
<roaster.version>2.22.3.Final</roaster.version>
<module.inclusionPattern>.*/spring-cloud-sleuth-instrumentation/.*|.*/spring-cloud-sleuth-brave/.*</module.inclusionPattern>
</properties>
<dependencies>
<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>spring-cloud-starter-sleuth</artifactId>
</dependency>
<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>spring-cloud-sleuth-zipkin</artifactId>
</dependency>
<dependency>
<groupId>org.jboss.forge.roaster</groupId>
<artifactId>roaster-api</artifactId>
<version>${roaster.version}</version>
</dependency>
<dependency>
<groupId>org.jboss.forge.roaster</groupId>
<artifactId>roaster-jdt</artifactId>
<version>${roaster.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>build-helper-maven-plugin</artifactId>
<version>${build-helper-maven-plugin.version}</version>
<executions>
<execution>
<phase>generate-sources</phase>
<goals>
<goal>add-source</goal>
</goals>
<configuration>
<sources>
<source>src/main/asciidoc</source>
</sources>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
<profiles>
<profile>
<id>docs</id>
<build>
<plugins>
<plugin>
<groupId>pl.project13.maven</groupId>
<artifactId>git-commit-id-plugin</artifactId>
</plugin>
<plugin>
<artifactId>maven-dependency-plugin</artifactId>
</plugin>
<plugin>
<artifactId>maven-resources-plugin</artifactId>
</plugin>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>exec-maven-plugin</artifactId>
<executions>
<execution>
<id>build-tags-and-spans</id>
<phase>prepare-package</phase>
<goals>
<goal>java</goal>
</goals>
<configuration>
<mainClass>org.springframework.cloud.sleuth.documentation.DocsFromSources</mainClass>
<arguments>
<argument>${maven.multiModuleProjectDirectory}</argument>
<argument>${module.inclusionPattern}</argument>
<argument>${maven.multiModuleProjectDirectory}/docs/src/main/asciidoc/</argument>
</arguments>
<includeProjectDependencies>true</includeProjectDependencies>
<includePluginDependencies>true</includePluginDependencies>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.asciidoctor</groupId>
<artifactId>asciidoctor-maven-plugin</artifactId>
</plugin>
<plugin>
<artifactId>maven-antrun-plugin</artifactId>
</plugin>
<plugin>
<artifactId>maven-deploy-plugin</artifactId>
</plugin>
</plugins>
</build>
</profile>
</profiles>
</project>

View File

@@ -1,86 +0,0 @@
:jdkversion: 1.8
image::https://github.com/spring-cloud/spring-cloud-sleuth/workflows/Build/badge.svg?style=svg["Build",link="https://github.com/spring-cloud/spring-cloud-sleuth/actions"]
image::https://badges.gitter.im/spring-cloud/spring-cloud-sleuth.svg[Gitter,link="https://gitter.im/spring-cloud/spring-cloud-sleuth?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge"]
== Spring Cloud Sleuth
Spring Cloud Sleuth provides Spring Boot auto-configuration for distributed tracing.
Sleuth configures everything you need to get started.
This includes where trace data (spans) are reported to, how many traces to keep (sampling), if remote fields (baggage) are sent, and which libraries are traced.
=== Quick Start
Add Spring Cloud Sleuth to the classpath of a Spring Boot application (together with a Tracer implementation) and you will see trace IDs in logs.
Example of Sleuth with Brave tracer:
[source,xml,indent=0,subs="verbatim,quotes,attributes"]
----
<!-- Spring Cloud Sleuth requires a Spring Cloud BOM -->
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<!-- Provide the latest stable Spring Cloud release train version (e.g. 2020.0.0) -->
<version>${release.train.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<!-- Boot's Web support -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- Sleuth with Brave tracer implementation -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-sleuth</artifactId>
</dependency>
</dependencies>
----
Consider the following HTTP handler:
[source,java,indent=0]
----
@RestController
public class DemoController {
private static Logger log = LoggerFactory.getLogger(DemoController.class);
@RequestMapping("/")
public String home() {
log.info("Handling home");
return "Hello World";
}
}
----
If you add that handler to a controller, you can see the calls to `home()`
being traced in the logs (notice the `0b6aaf642574edd3` ids).
[indent=0]
----
2020-10-21 12:01:16.285 INFO [,0b6aaf642574edd3,0b6aaf642574edd3,true] 289589 --- [nio-9000-exec-1] DemoController : Handling home!
----
NOTE: Instead of logging the request in the handler explicitly, you could set `logging.level.org.springframework.web.servlet.DispatcherServlet=DEBUG`.
NOTE: Set `spring.application.name=myService` (for instance) to see the service name as well as the trace and span IDs.
== Documentation
Please visit the https://docs.spring.io/spring-cloud-sleuth/docs/[documentation page] to read more about the project.
== Building
include::https://raw.githubusercontent.com/spring-cloud/spring-cloud-build/main/docs/src/main/asciidoc/building.adoc[]
== Contributing
include::https://raw.githubusercontent.com/spring-cloud/spring-cloud-build/main/docs/src/main/asciidoc/contributing.adoc[]

View File

@@ -1,25 +0,0 @@
:doctype: book
:idprefix:
:idseparator: -
:toc: left
:toclevels: 4
:tabsize: 4
:numbered:
:sectanchors:
:sectnums:
:icons: font
:hide-uri-scheme:
:docinfo: shared,private
:sc-ext: java
:project-full-name: Spring Cloud Sleuth
// project-specific attributes
:core_path: {project-root}
:docs_path: {project-root}/docs
:autoconfig_path: {project-root}/spring-cloud-sleuth-autoconfigure
:api_path: {project-root}/spring-cloud-sleuth-api
:brave_path: {project-root}/spring-cloud-sleuth-brave
:tests_path: {core_path}/tests
:common_tests_path: {tests_path}/common
:brave_tests_path: {tests_path}/brave

View File

@@ -1,118 +0,0 @@
|===
|Name | Default | Description
|spring.sleuth.async.configurer.enabled | `true` | Enable default AsyncConfigurer.
|spring.sleuth.async.enabled | `true` | Enable instrumenting async related components so that the tracing information is passed between threads.
|spring.sleuth.async.ignored-beans | | List of {@link java.util.concurrent.Executor} bean names that should be ignored and not wrapped in a trace representation.
|spring.sleuth.baggage.correlation-enabled | `true` | Enables correlating the baggage context with logging contexts.
|spring.sleuth.baggage.correlation-fields | | List of fields that should be propagated over the wire.
|spring.sleuth.baggage.local-fields | | List of fields that should be accessible within the JVM process but not propagated over the wire.
|spring.sleuth.baggage.remote-fields | | List of fields that are referenced the same in-process as it is on the wire. For example, the field "x-vcap-request-id" would be set as-is including the prefix.
|spring.sleuth.baggage.tag-fields | | List of fields that should automatically become tags.
|spring.sleuth.batch.enabled | `true` | Enable Spring Batch instrumentation.
|spring.sleuth.cassandra.enabled | `true` | Enable Cassandra instrumentation.
|spring.sleuth.circuitbreaker.enabled | `true` | Enable Spring Cloud CircuitBreaker instrumentation.
|spring.sleuth.config.server.enabled | `true` | Enable Spring Cloud Config Server instrumentation.
|spring.sleuth.deployer.enabled | `true` | Enable Spring Cloud Deployer instrumentation.
|spring.sleuth.deployer.status-poll-delay | `500` | Default poll delay to retrieve the deployed application status.
|spring.sleuth.enabled | `true` |
|spring.sleuth.feign.enabled | `true` | Enable span information propagation when using Feign.
|spring.sleuth.feign.processor.enabled | `true` | Enable post processor that wraps Feign Context in its tracing representations.
|spring.sleuth.function.enabled | `true` | Enable instrumenting of Spring Cloud Function and Spring Cloud Function based projects (e.g. Spring Cloud Stream).
|spring.sleuth.grpc.enabled | `true` | Enable span information propagation when using GRPC.
|spring.sleuth.http.enabled | `true` | Enables HTTP support.
|spring.sleuth.integration.enabled | `true` | Enable Spring Integration instrumentation.
|spring.sleuth.integration.patterns | `[!hystrixStreamOutput*, *, !channel*]` | An array of patterns against which channel names will be matched. @see org.springframework.integration.config.GlobalChannelInterceptor#patterns() Defaults to any channel name not matching the Hystrix Stream and functional Stream channel names.
|spring.sleuth.integration.websockets.enabled | `true` | Enable tracing for WebSockets.
|spring.sleuth.jdbc.datasource-proxy.enabled | `true` | Should the datasource-proxy tracing be enabled?
|spring.sleuth.jdbc.datasource-proxy.json-format | `false` | Use json output for logging query. @see ProxyDataSourceBuilder#asJson()
|spring.sleuth.jdbc.datasource-proxy.logging | | Logging to use for logging queries.
|spring.sleuth.jdbc.datasource-proxy.multiline | `true` | Use multiline output for logging query. @see ProxyDataSourceBuilder#multiline()
|spring.sleuth.jdbc.datasource-proxy.query.enable-logging | `false` | Enable logging all queries to the log.
|spring.sleuth.jdbc.datasource-proxy.query.log-level | `DEBUG` | Severity of query logger.
|spring.sleuth.jdbc.datasource-proxy.query.logger-name | | Name of query logger.
|spring.sleuth.jdbc.datasource-proxy.slow-query.enable-logging | `false` | Enable logging slow queries to the log.
|spring.sleuth.jdbc.datasource-proxy.slow-query.log-level | `WARN` | Severity of slow query logger.
|spring.sleuth.jdbc.datasource-proxy.slow-query.logger-name | | Name of slow query logger.
|spring.sleuth.jdbc.datasource-proxy.slow-query.threshold | `300` | Number of seconds to consider query as slow.
|spring.sleuth.jdbc.enabled | `true` | Enables JDBC instrumentation.
|spring.sleuth.jdbc.excluded-data-source-bean-names | | List of DataSource bean names that will not be decorated.
|spring.sleuth.jdbc.includes | | Which types of tracing we would like to include.
|spring.sleuth.jdbc.p6spy.custom-appender-class | | Class file to use (only with logging=custom). The class must implement {@link com.p6spy.engine.spy.appender.FormattedLogger}.
|spring.sleuth.jdbc.p6spy.enable-logging | `false` | Enables logging JDBC events.
|spring.sleuth.jdbc.p6spy.enabled | `true` | Should the p6spy tracing be enabled?
|spring.sleuth.jdbc.p6spy.log-file | `spy.log` | Name of log file to use (only with logging=file).
|spring.sleuth.jdbc.p6spy.log-filter.pattern | | Use regex pattern to filter log messages. Only matched messages will be logged.
|spring.sleuth.jdbc.p6spy.log-format | | Custom log format.
|spring.sleuth.jdbc.p6spy.logging | | Logging to use for logging queries.
|spring.sleuth.jdbc.p6spy.multiline | `true` | Enables multiline output.
|spring.sleuth.jdbc.p6spy.tracing.include-parameter-values | `false` | Report the effective sql string (with '?' replaced with real values) to tracing systems. <p> NOTE this setting does not affect the logging message.
|spring.sleuth.kafka.enabled | `true` | Enable instrumenting of Apache Kafka clients.
|spring.sleuth.messaging.aspect.enabled | `false` | Should {@link MessageMapping} wrapping be enabled.
|spring.sleuth.messaging.enabled | `false` | Should messaging be turned on.
|spring.sleuth.messaging.jms.enabled | `true` | Enable tracing of JMS.
|spring.sleuth.messaging.jms.remote-service-name | `jms` | JMS remote service name.
|spring.sleuth.messaging.kafka.enabled | `true` | Enable tracing of Kafka.
|spring.sleuth.messaging.kafka.mapper.enabled | `true` | Enable DefaultKafkaHeaderMapper tracing for Kafka.
|spring.sleuth.messaging.kafka.remote-service-name | `kafka` | Kafka remote service name.
|spring.sleuth.messaging.kafka.streams.enabled | `false` | Should Kafka Streams be turned on.
|spring.sleuth.messaging.rabbit.enabled | `true` | Enable tracing of RabbitMQ.
|spring.sleuth.messaging.rabbit.remote-service-name | `rabbitmq` | Rabbit remote service name.
|spring.sleuth.mongodb.enabled | `true` | Enable tracing for MongoDb.
|spring.sleuth.mongodb.socket-address-span-customizer.enabled | `false` | Enable setting of SocketAddress information on the Mongo span.
|spring.sleuth.opentracing.enabled | `true` | Enables OpenTracing support.
|spring.sleuth.propagation.type | | Tracing context propagation types.
|spring.sleuth.quartz.enabled | `true` | Enable tracing for Quartz.
|spring.sleuth.r2dbc.enabled | `true` | Enable R2dbc instrumentation.
|spring.sleuth.reactor.decorate-on-each | `true` | When true decorates on each operator, will be less performing, but logging will always contain the tracing entries in each operator. When false decorates on last operator, will be more performing, but logging might not always contain the tracing entries. @deprecated use explicit value via {@link SleuthReactorProperties#instrumentationType}
|spring.sleuth.reactor.enabled | `true` | When true enables instrumentation for reactor.
|spring.sleuth.reactor.instrumentation-type | |
|spring.sleuth.redis.enabled | `true` | Enable span information propagation when using Redis.
|spring.sleuth.redis.legacy.enabled | `false` | Enable legacy tracing of Redis that works only via Brave.
|spring.sleuth.redis.remote-service-name | `redis` | Service name for the remote Redis endpoint.
|spring.sleuth.rpc.enabled | `true` | Enable tracing of RPC.
|spring.sleuth.rsocket.enabled | `true` | When true enables instrumentation for rsocket.
|spring.sleuth.rxjava.schedulers.hook.enabled | `true` | Enable support for RxJava via RxJavaSchedulersHook.
|spring.sleuth.rxjava.schedulers.ignoredthreads | `[HystrixMetricPoller, ^RxComputation.*$]` | Thread names for which spans will not be sampled.
|spring.sleuth.sampler.probability | | Probability of requests that should be sampled. E.g. 1.0 - 100% requests should be sampled. The precision is whole-numbers only (i.e. there's no support for 0.1% of the traces).
|spring.sleuth.sampler.rate | `10` | A rate per second can be a nice choice for low-traffic endpoints as it allows you surge protection. For example, you may never expect the endpoint to get more than 50 requests per second. If there was a sudden surge of traffic, to 5000 requests per second, you would still end up with 50 traces per second. Conversely, if you had a percentage, like 10%, the same surge would end up with 500 traces per second, possibly overloading your storage. Amazon X-Ray includes a rate-limited sampler (named Reservoir) for this purpose. Brave has taken the same approach via the {@link brave.sampler.RateLimitingSampler}.
|spring.sleuth.sampler.refresh.enabled | `true` | Enable refresh scope for sampler.
|spring.sleuth.scheduled.enabled | `true` | Enable tracing for {@link org.springframework.scheduling.annotation.Scheduled}.
|spring.sleuth.scheduled.skip-pattern | | Pattern for the fully qualified name of a class that should be skipped.
|spring.sleuth.session.enabled | `true` | Enable Spring Session instrumentation.
|spring.sleuth.span-filter.additional-span-name-patterns-to-ignore | | Additional list of span names to ignore. Will be appended to {@link #spanNamePatternsToSkip}.
|spring.sleuth.span-filter.enabled | `false` | Will turn on the default Sleuth handler mechanism. Might ignore exporting of certain spans;
|spring.sleuth.span-filter.span-name-patterns-to-skip | `^catalogWatchTaskScheduler$` | List of span names to ignore. They will not be sent to external systems.
|spring.sleuth.supports-join | `true` | True means the tracing system supports sharing a span ID between a client and server.
|spring.sleuth.task.enabled | `true` | Enable Spring Cloud Task instrumentation.
|spring.sleuth.trace-id128 | `false` | When true, generate 128-bit trace IDs instead of 64-bit ones.
|spring.sleuth.tracer.mode | | Set which tracer implementation should be picked.
|spring.sleuth.tx.enabled | `true` | Enable Spring TX instrumentation.
|spring.sleuth.vault.enabled | `true` | Enable Spring Vault instrumentation.
|spring.sleuth.web.additional-skip-pattern | | Additional pattern for URLs that should be skipped in tracing. This will be appended to the {@link SleuthWebProperties#skipPattern}.
|spring.sleuth.web.client.enabled | `true` | Enable interceptor injecting into {@link org.springframework.web.client.RestTemplate}.
|spring.sleuth.web.client.skip-pattern | | Pattern for URLs that should be skipped in client side tracing.
|spring.sleuth.web.enabled | `true` | When true enables instrumentation for web applications.
|spring.sleuth.web.filter-order | `0` | Order in which the tracing filters should be registered.
|spring.sleuth.web.ignore-auto-configured-skip-patterns | `false` | If set to true, auto-configured skip patterns will be ignored.
|spring.sleuth.web.servlet.enabled | `true` | Enable servlet instrumentation.
|spring.sleuth.web.skip-pattern | `/api-docs.*\|/swagger.*\|.*\.png\|.*\.css\|.*\.js\|.*\.html\|/favicon.ico\|/hystrix.stream` | Pattern for URLs that should be skipped in tracing.
|spring.sleuth.web.tomcat.enabled | `true` | Enable tracing instrumentation for Tomcat.
|spring.sleuth.web.webclient.enabled | `true` | Enable tracing instrumentation for WebClient.
|spring.zipkin.activemq.message-max-bytes | `100000` | Maximum number of bytes for a given message with spans sent to Zipkin over ActiveMQ.
|spring.zipkin.activemq.queue | `zipkin` | Name of the ActiveMQ queue where spans should be sent to Zipkin.
|spring.zipkin.api-path | | The API path to append to baseUrl (above) as suffix. This applies if you use other monitoring tools, such as New Relic. The trace API doesn't need the API path, so you can set it to blank ("") in the configuration.
|spring.zipkin.base-url | `http://localhost:9411/` | URL of the zipkin query server instance. You can also provide the service id of the Zipkin server if Zipkin's registered in service discovery (e.g. https://zipkinserver/).
|spring.zipkin.compression.enabled | `false` |
|spring.zipkin.discovery-client-enabled | | If set to {@code false}, will treat the {@link ZipkinProperties#baseUrl} as a URL always.
|spring.zipkin.enabled | `true` | Enables sending spans to Zipkin.
|spring.zipkin.encoder | | Encoding type of spans sent to Zipkin. Set to {@link SpanBytesEncoder#JSON_V1} if your server is not recent.
|spring.zipkin.kafka.topic | `zipkin` | Name of the Kafka topic where spans should be sent to Zipkin.
|spring.zipkin.locator.discovery.enabled | `false` | Enabling of locating the host name via service discovery.
|spring.zipkin.message-timeout | `1` | Timeout in seconds before pending spans will be sent in batches to Zipkin.
|spring.zipkin.rabbitmq.addresses | | Addresses of the RabbitMQ brokers used to send spans to Zipkin
|spring.zipkin.rabbitmq.queue | `zipkin` | Name of the RabbitMQ queue where spans should be sent to Zipkin.
|spring.zipkin.sender.type | | Means of sending spans to Zipkin.
|spring.zipkin.service.name | | The name of the service, from which the Span was sent via HTTP, that should appear in Zipkin.
|===

View File

@@ -1,662 +0,0 @@
=== Annotation New Or Continue Span
> Span that wraps a @NewSpan or @ContinueSpan annotations.
**Span name** `%s` - since it contains `%s`, the name is dynamic and will be resolved at runtime.
Fully qualified name of the enclosing class `org.springframework.cloud.sleuth.instrument.annotation.SleuthAnnotationSpan`
.Tag Keys
|===
|Name | Description
|class|Class name where a method got annotated with a Sleuth annotation.
|method|Method name that got annotated with Sleuth annotation.
|===
.Event Values
|===
|Name | Description
|%s.after|Annotated after executing a method annotated with @ContinueSpan or @NewSpan. (since the name contains `%s` the final value will be resolved at runtime)
|%s.afterFailure|Annotated after throwing an exception from a method annotated with @ContinueSpan or @NewSpan. (since the name contains `%s` the final value will be resolved at runtime)
|%s.before|Annotated before executing a method annotated with @ContinueSpan or @NewSpan. (since the name contains `%s` the final value will be resolved at runtime)
|===
=== Async Annotation Span
> Span that wraps a @Async annotation. Either continues an existing one or creates a new one if there was no present one.
**Span name** `%s` - since it contains `%s`, the name is dynamic and will be resolved at runtime.
Fully qualified name of the enclosing class `org.springframework.cloud.sleuth.instrument.async.SleuthAsyncSpan`
.Tag Keys
|===
|Name | Description
|class|Class name where a method got annotated with @Async.
|method|Method name that got annotated with @Async.
|===
=== Async Callable Span
> Span created whenever a Callable needs to be instrumented.
**Span name** `%s` - since it contains `%s`, the name is dynamic and will be resolved at runtime.
Fully qualified name of the enclosing class `org.springframework.cloud.sleuth.instrument.async.SleuthAsyncSpan`
=== Async Runnable Span
> Span created whenever a Runnable needs to be instrumented.
**Span name** `%s` - since it contains `%s`, the name is dynamic and will be resolved at runtime.
Fully qualified name of the enclosing class `org.springframework.cloud.sleuth.instrument.async.SleuthAsyncSpan`
=== Batch Job Span
> Span created around a Job execution.
**Span name** `%s` - since it contains `%s`, the name is dynamic and will be resolved at runtime.
Fully qualified name of the enclosing class `org.springframework.cloud.sleuth.instrument.batch.SleuthBatchSpan`
.Tag Keys
|===
|Name | Description
|batch.job.executionId|ID of the Spring Batch execution.
|batch.job.instanceId|ID of the Spring Batch job instance.
|batch.job.name|Name of the Spring Batch job.
|===
=== Batch Step Span
> Span created around a Job execution.
**Span name** `%s` - since it contains `%s`, the name is dynamic and will be resolved at runtime.
Fully qualified name of the enclosing class `org.springframework.cloud.sleuth.instrument.batch.SleuthBatchSpan`
.Tag Keys
|===
|Name | Description
|batch.job.executionId|ID of the Spring Batch execution.
|batch.step.executionId|ID of the Spring Batch execution.
|batch.step.name|Name of the Spring Batch job.
|batch.step.type|Type of the Spring Batch job.
|===
=== Cassandra Span
> Span created around CqlSession executions.
**Span name** `%s` - since it contains `%s`, the name is dynamic and will be resolved at runtime.
Fully qualified name of the enclosing class `org.springframework.cloud.sleuth.instrument.cassandra.SleuthCassandraSpan`
IMPORTANT: All tags and events must be prefixed with `cassandra.` prefix!
.Tag Keys
|===
|Name | Description
|cassandra.cql|A tag containing Cassandra CQL.
|cassandra.keyspace|Name of the Cassandra keyspace.
|cassandra.node[%s].error|A tag containing error that occurred for the given node. (since the name contains `%s` the final value will be resolved at runtime)
|===
.Event Values
|===
|Name | Description
|cassandra.node.error|Set whenever an error occurred for the given node.
|cassandra.node.success|Set when a success occurred for the session processing.
|===
=== Circuit Breaker Function Span
> Span created when we wrap a Function passed to the CircuitBreaker. as fallback.
**Span name** `%s` - since it contains `%s`, the name is dynamic and will be resolved at runtime.
Fully qualified name of the enclosing class `org.springframework.cloud.sleuth.instrument.circuitbreaker.SleuthCircuitBreakerSpan`
=== Circuit Breaker Supplier Span
> Span created when we wrap a Supplier passed to the CircuitBreaker.
**Span name** `%s` - since it contains `%s`, the name is dynamic and will be resolved at runtime.
Fully qualified name of the enclosing class `org.springframework.cloud.sleuth.instrument.circuitbreaker.SleuthCircuitBreakerSpan`
=== Config Span
> Span created around an EnvironmentRepository.
**Span name** `find`.
Fully qualified name of the enclosing class `org.springframework.cloud.sleuth.instrument.config.SleuthConfigSpan`
.Tag Keys
|===
|Name | Description
|config.environment.class|Implementation of the EnvironmentRepository.
|config.environment.method|Method executed on the EnvironmentRepository.
|===
=== Deployer Deploy Span
> Span created upon deploying of an application.
**Span name** `deploy`.
Fully qualified name of the enclosing class `org.springframework.cloud.sleuth.instrument.deployer.SleuthDeployerSpan`
.Tag Keys
|===
|Name | Description
|deployer.app.group|Group of the deployed application.
|deployer.app.id|ID of the deployed application.
|deployer.app.name|Name of the deployed application.
|deployer.platform.cf.org|CloudFoundry org.
|deployer.platform.cf.space|CloudFoundry space.
|deployer.platform.cf.url|CloudFoundry API URL.
|deployer.platform.k8s.namespace|Kubernetes namespace.
|deployer.platform.k8s.url|Kubernetes API URL.
|deployer.platform.name|Name of the platform to which apps are being deployed.
|===
.Event Values
|===
|Name | Description
|%s|When deployer changes the state of the deployed application. (since the name contains `%s` the final value will be resolved at runtime)
|deployer.start|When deployer started deploying the application.
|===
=== Deployer Get Log Span
> Span created upon asking for logs of deployed applications.
**Span name** `getLog`.
Fully qualified name of the enclosing class `org.springframework.cloud.sleuth.instrument.deployer.SleuthDeployerSpan`
.Tag Keys
|===
|Name | Description
|deployer.app.group|Group of the deployed application.
|deployer.app.id|ID of the deployed application.
|deployer.app.name|Name of the deployed application.
|deployer.platform.cf.org|CloudFoundry org.
|deployer.platform.cf.space|CloudFoundry space.
|deployer.platform.cf.url|CloudFoundry API URL.
|deployer.platform.k8s.namespace|Kubernetes namespace.
|deployer.platform.k8s.url|Kubernetes API URL.
|deployer.platform.name|Name of the platform to which apps are being deployed.
|===
.Event Values
|===
|Name | Description
|%s|When deployer changes the state of the deployed application. (since the name contains `%s` the final value will be resolved at runtime)
|deployer.start|When deployer started deploying the application.
|===
=== Deployer Scale Span
> Span created upon asking for logs of deployed applications.
**Span name** `scale`.
Fully qualified name of the enclosing class `org.springframework.cloud.sleuth.instrument.deployer.SleuthDeployerSpan`
.Tag Keys
|===
|Name | Description
|deployer.app.group|Group of the deployed application.
|deployer.app.id|ID of the deployed application.
|deployer.app.name|Name of the deployed application.
|deployer.platform.cf.org|CloudFoundry org.
|deployer.platform.cf.space|CloudFoundry space.
|deployer.platform.cf.url|CloudFoundry API URL.
|deployer.platform.k8s.namespace|Kubernetes namespace.
|deployer.platform.k8s.url|Kubernetes API URL.
|deployer.platform.name|Name of the platform to which apps are being deployed.
|deployer.scale.count|Scale count.
|deployer.scale.deploymentId|Scale command deployment id.
|===
.Event Values
|===
|Name | Description
|%s|When deployer changes the state of the deployed application. (since the name contains `%s` the final value will be resolved at runtime)
|deployer.start|When deployer started deploying the application.
|===
=== Deployer Statuses Span
> Span created upon asking for statuses of deployed applications.
**Span name** `statuses`.
Fully qualified name of the enclosing class `org.springframework.cloud.sleuth.instrument.deployer.SleuthDeployerSpan`
.Tag Keys
|===
|Name | Description
|deployer.app.group|Group of the deployed application.
|deployer.app.id|ID of the deployed application.
|deployer.app.name|Name of the deployed application.
|deployer.platform.cf.org|CloudFoundry org.
|deployer.platform.cf.space|CloudFoundry space.
|deployer.platform.cf.url|CloudFoundry API URL.
|deployer.platform.k8s.namespace|Kubernetes namespace.
|deployer.platform.k8s.url|Kubernetes API URL.
|deployer.platform.name|Name of the platform to which apps are being deployed.
|===
.Event Values
|===
|Name | Description
|%s|When deployer changes the state of the deployed application. (since the name contains `%s` the final value will be resolved at runtime)
|deployer.start|When deployer started deploying the application.
|===
=== Deployer Status Span
> Span created upon asking for a status of a deployed application.
**Span name** `status`.
Fully qualified name of the enclosing class `org.springframework.cloud.sleuth.instrument.deployer.SleuthDeployerSpan`
.Tag Keys
|===
|Name | Description
|deployer.app.group|Group of the deployed application.
|deployer.app.id|ID of the deployed application.
|deployer.app.name|Name of the deployed application.
|deployer.platform.cf.org|CloudFoundry org.
|deployer.platform.cf.space|CloudFoundry space.
|deployer.platform.cf.url|CloudFoundry API URL.
|deployer.platform.k8s.namespace|Kubernetes namespace.
|deployer.platform.k8s.url|Kubernetes API URL.
|deployer.platform.name|Name of the platform to which apps are being deployed.
|===
.Event Values
|===
|Name | Description
|%s|When deployer changes the state of the deployed application. (since the name contains `%s` the final value will be resolved at runtime)
|deployer.start|When deployer started deploying the application.
|===
=== Deployer Undeploy Span
> Span created upon undeploying of an application.
**Span name** `undeploy`.
Fully qualified name of the enclosing class `org.springframework.cloud.sleuth.instrument.deployer.SleuthDeployerSpan`
.Tag Keys
|===
|Name | Description
|deployer.app.group|Group of the deployed application.
|deployer.app.id|ID of the deployed application.
|deployer.app.name|Name of the deployed application.
|deployer.platform.cf.org|CloudFoundry org.
|deployer.platform.cf.space|CloudFoundry space.
|deployer.platform.cf.url|CloudFoundry API URL.
|deployer.platform.k8s.namespace|Kubernetes namespace.
|deployer.platform.k8s.url|Kubernetes API URL.
|deployer.platform.name|Name of the platform to which apps are being deployed.
|===
.Event Values
|===
|Name | Description
|%s|When deployer changes the state of the deployed application. (since the name contains `%s` the final value will be resolved at runtime)
|deployer.start|When deployer started deploying the application.
|===
=== Jdbc Connection Span
> Span created when a JDBC connection takes place.
**Span name** `connection`.
Fully qualified name of the enclosing class `org.springframework.cloud.sleuth.instrument.jdbc.SleuthJdbcSpan`
IMPORTANT: All tags and events must be prefixed with `jdbc.` prefix!
.Tag Keys
|===
|Name | Description
|jdbc.datasource.driver|Name of the JDBC datasource driver.
|jdbc.datasource.pool|Name of the JDBC datasource pool.
|===
=== Jdbc Query Span
> Span created when a JDBC query gets executed.
**Span name** `%s` - since it contains `%s`, the name is dynamic and will be resolved at runtime.
Fully qualified name of the enclosing class `org.springframework.cloud.sleuth.instrument.jdbc.SleuthJdbcSpan`
IMPORTANT: All tags and events must be prefixed with `jdbc.` prefix!
.Tag Keys
|===
|Name | Description
|jdbc.query|The SQL query value.
|jdbc.row-count|Number of SQL rows.
|===
.Event Values
|===
|Name | Description
|jdbc.commit|When the transaction gets commited.
|jdbc.rollback|When the transaction gets rolled back.
|===
=== Jdbc Result Set Span
> Span created when working with JDBC result set.
**Span name** `result-set`.
Fully qualified name of the enclosing class `org.springframework.cloud.sleuth.instrument.jdbc.SleuthJdbcSpan`
IMPORTANT: All tags and events must be prefixed with `jdbc.` prefix!
.Tag Keys
|===
|Name | Description
|jdbc.query|The SQL query value.
|jdbc.row-count|Number of SQL rows.
|===
.Event Values
|===
|Name | Description
|jdbc.commit|When the transaction gets commited.
|jdbc.rollback|When the transaction gets rolled back.
|===
=== Kafka Consumer Span
> Span created on the Kafka consumer side.
**Span name** `kafka.consume`.
Fully qualified name of the enclosing class `org.springframework.cloud.sleuth.instrument.kafka.SleuthKafkaSpan`
IMPORTANT: All tags and events must be prefixed with `kafka.` prefix!
.Tag Keys
|===
|Name | Description
|kafka.offset|Kafka offset number.
|kafka.partition|Kafka partition number.
|kafka.topic|Name of the Kafka topic.
|===
=== Kafka On Message Span
> Span created on the Kafka consumer side when using a MessageListener.
**Span name** `kafka.on-message`.
Fully qualified name of the enclosing class `org.springframework.cloud.sleuth.instrument.kafka.SleuthKafkaSpan`
IMPORTANT: All tags and events must be prefixed with `kafka.` prefix!
.Tag Keys
|===
|Name | Description
|kafka.offset|Kafka offset number.
|kafka.partition|Kafka partition number.
|kafka.topic|Name of the Kafka topic.
|===
=== Kafka Producer Span
> Span created on the Kafka consumer side.
**Span name** `kafka.produce`.
Fully qualified name of the enclosing class `org.springframework.cloud.sleuth.instrument.kafka.SleuthKafkaSpan`
IMPORTANT: All tags and events must be prefixed with `kafka.` prefix!
.Tag Keys
|===
|Name | Description
|kafka.topic|Name of the Kafka topic.
|===
=== Messaging Span
> Span created when message is sent or received.
**Span name** `%s` - since it contains `%s`, the name is dynamic and will be resolved at runtime.
Fully qualified name of the enclosing class `org.springframework.cloud.sleuth.instrument.messaging.SleuthMessagingSpan`
.Tag Keys
|===
|Name | Description
|%s|User provided keys via customization options. (since the name contains `%s` the final value will be resolved at runtime)
|channel|Name of the Spring Integration channel.
|function.name|Name of the Spring Cloud Function function name.
|===
=== Mvc Handler Interceptor Span
> Span around a HandlerInterceptor. Will continue the current span and tag it
**Span name** `%s` - since it contains `%s`, the name is dynamic and will be resolved at runtime.
Fully qualified name of the enclosing class `org.springframework.cloud.sleuth.instrument.web.mvc.SleuthMvcSpan`
.Tag Keys
|===
|Name | Description
|mvc.controller.class|Class name where a method got annotated with @Scheduled.
|mvc.controller.method|Method name that got annotated with @Scheduled.
|===
=== Quartz Trigger Span
> Span created when trigger is fired and then completed.
**Span name** `%s` - since it contains `%s`, the name is dynamic and will be resolved at runtime.
Fully qualified name of the enclosing class `org.springframework.cloud.sleuth.instrument.quartz.SleuthQuartzSpan`
.Tag Keys
|===
|Name | Description
|quartz.trigger|Name of the trigger.
|===
=== R2dbc Query Span
> Span created on the Kafka consumer side.
**Span name** `query`.
Fully qualified name of the enclosing class `org.springframework.cloud.sleuth.instrument.r2dbc.SleuthR2dbcSpan`
IMPORTANT: All tags and events must be prefixed with `r2dbc.` prefix!
.Tag Keys
|===
|Name | Description
|r2dbc.connection|Name of the R2DBC connection.
|r2dbc.query[%s]|Name of the R2DBC query. (since the name contains `%s` the final value will be resolved at runtime)
|r2dbc.thread|Name of the R2DBC thread.
|===
=== Rsocket Requester Span
> Span created on the RSocket responder side.
**Span name** `%s` - since it contains `%s`, the name is dynamic and will be resolved at runtime.
Fully qualified name of the enclosing class `org.springframework.cloud.sleuth.instrument.rsocket.SleuthRSocketSpan`
IMPORTANT: All tags and events must be prefixed with `rsocket.` prefix!
.Tag Keys
|===
|Name | Description
|rsocket.request-type|Name of the R2DBC thread.
|rsocket.route|Name of the RSocket route.
|===
=== Rsocket Responder Span
> Span created on the RSocket responder side.
**Span name** `%s` - since it contains `%s`, the name is dynamic and will be resolved at runtime.
Fully qualified name of the enclosing class `org.springframework.cloud.sleuth.instrument.rsocket.SleuthRSocketSpan`
=== Rx Java Trace Action Span
> Span that wraps a Rx Java .
**Span name** `rxjava`.
Fully qualified name of the enclosing class `org.springframework.cloud.sleuth.instrument.rxjava.SleuthRxJavaSpan`
.Tag Keys
|===
|Name | Description
|thread|Name of the thread.
|===
=== Scheduled Annotation Span
> Span that wraps a annotated method. Either creates a new span or continues an existing one.
**Span name** `%s` - since it contains `%s`, the name is dynamic and will be resolved at runtime.
Fully qualified name of the enclosing class `org.springframework.cloud.sleuth.instrument.scheduling.SleuthSchedulingSpan`
.Tag Keys
|===
|Name | Description
|class|Class name where a method got annotated with @Scheduled.
|method|Method name that got annotated with @Scheduled.
|===
=== Security Context Change
> Indicates that a SecurityContextChangedEvent happened during the current span.
**Span name** `Security Context Change`.
Fully qualified name of the enclosing class `org.springframework.cloud.sleuth.instrument.security.SleuthSecuritySpan`
.Event Values
|===
|Name | Description
|Authentication cleared %s|Event created when an Authentication object is removed from the SecurityContext. (since the name contains `%s` the final value will be resolved at runtime)
|Authentication replaced %s|Event created when an Authentication object is replaced with a new one in the SecurityContext. (since the name contains `%s` the final value will be resolved at runtime)
|Authentication set %s|Event created when an Authentication object is added to the SecurityContext. (since the name contains `%s` the final value will be resolved at runtime)
|===
=== Session Create Span
> Span created when a new session has to be created.
**Span name** `session.create`.
Fully qualified name of the enclosing class `org.springframework.cloud.sleuth.instrument.session.SleuthSessionSpan`
=== Session Delete Span
> Span created when a session is deleted.
**Span name** `session.delete`.
Fully qualified name of the enclosing class `org.springframework.cloud.sleuth.instrument.session.SleuthSessionSpan`
=== Session Find Span
> Span created when a new session is searched for.
**Span name** `session.find`.
Fully qualified name of the enclosing class `org.springframework.cloud.sleuth.instrument.session.SleuthSessionSpan`
IMPORTANT: All tags and events must be prefixed with `session.` prefix!
.Tag Keys
|===
|Name | Description
|session.index.name|
|===
=== Session Save Span
> Span created when a new session is saved.
**Span name** `session.save`.
Fully qualified name of the enclosing class `org.springframework.cloud.sleuth.instrument.session.SleuthSessionSpan`
=== Task Execution Listener Span
> Span created within the lifecycle of a task.
**Span name** `%s` - since it contains `%s`, the name is dynamic and will be resolved at runtime.
Fully qualified name of the enclosing class `org.springframework.cloud.sleuth.instrument.task.SleuthTaskSpan`
=== Task Runner Span
> Span created when a task runner is executed.
**Span name** `%s` - since it contains `%s`, the name is dynamic and will be resolved at runtime.
Fully qualified name of the enclosing class `org.springframework.cloud.sleuth.instrument.task.SleuthTaskSpan`
=== Tx Span
> Span created when there was no previous transaction. If there was one, we will continue it unless propagation is required.
**Span name** `tx`.
Fully qualified name of the enclosing class `org.springframework.cloud.sleuth.instrument.tx.SleuthTxSpan`
IMPORTANT: All tags and events must be prefixed with `tx.` prefix!
.Tag Keys
|===
|Name | Description
|tx.isolation-level|Transaction isolation level.
|tx.name|Transaction name.
|tx.propagation-level|Transaction propagation level.
|tx.read-only|Whether the transaction is read-only.
|tx.timeout|Transaction timeout.
|tx.transaction-manager|Name of the TransactionManager.
|===
=== Web Filter Span
> Span around a WebFilter. Will continue the current span or create a new one and tag it
**Span name** `%s` - since it contains `%s`, the name is dynamic and will be resolved at runtime.
Fully qualified name of the enclosing class `org.springframework.cloud.sleuth.instrument.web.SleuthWebSpan`
.Tag Keys
|===
|Name | Description
|http.status_code|Response status code.
|mvc.controller.class|Name of the class that is processing the request.
|mvc.controller.method|Name of the method that is processing the request.
|===

View File

@@ -1,22 +0,0 @@
:numbered!:
[[appendix]]
[[common-application-properties]]
== Common application properties
include::_attributes.adoc[]
Various properties can be specified inside your `application.properties` file, inside your `application.yml` file, or as command line switches.
This appendix provides a list of common {project-full-name} properties and references to the underlying classes that consume them.
NOTE: Property contributions can come from additional jar files on your classpath, so you should not consider this an exhaustive list.
Also, you can define your own properties.
include::_configprops.adoc[]
[[sleuth-spans]]
== Spring Cloud Sleuth Spans
Below you can find a list of all the spans that are created by Spring Cloud Sleuth.
include::_spans.adoc[]

View File

@@ -1,95 +0,0 @@
[[documentation]]
= Spring Cloud Sleuth Documentation
include::_attributes.adoc[]
This section provides a brief overview of {project-full-name} reference documentation.
It serves as a map for the rest of the document.
[[sleuth-documentation-about]]
== About the Documentation
The {project-full-name} reference guide is available as
* {docs-url}/reference/html[Multi-page HTML]
* {docs-url}/reference/htmlsingle[Single-page HTML]
* {docs-url}/reference/pdf/{project-name}.pdf[PDF]
Copies of this document may be made for your own use and for distribution to others, provided that you do not charge any fee for such copies and further provided that each copy contains this Copyright Notice, whether distributed in print or electronically.
[[documentation-getting-help]]
== Getting Help
If you have trouble with {project-full-name}, we would like to help.
* Try the <<howto.adoc#howto, How-to documents>>.
They provide solutions to the most common questions.
* Learn the {project-full-name} basics.
If you are starting out with {project-full-name}, try one of the https://spring.io/guides[guides].
* Ask a question.
We monitor https://stackoverflow.com[stackoverflow.com] for questions tagged with https://stackoverflow.com/tags/{project-name}[`{project-name}`].
* Report bugs with {project-full-name} at https://github.com/spring-cloud/{project-name}/issues.
* Chat with us at http://https://gitter.im/spring-cloud/{project-name}[{project-full-name} Gitter]
NOTE: All of {project-full-name} is open source, including the documentation.
If you find problems with the docs or if you want to improve them, please {github-code}[get involved].
[[sleuth-documentation-first-steps]]
== First Steps
If you are getting started with {project-full-name} or 'Spring' in general, start with
<<getting-started.adoc#getting-started, the following topics>>:
* *From scratch:* <<getting-started.adoc#getting-started-introducing-spring-cloud-sleuth, Overview>>
* *Tutorial:* <<getting-started.adoc#getting-started-first-application, Part 1>> | <<getting-started.adoc#getting-started-first-application-code, Part 2>>
* *Running your example:* <<getting-started.adoc#getting-started-first-application-run, Part 1>>
[[sleuth-documentation-working-with-sleuth]]
== Working with {project-full-name}
Ready to actually start using {project-full-name}? <<using.adoc#using, We have you covered>>:
* <<using.adoc#using-span-lifecycle,Span Lifecycle with Spring Cloud Sleuth's API>>
* <<using.adoc#using-naming-spans,Naming Spans>>
* <<using.adoc#using-annotations,Managing Spans with Annotations>>
[[sleuth-documentation-features]]
== Learning about {project-full-name} Features
Need more details about {project-full-name}'s core features?
<<project-features.adoc#features, The following content is for you>>:
* *Core Features:*
<<project-features.adoc#features-context-propagation, Context Propagation>> |
<<project-features.adoc#features-sampling, Sampling>>
<<project-features.adoc#features-baggage, Baggage>>
* *Tracer Features:*
<<project-features.adoc#features-brave, OpenZipkin Brave>>
* *Reporting Features:*
<<project-features.adoc#features-zipkin, Zipkin>> |
<<project-features.adoc#features-log-integration, Logs>>
[[sleuth-documentation-integration]]
== Integrations Topics
Finally, we have topics related to instrumentation integrations:
* *Integrations:*
<<integrations.adoc#sleuth-kafka-integration, Apache Kafka>> |
<<integrations.adoc#sleuth-async-integration, Asynchronous Communication>> |
<<integrations.adoc#sleuth-http-client-integration, HTTP Client Integration>> |
<<integrations.adoc#sleuth-http-server-integration, HTTP Server Integration>> |
<<integrations.adoc#sleuth-messaging-integration, Messaging>> |
<<integrations.adoc#sleuth-openfeign-integration, OpenFeign>> |
<<integrations.adoc#sleuth-opentracing-integration, OpenTracing>> |
<<integrations.adoc#sleuth-reactor-integration, Reactor>> |
<<integrations.adoc#sleuth-redis-integration, Redis>> |
<<integrations.adoc#sleuth-rpc-integration, RPC>> |
<<integrations.adoc#sleuth-rpc-grpc-integration, gRPC>> |
<<integrations.adoc#sleuth-rpc-dubbo-integration, Dubbo>> |
<<integrations.adoc#sleuth-runnablecallable-integration, Runnable and Callable>> |
<<integrations.adoc#sleuth-rxjava-integration, RxJava>> |
<<integrations.adoc#sleuth-circuitbreaker-integration, Spring Cloud CircuitBreaker>> |
<<integrations.adoc#sleuth-quartz-integration, Quartz>>

View File

@@ -1,295 +0,0 @@
[[getting-started]]
= Getting Started
include::_attributes.adoc[]
If you are getting started with {project-full-name} or Spring in general, start by reading this section.
It answers the basic "`what?`", "`how?`" and "`why?`" questions.
It includes an introduction to {project-full-name}, along with installation instructions.
We then walk you through building your first {project-full-name} application, discussing some core principles as we go.
[[getting-started-introducing-spring-cloud-sleuth]]
== Introducing Spring Cloud Sleuth
Spring Cloud Sleuth provides API for distributed tracing solution for https://cloud.spring.io[Spring Cloud].
It integrates with https://github.com/openzipkin/brave[OpenZipkin Brave]
Spring Cloud Sleuth is able to trace your requests and messages so that you can correlate that communication to corresponding log entries.
You can also export the tracing information to an external system to visualize latency.
Spring Cloud Sleuth supports https://zipkin.io[OpenZipkin] compatible systems directly.
[[getting-started-terminology]]
=== Terminology
Spring Cloud Sleuth borrows https://research.google.com/pubs/pub36356.html[Dapper's] terminology.
*Span*: The basic unit of work.
For example, sending an RPC is a new span, as is sending a response to an RPC.
Spans also have other data, such as descriptions, timestamped events, key-value annotations (tags), the ID of the span that caused them, and process IDs (normally IP addresses).
Spans can be started and stopped, and they keep track of their timing information.
Once you create a span, you must stop it at some point in the future.
*Trace:* A set of spans forming a tree-like structure.
For example, if you run a distributed big-data store, a trace might be formed by a `PUT` request.
*Annotation/Event:* Used to record the existence of an event in time.
Conceptually in a typical RPC scenario we mark these events to highlight what kind of an action took place (it doesn't mean that physically such an event will be set on a span).
* *cs*: Client Sent.
The client has made a request.
This annotation indicates the start of the span.
* *sr*: Server Received: The server side got the request and started processing it.
Subtracting the `cs` timestamp from this timestamp reveals the network latency.
* *ss*: Server Sent.
Annotated upon completion of request processing (when the response got sent back to the client).
Subtracting the `sr` timestamp from this timestamp reveals the time needed by the server side to process the request.
* *cr*: Client Received.
Signifies the end of the span.
The client has successfully received the response from the server side.
Subtracting the `cs` timestamp from this timestamp reveals the whole time needed by the client to receive the response from the server.
The following image shows how *Span* and *Trace* look in a system.
image::{github-raw}/docs/src/main/asciidoc/images/trace-id.jpg[Trace Info propagation]
Each color of a note signifies a span (there are seven spans - from *A* to *G*).
Consider the following note:
[source]
----
Trace Id = X
Span Id = D
Client Sent
----
This note indicates that the current span has *Trace Id* set to *X* and *Span Id* set to *D*.
Also, from the RPC perspective, the `Client Sent` event took place.
Let's consider more notes:
[source]
----
Trace Id = X
Span Id = A
(no custom span)
Trace Id = X
Span Id = C
(custom span)
----
You can continue with a created span (example with `no custom span` indication) or you can create child spans manually (example with `custom span` indication).
The following image shows how parent-child relationships of spans look:
image::{github-raw}/docs/src/main/asciidoc/images/parents.jpg[Parent child relationship]
[[getting-started-first-application]]
== Developing Your First Spring Cloud sleuth-based Application
This section describes how to develop a small “Hello World!” web application that highlights some of Spring Cloud Sleuths key features.
We use Maven to build this project, since most IDEs support it.
As the tracer implementation we'll use https://github.com/openzipkin/brave[OpenZipkin Brave].
[TIP]
====
You can shortcut the steps below by going to https://start.spring.io and choosing the "Web" and "Spring Cloud Sleuth" starters from the dependencies searcher.
Doing so generates a new project structure so that you can <<getting-started-first-application-code,start coding right away>>.
====
[[getting-started-first-application-pom]]
=== Creating the POM
We need to start by creating a Maven `pom.xml` file.
The `pom.xml` is the recipe that is used to build your project.
Open your favorite text editor and add the following:
[source,xml,indent=0,subs="verbatim,quotes,attributes"]
----
<?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>
<groupId>com.example</groupId>
<artifactId>myproject</artifactId>
<version>0.0.1-SNAPSHOT</version>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<!-- Use the latest compatible Spring Boot version. You can check https://spring.io/projects/spring-cloud for more information -->
<version>${spring-boot-version}</version>
</parent>
<!-- Spring Cloud Sleuth requires a Spring Cloud BOM -->
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<!-- Provide the latest stable Spring Cloud release train version (e.g. 2020.0.0) -->
<version>${release.train.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<!-- (you don't need this if you are using a GA version) -->
<repositories>
<repository>
<id>spring-snapshots</id>
<url>https://repo.spring.io/snapshot</url>
<snapshots><enabled>true</enabled></snapshots>
</repository>
<repository>
<id>spring-milestones</id>
<url>https://repo.spring.io/milestone</url>
</repository>
</repositories>
<pluginRepositories>
<pluginRepository>
<id>spring-snapshots</id>
<url>https://repo.spring.io/snapshot</url>
</pluginRepository>
<pluginRepository>
<id>spring-milestones</id>
<url>https://repo.spring.io/milestone</url>
</pluginRepository>
</pluginRepositories>
</project>
----
The preceding listing should give you a working build.
You can test it by running `mvn package` (for now, you can ignore the "`jar will be empty - no content was marked for inclusion!`" warning).
NOTE: At this point, you could import the project into an IDE (most modern Java IDEs include built-in support for Maven).
For simplicity, we continue to use a plain text editor for this example.
[[getting-started-first-application-dependencies]]
=== Adding Classpath Dependencies
To add the necessary dependencies, edit your `pom.xml` and add the `spring-boot-starter-web` dependency immediately below the `parent` section:
[source,xml,indent=0,subs="verbatim,quotes,attributes"]
----
<dependencies>
<!-- Boot's Web support -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- Sleuth with Brave tracer implementation -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-sleuth</artifactId>
</dependency>
</dependencies>
----
[[getting-started-first-application-code]]
=== Writing the Code
To finish our application, we need to create a single Java file.
By default, Maven compiles sources from `src/main/java`, so you need to create that directory structure and then add a file named `src/main/java/Example.java` to contain the following code:
[source,java,indent=0]
----
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.*;
import org.springframework.boot.autoconfigure.*;
import org.springframework.web.bind.annotation.*;
@RestController
@EnableAutoConfiguration
public class Example {
private static final Logger log = LoggerFactory.getLogger(Example.class);
@RequestMapping("/")
String home() {
log.info("Hello world!");
return "Hello World!";
}
public static void main(String[] args) {
SpringApplication.run(Example.class, args);
}
}
----
Although there is not much code here, quite a lot is going on.
We step through the important parts in the next few sections.
[getting-started-first-application-annotations]]
==== The @RestController and @RequestMapping Annotations
Spring Boot sets up the Rest Controller and makes our application bind to a Tomcat port.
Spring Cloud Sleuth with Brave tracer will provide instrumentation of the incoming request.
[[getting-started-first-application-run]]
=== Running the Example
At this point, your application should work.
Since you used the `spring-boot-starter-parent` POM, you have a useful `run` goal that you can use to start the application.
Type `SPRING_APPLICATION_NAME=backend mvn spring-boot:run` from the root project directory to start the application.
You should see output similar to the following:
[indent=0,subs="attributes"]
----
$ mvn spring-boot:run
. ____ _ __ _ _
/\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
\\/ ___)| |_)| | | | | || (_| | ) ) ) )
' |____| .__|_| |_|_| |_\__, | / / / /
=========|_|==============|___/=/_/_/_/
...
....... . . .
....... . . . (log output here)
....... . . .
........ Started Example in 2.222 seconds (JVM running for 6.514)
----
If you open a web browser to `http://localhost:8080`, you should see the following output:
[indent=0]
----
Hello World!
----
If you check the logs you should see a similar output
[indent=0]
----
2020-10-21 12:01:16.285 INFO [backend,0b6aaf642574edd3,0b6aaf642574edd3] 289589 --- [nio-9000-exec-1] Example : Hello world!
----
You can notice that the logging format has been updated with the following information `[backend,0b6aaf642574edd3,0b6aaf642574edd3`.
This entry corresponds to `[application name,trace id, span id]`.
The application name got read from the `SPRING_APPLICATION_NAME` environment variable.
NOTE: Instead of logging the request in the handler explicitly, you could set `logging.level.org.springframework.web.servlet.DispatcherServlet=DEBUG`.
To gracefully exit the application, press `ctrl-c`.
[[getting-started-whats-next]]
== Next Steps
Hopefully, this section provided some of the {project-full-name} basics and got you on your way to writing your own applications.
If you are a task-oriented type of developer, you might want to jump over to https://spring.io and check out some of the
https://spring.io/guides/[getting started] guides that solve specific "`How do I do that with Spring?`" problems.
We also have {project-full-name}-specific "`<<howto.adoc#howto, how-to>>`" reference documentation.
Otherwise, the next logical step is to read <<using.adoc#using, Using {project-full-name}>>.
If you are really impatient, you could also jump ahead and read about
<<project-features.adoc#project-features, {project-full-name} features>>.
You can find the default project samples at
https://github.com/spring-cloud/spring-cloud-sleuth/tree/{branch}/spring-cloud-sleuth-samples[samples].

View File

@@ -1,330 +0,0 @@
#!/bin/bash -x
set -e
# Set default props like MAVEN_PATH, ROOT_FOLDER etc.
function set_default_props() {
# The script should be run from the root folder
ROOT_FOLDER=`pwd`
echo "Current folder is ${ROOT_FOLDER}"
if [[ ! -e "${ROOT_FOLDER}/.git" ]]; then
echo "You're not in the root folder of the project!"
exit 1
fi
# Prop that will let commit the changes
COMMIT_CHANGES="no"
MAVEN_PATH=${MAVEN_PATH:-}
echo "Path to Maven is [${MAVEN_PATH}]"
REPO_NAME=${PWD##*/}
echo "Repo name is [${REPO_NAME}]"
SPRING_CLOUD_STATIC_REPO=${SPRING_CLOUD_STATIC_REPO:-git@github.com:spring-cloud/spring-cloud-static.git}
echo "Spring Cloud Static repo is [${SPRING_CLOUD_STATIC_REPO}"
}
# Check if gh-pages exists and docs have been built
function check_if_anything_to_sync() {
git remote set-url --push origin `git config remote.origin.url | sed -e 's/^git:/https:/'`
if ! (git remote set-branches --add origin gh-pages && git fetch -q); then
echo "No gh-pages, so not syncing"
exit 0
fi
if ! [ -d docs/target/generated-docs ] && ! [ "${BUILD}" == "yes" ]; then
echo "No gh-pages sources in docs/target/generated-docs, so not syncing"
exit 0
fi
}
function retrieve_current_branch() {
# Code getting the name of the current branch. For master we want to publish as we did until now
# https://stackoverflow.com/questions/1593051/how-to-programmatically-determine-the-current-checked-out-git-branch
# If there is a branch already passed will reuse it - otherwise will try to find it
CURRENT_BRANCH=${BRANCH}
if [[ -z "${CURRENT_BRANCH}" ]] ; then
CURRENT_BRANCH=$(git symbolic-ref -q HEAD)
CURRENT_BRANCH=${CURRENT_BRANCH##refs/heads/}
CURRENT_BRANCH=${CURRENT_BRANCH:-HEAD}
fi
echo "Current branch is [${CURRENT_BRANCH}]"
git checkout ${CURRENT_BRANCH} || echo "Failed to check the branch... continuing with the script"
}
# Switches to the provided value of the release version. We always prefix it with `v`
function switch_to_tag() {
git checkout v${VERSION}
}
# Build the docs if switch is on
function build_docs_if_applicable() {
if [[ "${BUILD}" == "yes" ]] ; then
./mvnw clean install -P docs -pl docs -DskipTests
fi
}
# Get the name of the `docs.main` property
# Get allowed branches - assumes that a `docs` module is available under `docs` profile
function retrieve_doc_properties() {
MAIN_ADOC_VALUE=$("${MAVEN_PATH}"mvn -q \
-Dexec.executable="echo" \
-Dexec.args='${docs.main}' \
--non-recursive \
org.codehaus.mojo:exec-maven-plugin:1.3.1:exec)
echo "Extracted 'main.adoc' from Maven build [${MAIN_ADOC_VALUE}]"
ALLOW_PROPERTY=${ALLOW_PROPERTY:-"docs.allowed.branches"}
ALLOWED_BRANCHES_VALUE=$("${MAVEN_PATH}"mvn -q \
-Dexec.executable="echo" \
-Dexec.args="\${${ALLOW_PROPERTY}}" \
org.codehaus.mojo:exec-maven-plugin:1.3.1:exec \
-P docs \
-pl docs)
echo "Extracted '${ALLOW_PROPERTY}' from Maven build [${ALLOWED_BRANCHES_VALUE}]"
}
# Stash any outstanding changes
function stash_changes() {
git diff-index --quiet HEAD && dirty=$? || (echo "Failed to check if the current repo is dirty. Assuming that it is." && dirty="1")
if [ "$dirty" != "0" ]; then git stash; fi
}
# Switch to gh-pages branch to sync it with current branch
function add_docs_from_target() {
local DESTINATION_REPO_FOLDER
if [[ -z "${DESTINATION}" && -z "${CLONE}" ]] ; then
DESTINATION_REPO_FOLDER=${ROOT_FOLDER}
elif [[ "${CLONE}" == "yes" ]]; then
mkdir -p ${ROOT_FOLDER}/target
local clonedStatic=${ROOT_FOLDER}/target/spring-cloud-static
if [[ ! -e "${clonedStatic}/.git" ]]; then
echo "Cloning Spring Cloud Static to target"
git clone ${SPRING_CLOUD_STATIC_REPO} ${clonedStatic} && git checkout gh-pages
else
echo "Spring Cloud Static already cloned - will pull changes"
cd ${clonedStatic} && git checkout gh-pages && git pull origin gh-pages
fi
DESTINATION_REPO_FOLDER=${clonedStatic}/${REPO_NAME}
mkdir -p ${DESTINATION_REPO_FOLDER}
else
if [[ ! -e "${DESTINATION}/.git" ]]; then
echo "[${DESTINATION}] is not a git repository"
exit 1
fi
DESTINATION_REPO_FOLDER=${DESTINATION}/${REPO_NAME}
mkdir -p ${DESTINATION_REPO_FOLDER}
echo "Destination was provided [${DESTINATION}]"
fi
cd ${DESTINATION_REPO_FOLDER}
git checkout gh-pages
git pull origin gh-pages
# Add git branches
###################################################################
if [[ -z "${VERSION}" ]] ; then
copy_docs_for_current_version
else
copy_docs_for_provided_version
fi
commit_changes_if_applicable
}
# Copies the docs by using the retrieved properties from Maven build
function copy_docs_for_current_version() {
if [[ "${CURRENT_BRANCH}" == "master" ]] ; then
echo -e "Current branch is master - will copy the current docs only to the root folder"
for f in docs/target/generated-docs/*; do
file=${f#docs/target/generated-docs/*}
if ! git ls-files -i -o --exclude-standard --directory | grep -q ^$file$; then
# Not ignored...
cp -rf $f ${ROOT_FOLDER}/
git add -A ${ROOT_FOLDER}/$file
fi
done
COMMIT_CHANGES="yes"
else
echo -e "Current branch is [${CURRENT_BRANCH}]"
# https://stackoverflow.com/questions/29300806/a-bash-script-to-check-if-a-string-is-present-in-a-comma-separated-list-of-strin
if [[ ",${ALLOWED_BRANCHES_VALUE}," = *",${CURRENT_BRANCH},"* ]] ; then
mkdir -p ${ROOT_FOLDER}/${CURRENT_BRANCH}
echo -e "Branch [${CURRENT_BRANCH}] is allowed! Will copy the current docs to the [${CURRENT_BRANCH}] folder"
for f in docs/target/generated-docs/*; do
file=${f#docs/target/generated-docs/*}
if ! git ls-files -i -o --exclude-standard --directory | grep -q ^$file$; then
# Not ignored...
# We want users to access 1.0.0.RELEASE/ instead of 1.0.0.RELEASE/spring-cloud.sleuth.html
if [[ "${file}" == "${MAIN_ADOC_VALUE}.html" ]] ; then
# We don't want to copy the spring-cloud-sleuth.html
# we want it to be converted to index.html
cp -rf $f ${ROOT_FOLDER}/${CURRENT_BRANCH}/index.html
git add -A ${ROOT_FOLDER}/${CURRENT_BRANCH}/index.html
else
cp -rf $f ${ROOT_FOLDER}/${CURRENT_BRANCH}
git add -A ${ROOT_FOLDER}/${CURRENT_BRANCH}/$file
fi
fi
done
COMMIT_CHANGES="yes"
else
echo -e "Branch [${CURRENT_BRANCH}] is not on the allow list! Check out the Maven [${ALLOW_PROPERTY}] property in
[docs] module available under [docs] profile. Won't commit any changes to gh-pages for this branch."
fi
fi
}
# Copies the docs by using the explicitly provided version
function copy_docs_for_provided_version() {
local FOLDER=${DESTINATION_REPO_FOLDER}/${VERSION}
mkdir -p ${FOLDER}
echo -e "Current tag is [v${VERSION}] Will copy the current docs to the [${FOLDER}] folder"
for f in ${ROOT_FOLDER}/docs/target/generated-docs/*; do
file=${f#${ROOT_FOLDER}/docs/target/generated-docs/*}
copy_docs_for_branch ${file} ${FOLDER}
done
COMMIT_CHANGES="yes"
CURRENT_BRANCH="v${VERSION}"
}
# Copies the docs from target to the provided destination
# Params:
# $1 - file from target
# $2 - destination to which copy the files
function copy_docs_for_branch() {
local file=$1
local destination=$2
if ! git ls-files -i -o --exclude-standard --directory | grep -q ^${file}$; then
# Not ignored...
# We want users to access 1.0.0.RELEASE/ instead of 1.0.0.RELEASE/spring-cloud.sleuth.html
if [[ ("${file}" == "${MAIN_ADOC_VALUE}.html") || ("${file}" == "${REPO_NAME}.html") ]] ; then
# We don't want to copy the spring-cloud-sleuth.html
# we want it to be converted to index.html
cp -rf $f ${destination}/index.html
git add -A ${destination}/index.html
else
cp -rf $f ${destination}
git add -A ${destination}/$file
fi
fi
}
function commit_changes_if_applicable() {
if [[ "${COMMIT_CHANGES}" == "yes" ]] ; then
COMMIT_SUCCESSFUL="no"
git commit -a -m "Sync docs from ${CURRENT_BRANCH} to gh-pages" && COMMIT_SUCCESSFUL="yes" || echo "Failed to commit changes"
# Uncomment the following push if you want to auto push to
# the gh-pages branch whenever you commit to master locally.
# This is a little extreme. Use with care!
###################################################################
if [[ "${COMMIT_SUCCESSFUL}" == "yes" ]] ; then
git push origin gh-pages
fi
fi
}
# Switch back to the previous branch and exit block
function checkout_previous_branch() {
# If -version was provided we need to come back to root project
cd ${ROOT_FOLDER}
git checkout ${CURRENT_BRANCH} || echo "Failed to check the branch... continuing with the script"
if [ "$dirty" != "0" ]; then git stash pop; fi
exit 0
}
# Assert if properties have been properly passed
function assert_properties() {
echo "VERSION [${VERSION}], DESTINATION [${DESTINATION}], CLONE [${CLONE}]"
if [[ "${VERSION}" != "" && (-z "${DESTINATION}" && -z "${CLONE}") ]] ; then echo "Version was set but destination / clone was not!"; exit 1;fi
if [[ ("${DESTINATION}" != "" && "${CLONE}" != "") && -z "${VERSION}" ]] ; then echo "Destination / clone was set but version was not!"; exit 1;fi
if [[ "${DESTINATION}" != "" && "${CLONE}" == "yes" ]] ; then echo "Destination and clone was set. Pick one!"; exit 1;fi
}
# Prints the usage
function print_usage() {
cat <<EOF
The idea of this script is to update gh-pages branch with the generated docs. Without any options
the script will work in the following manner:
- if there's no gh-pages / target for docs module then the script ends
- for master branch the generated docs are copied to the root of gh-pages branch
- for any other branch (if that branch is allowed) a subfolder with branch name is created
and docs are copied there
- if the version switch is passed (-v) then a tag with (v) prefix will be retrieved and a folder
with that version number will be created in the gh-pages branch. WARNING! No allow verification will take place
- if the destination switch is passed (-d) then the script will check if the provided dir is a git repo and then will
switch to gh-pages of that repo and copy the generated docs to `docs/<project-name>/<version>`
- if the destination switch is passed (-d) then the script will check if the provided dir is a git repo and then will
switch to gh-pages of that repo and copy the generated docs to `docs/<project-name>/<version>`
USAGE:
You can use the following options:
-v|--version - the script will apply the whole procedure for a particular library version
-d|--destination - the root of destination folder where the docs should be copied. You have to use the full path.
E.g. point to spring-cloud-static folder. Can't be used with (-c)
-b|--build - will run the standard build process after checking out the branch
-c|--clone - will automatically clone the spring-cloud-static repo instead of providing the destination.
Obviously can't be used with (-d)
EOF
}
# ==========================================
# ____ ____ _____ _____ _____ _______
# / ____|/ ____| __ \|_ _| __ \__ __|
# | (___ | | | |__) | | | | |__) | | |
# \___ \| | | _ / | | | ___/ | |
# ____) | |____| | \ \ _| |_| | | |
# |_____/ \_____|_| \_\_____|_| |_|
#
# ==========================================
while [[ $# > 0 ]]
do
key="$1"
case ${key} in
-v|--version)
VERSION="$2"
shift # past argument
;;
-d|--destination)
DESTINATION="$2"
shift # past argument
;;
-b|--build)
BUILD="yes"
;;
-c|--clone)
CLONE="yes"
;;
-h|--help)
print_usage
exit 0
;;
*)
echo "Invalid option: [$1]"
print_usage
exit 1
;;
esac
shift # past argument or value
done
assert_properties
set_default_props
check_if_anything_to_sync
if [[ -z "${VERSION}" ]] ; then
retrieve_current_branch
else
switch_to_tag
fi
build_docs_if_applicable
retrieve_doc_properties
stash_changes
add_docs_from_target
checkout_previous_branch

View File

@@ -1,477 +0,0 @@
[[howto]]
= "`How-to`" Guides
include::_attributes.adoc[]
This section provides answers to some common "`how do I do that...?`" questions that often arise when using {project-full-name}.
Its coverage is not exhaustive, but it does cover quite a lot.
If you have a specific problem that we do not cover here, you might want to check out
https://stackoverflow.com/tags/{project-name}[stackoverflow.com] to see if someone has already provided an answer.
Stack Overflow is also a great place to ask new questions (please use the `{project-name}` tag).
We are also more than happy to extend this section.
If you want to add a "`how-to`", send us a {github-code}[pull request].
[[how-to-set-up-sleuth-with-brave]]
== How to Set Up Sleuth with Brave?
Add the Sleuth starter to the classpath.
====
[source,xml,indent=0,subs="verbatim,attributes",role="primary"]
.Maven
----
<dependencyManagement>
<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>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-sleuth</artifactId>
</dependency>
----
[source,groovy,indent=0,subs="verbatim,attributes",role="secondary"]
.Gradle
----
dependencyManagement {
imports {
mavenBom "org.springframework.cloud:spring-cloud-dependencies:${releaseTrainVersion}"
}
}
dependencies {
implementation "org.springframework.cloud:spring-cloud-starter-sleuth"
}
----
====
[[how-to-set-up-sleuth-with-brave-zipkin-http]]
== How to Set Up Sleuth with Brave & Zipkin via HTTP?
Add the Sleuth starter and Zipkin to the classpath.
====
[source,xml,indent=0,subs="verbatim,attributes",role="primary"]
.Maven
----
<dependencyManagement>
<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>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-sleuth</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-sleuth-zipkin</artifactId>
</dependency>
----
[source,groovy,indent=0,subs="verbatim,attributes",role="secondary"]
.Gradle
----
dependencyManagement {
imports {
mavenBom "org.springframework.cloud:spring-cloud-dependencies:${releaseTrainVersion}"
}
}
dependencies {
implementation "org.springframework.cloud:spring-cloud-starter-sleuth"
implementation "org.springframework.cloud:spring-cloud-sleuth-zipkin"
}
----
====
[[how-to-set-up-sleuth-with-brave-zipkin-messaging]]
== How to Set Up Sleuth with Brave & Zipkin via Messaging?
If you want to use RabbitMQ, Kafka or ActiveMQ instead of HTTP, add the `spring-rabbit`, `spring-kafka` or `org.apache.activemq:activemq-client` dependency.
The default destination name is `Zipkin`.
If using Kafka, you must add the Kafka dependency.
====
[source,xml,indent=0,subs="verbatim,attributes",role="primary"]
.Maven
----
<dependencyManagement>
<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>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-sleuth</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-sleuth-zipkin</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.kafka</groupId>
<artifactId>spring-kafka</artifactId>
</dependency>
----
[source,groovy,indent=0,subs="verbatim,attributes",role="secondary"]
.Gradle
----
dependencyManagement {
imports {
mavenBom "org.springframework.cloud:spring-cloud-dependencies:${releaseTrainVersion}"
}
}
dependencies {
implementation "org.springframework.cloud:spring-cloud-starter-sleuth"
implementation "org.springframework.cloud:spring-cloud-sleuth-zipkin"
implementation "org.springframework.kafka:spring-kafka"
}
----
====
Also, you need to set the property `spring.zipkin.sender.type` property accordingly:
[source,yaml]
----
spring.zipkin.sender.type: kafka
----
If you want Sleuth over RabbitMQ, add the `spring-cloud-starter-sleuth`, `spring-cloud-sleuth-zipkin` and `spring-rabbit` dependencies.
====
[source,xml,indent=0,subs="verbatim,attributes",role="primary"]
.Maven
----
<dependencyManagement>
<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>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-sleuth</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-sleuth-zipkin</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.amqp</groupId>
<artifactId>spring-rabbit</artifactId>
</dependency>
----
[source,groovy,indent=0,subs="verbatim,attributes",role="secondary"]
.Gradle
----
dependencyManagement {
imports {
mavenBom "org.springframework.cloud:spring-cloud-dependencies:${releaseTrainVersion}"
}
}
dependencies {
implementation "org.springframework.cloud:spring-cloud-starter-sleuth"
implementation "org.springframework.cloud:spring-cloud-sleuth-zipkin"
implementation "org.springframework.amqp:spring-rabbit"
}
----
====
If you want Sleuth over ActiveMQ, add the `spring-cloud-starter-sleuth`, `spring-cloud-sleuth-zipkin` and `activemq-client` dependencies.
====
[source,xml,indent=0,subs="verbatim,attributes",role="primary"]
.Maven
----
<dependencyManagement>
<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>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-sleuth</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-sleuth-zipkin</artifactId>
</dependency>
<dependency>
<groupId>org.apache.activemq</groupId>
<artifactId>activemq-client</artifactId>
</dependency>
----
[source,groovy,indent=0,subs="verbatim,attributes",role="secondary"]
.Gradle
----
dependencyManagement {
imports {
mavenBom "org.springframework.cloud:spring-cloud-dependencies:${releaseTrainVersion}"
}
}
dependencies {
implementation "org.springframework.cloud:spring-cloud-starter-sleuth"
implementation "org.springframework.cloud:spring-cloud-sleuth-zipkin"
implementation "org.apache.activemq:activemq-client"
}
----
====
Also, you need to set the property `spring.zipkin.sender.type` property accordingly:
[source,yaml]
----
spring.zipkin.sender.type: activemq
----
[[how-to-see-spans-in-an-external-system]]
== How to See Spans in an External System?
If you can't see spans get reported to an external system (e.g. Zipkin), then it's most likely due to the following causes:
* <<not-sampled-span,Your span is not being sampled>>
* <<missing-dependency,You have forgotten to add the dependency to report to an external system (e.g. `spring-cloud-sleuth-zipkin`)>>
* <<connection-misconfiguration,You have misconfigured the connection to the external system>>
[[not-sampled-span]]
=== Your Span Is Not Being Sampled
In order to check if the span is not being sampled it's enough to see if the exportable flag is being set.
Let's look at the following example:
[indent=0]
----
2020-10-21 12:01:16.285 INFO [backend,0b6aaf642574edd3,0b6aaf642574edd3,true] 289589 --- [nio-9000-exec-1] Example : Hello world!
----
If the boolean value in the section `[backend,0b6aaf642574edd3,0b6aaf642574edd3,true]` is `true` means that the span is being sampled and should be reported.
[[missing-dependency]]
=== Missing Dependency
Up till Sleuth 3.0.0 the dependency `spring-cloud-starter-zipkin` included the `spring-cloud-starter-sleuth` dependency and the `spring-cloud-sleuth-zipkin` dependency.
With 3.0.0 `spring-cloud-starter-zipkin` was removed, so you need to change it to `spring-cloud-sleuth-zipkin`.
[[connection-misconfiguration]]
=== Connection Misconfiguration
Double check if the remote system address is correct (e.g. `spring.zipkin.baseUrl`) and that if trying to communicate over the broker, your broker connection is set up properly.
[[how-to-make-components-work]]
== How to Make RestTemplate, WebClient, etc. Work?
If you're observing that the tracing context is not being propagated then cause is one of the following:
* We are not instrumenting the given library
* We are instrumenting the library, however you misconfigured the setup
In case of lack of instrumentation capabilities please file https://github.com/spring-cloud/spring-cloud-sleuth/issues[an issue] with a request to add such instrumentation.
In case of the misconfiguration please ensure that the client you're using to communicate is a Spring bean.
If you create the client manually via the `new` operator the instrumentation will not work.
Example where instrumentation will work:
====
[source,java,indent=0]
----
import org.springframework.context.annotation.Configuration;
import org.springframework.web.client.RestTemplate;
@Configuration(proxyBeanMethods = false)
class MyConfiguration {
@Bean RestTemplate myRestTemplate() {
return new RestTemplate();
}
}
@Service
class MyService {
private final RestTemplate restTemplate;
MyService(RestTemplate restTemplate) {
this.restTemplate = restTemplate;
}
String makeACall() {
return this.restTemplate.getForObject("http://example.com", String.class);
}
}
----
====
Example where instrumentation will **NOT** work:
====
[source,java,indent=0]
----
@Service
class MyService {
String makeACall() {
// This will not work because RestTemplate is not a bean
return new RestTemplate().getForObject("http://example.com", String.class);
}
}
----
====
[[how-to-add-headers-to-the-http-server-response]]
== How to Add Headers to the HTTP Server Response?
Register a filter that will set the server response.
====
[source,java,indent=0]
----
import org.springframework.cloud.sleuth.Span;
import org.springframework.cloud.sleuth.Tracer;
import javax.servlet.Filter;
import org.springframework.web.server.WebFilter;
@Configuration(proxyBeanMethods = false)
class MyConfig {
// Example of a servlet Filter for non-reactive applications
@Bean
Filter traceIdInResponseFilter(Tracer tracer) {
return (request, response, chain) -> {
Span currentSpan = tracer.currentSpan();
if (currentSpan != null) {
HttpServletResponse resp = (HttpServletResponse) response;
// putting trace id value in [mytraceid] response header
resp.addHeader("mytraceid", currentSpan.context().traceId());
}
chain.doFilter(request, response);
};
}
// Example of a reactive WebFilter for reactive applications
@Bean
WebFilter traceIdInResponseFilter(Tracer tracer) {
return (exchange, chain) -> {
Span currentSpan = tracer.currentSpan();
if (currentSpan != null) {
// putting trace id value in [mytraceid] response header
exchange.getResponse().getHeaders().add("mytraceid", currentSpan.context().traceId());
}
return chain.filter(exchange);
};
}
}
----
====
IMPORTANT: Your spans need to be sampled for the parser to work. That means that you need to be able to export spans to e.g. Zipkin.
[[how-to-cutomize-http-client-spans]]
== How to Customize HTTP Client Spans?
Register a bean of `HttpRequestParser` type whose name is `HttpClientRequestParser.NAME` to add customization for the request side.
Register a bean of `HttpResponseParser` type whose name is `HttpClientRequestParser.NAME` to add customization for the response side.
====
[source,java,indent=0]
----
include::{common_tests_path}/src/main/java/org/springframework/cloud/sleuth/instrument/web/client/integration/parser/WebClientCustomParserTests.java[tags=client_parser_config,indent=0]
----
====
[[how-to-cutomize-http-server-spans]]
== How to Customize HTTP Server Spans?
Register a bean of `HttpRequestParser` type whose name is `HttpServerRequestParser.NAME` to add customization for the request side.
Register a bean of `HttpResponseParser` type whose name is `HttpServerResponseParser.NAME` to add customization for the response side.
====
[source,java,indent=0]
----
include::{common_tests_path}/src/main/java/org/springframework/cloud/sleuth/instrument/web/HttpServerParserTests.java[tags=server_parser_config,indent=0]
----
====
IMPORTANT: Your spans need to be sampled for the parser to work. That means that you need to be able to export spans to e.g. Zipkin.
[[how-to-see-application-name-in-logs]]
== How to See the Application Name in Logs?
Assuming that you haven't changed the default logging format set the `spring.application.name` property in `bootstrap.yml`, not in `application.yml`.
TIP: With the new Spring Cloud configuration bootstrap this should no longer be required since there will be no Bootstrap Context anymore.
[[how-to-change-context-propagation]]
== How to Change The Context Propagation Mechanism?
To use the provided defaults you can set the `spring.sleuth.propagation.type` property.
The value can be a list in which case you will propagate more tracing headers.
For Brave we support `AWS`, `B3`, `W3C` propagation types.
If you want to provide a custom propagation mechanism set the `spring.sleuth.propagation.type` property to `CUSTOM` and implement your own bean (`Propagation.Factory` for Brave).
Below you can find the examples:
====
[source,java,indent=0,subs="verbatim,attributes"]
----
@Component
include::{autoconfig_path}/src/test/java/org/springframework/cloud/sleuth/autoconfig/brave/BravePropagationTests.java[tags=custom_propagator,indent=0]
----
====
[[how-to-implement-own-tracer]]
== How to Implement My Own Tracer?
Spring Cloud Sleuth API contains all necessary interfaces to be implemented by a tracer.
The project comes with OpenZipkin Brave implementation.
You can check how both tracers are bridged to the Sleuth's API by looking at the `org.springframework.cloud.sleuth.brave.bridge` module.

View File

@@ -1 +0,0 @@

Binary file not shown.

Before

Width:  |  Height:  |  Size: 183 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 54 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 46 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 68 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 66 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 36 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 52 KiB

View File

@@ -1 +0,0 @@
include::spring-cloud-sleuth.adoc[]

View File

@@ -1,803 +0,0 @@
[[sleuth-integration]]
= Spring Cloud Sleuth customization
include::_attributes.adoc[]
In this section, we describe how to customize various parts of Spring Cloud Sleuth. Please check the <<appendix.adoc#sleuth-spans,appendix>> for the list of spans, tags and events.
[[sleuth-kafka-integration]]
== Apache Kafka
This feature is available for all tracer implementations.
We decorate the Kafka clients (`KafkaProducer` and `KafkaConsumer`) to create a span for each event that is produced or consumed. You can disable this feature by setting the value of `spring.sleuth.kafka.enabled` to `false`.
IMPORTANT: You have to register the `Producer` or `Consumer` as beans in order for Sleuth's auto-configuration to decorate them. When you then inject the beans, the expected type must be `Producer` or `Consumer` (and NOT e.g. `KafkaProducer`).
We also provide `TracingKafkaProducerFactory` and `TracingKafkaConsumerFactory` to be used with the https://projectreactor.io/docs/kafka/release/reference/[Reactor Kafka] clients (`KafkaSender` and `KafkaReceiver`, respectively). See an example in the snippet below:
[source,java,indent=0]
----
@Bean
KafkaReceiver<String, String> reactiveKafkaReceiver(TracingKafkaConsumerFactory tracingKafkaConsumerFactory, KafkaReceiverOptions kafkaReceiverOptions) {
return KafkaReceiver.create(tracingKafkaConsumerFactory, kafkaReceiverOptions);
}
----
Additionally, we decorate any https://docs.spring.io/spring-kafka/docs/current/reference/html/[Spring Kafka] `ProducerFactory` and `ConsumerFactory` available in the context. However, this is disabled if Brave instrumentation is on the classpath.
[[sleuth-async-integration]]
== Asynchronous Communication
In this section, we describe how to customize asynchronous communication with Spring Cloud Sleuth.
[[sleuth-async-annotation-integration]]
=== `@Async` Annotated methods
This feature is available for all tracer implementations.
In Spring Cloud Sleuth, we instrument async-related components so that the tracing information is passed between threads.
You can disable this behavior by setting the value of `spring.sleuth.async.enabled` to `false`.
If you annotate your method with `@Async`, we automatically modify the existing Span as follows:
* If the method is annotated with `@SpanName`, the value of the annotation is the Span's name.
* If the method is not annotated with `@SpanName`, the Span name is the annotated method name.
* The span is tagged with the method's class name and method name.
Since we're modifying the existing span, if you want to maintain its original name (e.g. a span created by receiving an HTTP request)
you should wrap your `@Async` annotated method with a `@NewSpan` annotation or create a new span manually.
[[sleuth-async-scheduled-integration]]
=== `@Scheduled` Annotated Methods
This feature is available for all tracer implementations.
In Spring Cloud Sleuth, we instrument scheduled method execution so that the tracing information is passed between threads.
You can disable this behavior by setting the value of `spring.sleuth.scheduled.enabled` to `false`.
If you annotate your method with `@Scheduled`, we automatically create a new span with the following characteristics:
* The span name is the annotated method name.
* The span is tagged with the method's class name and method name.
If you want to skip span creation for some `@Scheduled` annotated classes, you can set the `spring.sleuth.scheduled.skipPattern` with a regular expression that matches the fully qualified name of the `@Scheduled` annotated class.
[[sleuth-async-executor-service-integration]]
=== Executor, ExecutorService, and ScheduledExecutorService
This feature is available for all tracer implementations.
We provide `LazyTraceExecutor`, `TraceableExecutorService`, and `TraceableScheduledExecutorService`.
Those implementations create spans each time a new task is submitted, invoked, or scheduled.
The following example shows how to pass tracing information with `TraceableExecutorService` when working with `CompletableFuture`:
[source,java,indent=0]
----
include::{common_tests_path}/src/main/java/org/springframework/cloud/sleuth/instrument/async/TraceableExecutorServiceTests.java[tags=completablefuture,indent=0]
----
IMPORTANT: Sleuth does not work with `parallelStream()` out of the box.
If you want to have the tracing information propagated through the stream, you have to use the approach with `supplyAsync(...)`, as shown earlier.
If there are beans that implement the `Executor` interface that you would like to exclude from span creation, you can use the `spring.sleuth.async.ignored-beans`
property where you can provide a list of bean names.
You can disable this behavior by setting the value of `spring.sleuth.async.enabled` to `false`.
[[sleuth-async-executor-integration]]
==== Customization of Executors
Sometimes, you need to set up a custom instance of the `AsyncExecutor`.
The following example shows how to set up such a custom `Executor`:
[source,java,indent=0]
----
include::{common_tests_path}/src/main/java/org/springframework/cloud/sleuth/instrument/web/client/MultipleAsyncRestTemplateTests.java[tags=custom_executor,indent=0]
----
TIP: To ensure that your configuration gets post processed, remember to add the `@Role(BeanDefinition.ROLE_INFRASTRUCTURE)` on your
`@Configuration` class
[[sleuth-http-client-integration]]
== HTTP Client Integration
Features from this section can be disabled by setting the `spring.sleuth.web.client.enabled` property with value equal to `false`.
[[sleuth-http-client-rest-template-integration]]
=== Synchronous Rest Template
This feature is available for all tracer implementations.
We inject a `RestTemplate` interceptor to ensure that all the tracing information is passed to the requests.
Each time a call is made, a new Span is created.
It gets closed upon receiving the response.
To block the synchronous `RestTemplate` features, set `spring.sleuth.web.client.enabled` to `false`.
IMPORTANT: You have to register `RestTemplate` as a bean so that the interceptors get injected.
If you create a `RestTemplate` instance with a `new` keyword, the instrumentation does NOT work.
[[sleuth-http-client-async-rest-template-integration]]
=== Asynchronous Rest Template
This feature is available for all tracer implementations.
IMPORTANT: Starting with Sleuth `2.0.0`, we no longer register a bean of `AsyncRestTemplate` type.
It is up to you to create such a bean.
Then we instrument it.
To block the `AsyncRestTemplate` features, set `spring.sleuth.web.async.client.enabled` to `false`.
To disable creation of the default `TraceAsyncClientHttpRequestFactoryWrapper`, set `spring.sleuth.web.async.client.factory.enabled`
to `false`.
If you do not want to create `AsyncRestClient` at all, set `spring.sleuth.web.async.client.template.enabled` to `false`.
[[sleuth-http-client-multiple-async-rest-template-integration]]
==== Multiple Asynchronous Rest Templates
Sometimes you need to use multiple implementations of the Asynchronous Rest Template.
In the following snippet, you can see an example of how to set up such a custom `AsyncRestTemplate`:
[source,java,indent=0]
----
include::{common_tests_path}/src/main/java/org/springframework/cloud/sleuth/instrument/web/client/MultipleAsyncRestTemplateTests.java[tags=custom_async_rest_template,indent=0]
----
[[sleuth-http-client-webclient-integration]]
==== `WebClient`
This feature is available for all tracer implementations.
We inject a `ExchangeFilterFunction` implementation that creates a span and, through on-success and on-error callbacks, takes care of closing client-side spans.
To block this feature, set `spring.sleuth.web.client.enabled` to `false`.
IMPORTANT: You have to register `WebClient` as a bean so that the tracing instrumentation gets applied.
If you create a `WebClient` instance with a `new` keyword, the instrumentation does NOT work.
[[sleuth-http-client-traverson-integration]]
==== Traverson
This feature is available for all tracer implementations.
If you use the https://docs.spring.io/spring-hateoas/docs/current/reference/html/#client.traverson[Traverson] library, you can inject a `RestTemplate` as a bean into your Traverson object.
Since `RestTemplate` is already intercepted, you get full support for tracing in your client.
The following pseudo code shows how to do that:
[source,java,indent=0]
----
@Autowired RestTemplate restTemplate;
Traverson traverson = new Traverson(URI.create("https://some/address"),
MediaType.APPLICATION_JSON, MediaType.APPLICATION_JSON_UTF8).setRestOperations(restTemplate);
// use Traverson
----
[[sleuth-http-client-apache-integration]]
==== Apache `HttpClientBuilder` and `HttpAsyncClientBuilder`
This feature is available for Brave tracer implementation.
We instrument the `HttpClientBuilder` and `HttpAsyncClientBuilder` so that tracing context gets injected to the sent requests.
To block these features, set `spring.sleuth.web.client.enabled` to `false`.
[[sleuth-http-client-netty-integration]]
==== Netty `HttpClient`
This feature is available for all tracer implementations.
We instrument the Netty's `HttpClient`.
To block this feature, set `spring.sleuth.web.client.enabled` to `false`.
IMPORTANT: You have to register `HttpClient` as a bean so that the instrumentation happens.
If you create a `HttpClient` instance with a `new` keyword, the instrumentation does NOT work.
[[sleuth-http-client-userinfo-integration]]
==== `UserInfoRestTemplateCustomizer`
This feature is available for all tracer implementations.
We instrument the Spring Security's `UserInfoRestTemplateCustomizer`.
To block this feature, set `spring.sleuth.web.client.enabled` to `false`.
[[sleuth-http-server-integration]]
== HTTP Server Integration
Features from this section can be disabled by setting the `spring.sleuth.web.enabled` property with value equal to `false`.
[[sleuth-http-server-http-filter-integration]]
=== HTTP Filter
This feature is available for all tracer implementations.
Through the `TracingFilter`, all sampled incoming requests result in creation of a Span.
You can configure which URIs you would like to skip by setting the `spring.sleuth.web.skipPattern` property.
If you have `ManagementServerProperties` on classpath, its value of `contextPath` gets appended to the provided skip pattern.
If you want to reuse the Sleuth's default skip patterns and just append your own, pass those patterns by using the `spring.sleuth.web.additionalSkipPattern`.
By default, all the spring boot actuator endpoints are automatically added to the skip pattern.
If you want to disable this behaviour set `spring.sleuth.web.ignore-auto-configured-skip-patterns`
to `true`.
To change the order of tracing filter registration, please set the
`spring.sleuth.web.filter-order` property.
To disable the filter that logs uncaught exceptions you can disable the
`spring.sleuth.web.exception-throwing-filter-enabled` property.
[[sleuth-http-server-handler-interceptor-integration]]
=== HandlerInterceptor
This feature is available for all tracer implementations.
Since we want the span names to be precise, we use a `TraceHandlerInterceptor` that either wraps an existing `HandlerInterceptor` or is added directly to the list of existing `HandlerInterceptors`.
The `TraceHandlerInterceptor` adds a special request attribute to the given `HttpServletRequest`.
If the the `TracingFilter` does not see this attribute, it creates a "`fallback`" span, which is an additional span created on the server side so that the trace is presented properly in the UI.
If that happens, there is probably missing instrumentation.
In that case, please file an issue in Spring Cloud Sleuth.
[[sleuth-http-server-async-integration]]
=== Async Servlet support
This feature is available for all tracer implementations.
If your controller returns a `Callable` or a `WebAsyncTask`, Spring Cloud Sleuth continues the existing span instead of creating a new one.
[[sleuth-http-server-webflux-integration]]
=== WebFlux support
This feature is available for all tracer implementations.
Through `TraceWebFilter`, all sampled incoming requests result in creation of a Span.
That Span's name is `http:` + the path to which the request was sent.
For example, if the request was sent to `/this/that`, the name is `http:/this/that`.
You can configure which URIs you would like to skip by using the `spring.sleuth.web.skipPattern` property.
If you have `ManagementServerProperties` on the classpath, its value of `contextPath` gets appended to the provided skip pattern.
If you want to reuse Sleuth's default skip patterns and append your own, pass those patterns by using the `spring.sleuth.web.additionalSkipPattern`.
In order to achieve best results in terms of performance and context propagation we suggest that you switch the `spring.sleuth.reactor.instrumentation-type` to `MANUAL`.
In order to execute code with the span in scope you can call `WebFluxSleuthOperators.withSpanInScope`.
Example:
[source,java,indent=0]
-----
include::{project-root}/benchmarks/src/main/java/org/springframework/cloud/sleuth/benchmarks/app/webflux/SleuthBenchmarkingSpringWebFluxApp.java[tags=simple_manual,indent=0]
-----
To change the order of tracing filter registration, please set the
`spring.sleuth.web.filter-order` property.
[[sleuth-messaging-integration]]
== Messaging
Features from this section can be disabled by setting the `spring.sleuth.messaging.enabled` property with value equal to `false`.
[[sleuth-messaging-spring-integration-integration]]
=== Spring Integration
This feature is available for all tracer implementations.
Spring Cloud Sleuth integrates with https://projects.spring.io/spring-integration/[Spring Integration].
It creates spans for publish and subscribe events.
To disable Spring Integration instrumentation, set `spring.sleuth.integration.enabled` to `false`.
You can provide the `spring.sleuth.integration.patterns` pattern to explicitly provide the names of channels that you want to include for tracing.
By default, all channels but `hystrixStreamOutput` channel are included.
IMPORTANT: When using the `Executor` to build a Spring Integration `IntegrationFlow`, you must use the untraced version of the `Executor`.
Decorating the Spring Integration Executor Channel with `TraceableExecutorService` causes the spans to be improperly closed.
If you want to customize the way tracing context is read from and written to message headers, it's enough for you to register beans of types:
* `Propagator.Setter<MessageHeaderAccessor>` - for writing headers to the message
* `Propagator.Getter<MessageHeaderAccessor>` - for reading headers from the message
[[sleuth-messaging-spring-integration-customization]]
==== Spring Integration Customization
==== Customizing messaging spans
In order to change the default span names and tags, just register a bean of type `MessageSpanCustomizer`. You can also
override the existing `DefaultMessageSpanCustomizer` to extend the existing behaviour.
[source,java]
----
@Component
include::{common_tests_path}/src/main/java/org/springframework/cloud/sleuth/instrument/messaging/TracingChannelInterceptorTest.java[tags=message_span_customizer,indent=2]
----
[[sleuth-messaging-spring-cloud-function-integration]]
=== Spring Cloud Function and Spring Cloud Stream
This feature is available for all tracer implementations.
Spring Cloud Sleuth can instrument Spring Cloud Function. Since Spring Cloud Stream uses Spring Cloud Function
you will get the messaging instrumentation out of the box.
The way to achieve it is to provide a `Function` or `Consumer` or `Supplier` that takes in a `Message` as a parameter e.g. `Function<Message<String>, Message<Integer>>`.
If the type **is not** `Message` then instrumentation **will not** take place.
For a reactive `Consumer<Flux<Message<?>>>` remember to manually close the span and clear the context before you call `.subscribe()`. Example:
[source,java,indent=0]
----
@Bean
Consumer<Flux<Message<String>>> channel(Tracer tracer) {
// For the reactive consumer remember to call "subscribe()" at the end, otherwise
// you'll get the "Dispatcher has no subscribers" error
return i -> i
.doOnNext(s -> log.info("HELLO"))
// You must finish the span yourself and clear the tracing context like presented below.
// Otherwise you will be missing out the span that wraps the function execution.
.doOnNext(s -> {
tracer.currentSpan().end();
tracer.withSpan(null);
})
.subscribe();
}
}
----
You can disable Spring Cloud Stream integration by setting the value of `spring.sleuth.function.enabled` to `false`.
If you want to fully control the life cycle of spans within the reactive messaging context of Spring Cloud Stream
remember to disable the Spring Cloud Stream integration and leverage the `MessagingSleuthOperators` utility
class that allows you to manipulate the input and output messages in order to continue the tracing context and to execute custom code within the tracing context.
[source,java,indent=0]
-----
include::{project-root}/benchmarks/src/main/java/org/springframework/cloud/sleuth/benchmarks/app/stream/SleuthBenchmarkingStreamApplication.java[tags=simple_reactive,indent=0]
-----
[[sleuth-messaging-spring-rabbitmq-integration]]
=== Spring RabbitMq
This feature is available for Brave tracer implementation.
We instrument the `RabbitTemplate` so that tracing headers get injected into the message.
To block this feature, set `spring.sleuth.messaging.rabbit.enabled` to `false`.
[[sleuth-messaging-spring-kafka-integration]]
=== Spring Kafka
This feature is available for Brave tracer implementation.
We instrument the Spring Kafka's `ProducerFactory` and `ConsumerFactory`
so that tracing headers get injected into the created Spring Kafka's
`Producer` and `Consumer`.
To block this feature, set `spring.sleuth.messaging.kafka.enabled` to `false`.
[[sleuth-messaging-spring-kafka-streams-integration]]
=== Spring Kafka Streams
This feature is available for Brave tracer implementation.
We instrument the `KafkaStreams` `KafkaClientSupplier` so that tracing headers get injected into the `Producer` and `Consumer`s. A `KafkaStreamsTracing` bean allows for further instrumentation through additional `TransformerSupplier` and
`ProcessorSupplier` methods.
To block this feature, set `spring.sleuth.messaging.kafka.streams.enabled` to `false`.
[[sleuth-messaging-spring-jms-integration]]
=== Spring JMS
This feature is available for Brave tracer implementation.
We instrument the `JmsTemplate` so that tracing headers get injected into the message.
We also support `@JmsListener` annotated methods on the consumer side.
To block this feature, set `spring.sleuth.messaging.jms.enabled` to `false`.
IMPORTANT: We don't support baggage propagation for JMS
[[sleuth-openfeign-integration]]
== OpenFeign
This feature is available for all tracer implementations.
By default, Spring Cloud Sleuth provides integration with Feign through `TraceFeignClientAutoConfiguration`.
You can disable it entirely by setting `spring.sleuth.feign.enabled` to `false`.
If you do so, no Feign-related instrumentation take place.
Part of Feign instrumentation is done through a `FeignBeanPostProcessor`.
You can disable it by setting `spring.sleuth.feign.processor.enabled` to `false`.
If you set it to `false`, Spring Cloud Sleuth does not instrument any of your custom Feign components.
However, all the default instrumentation is still there.
[[sleuth-opentracing-integration]]
== OpenTracing
This feature is available for all tracer implementations.
Spring Cloud Sleuth is compatible with https://opentracing.io/[OpenTracing].
If you have OpenTracing on the classpath, we automatically register the OpenTracing `Tracer` bean.
If you wish to disable this, set `spring.sleuth.opentracing.enabled` to `false`
[[sleuth-quartz-integration]]
== Quartz
This feature is available for all tracer implementations.
We instrument quartz jobs by adding Job/Trigger listeners to the Quartz Scheduler.
To turn off this feature, set the `spring.sleuth.quartz.enabled` property to `false`.
[[sleuth-reactor-integration]]
== Reactor
This feature is available for all tracer implementations.
We have the following modes of instrumenting reactor based applications that can be set via `spring.sleuth.reactor.instrumentation-type` property:
* `DECORATE_QUEUES` - With the new Reactor https://github.com/reactor/reactor-core/pull/2566[queue wrapping mechanism] (Reactor 3.4.3) we're instrumenting the way threads are switched by Reactor. This should lead to feature parity with `ON_EACH` with low performance impact.
* `DECORATE_ON_EACH` - wraps every Reactor operator in a trace representation.
Passes the tracing context in most cases.
This mode might lead to drastic performance degradation.
* `DECORATE_ON_LAST` - wraps last Reactor operator in a trace representation.
Passes the tracing context in some cases thus accessing MDC context might not work.
This mode might lead to medium performance degradation.
* `MANUAL` - wraps every Reactor in the least invasive way without passing of tracing context.
It's up to the user to do it.
Current default is `ON_EACH` for backward compatibility reasons, however we encourage the users to migrate to the `MANUAL` instrumentation and profit from `WebFluxSleuthOperators` and `MessagingSleuthOperators`.
The performance improvement can be substantial.
Example:
[source,java,indent=0]
-----
include::{project-root}/benchmarks/src/main/java/org/springframework/cloud/sleuth/benchmarks/app/webflux/SleuthBenchmarkingSpringWebFluxApp.java[tags=simple_manual,indent=0]
-----
To disable Reactor support, set the `spring.sleuth.reactor.enabled` property to `false`.
[[sleuth-redis-integration]]
== Redis
This feature is available for all tracer implementations.
We're using the `Tracing` abstraction from Lettuce. If Brave is on the classpath we configure `Tracing` to be `BraveTracing`.
To disable Redis support, set the `spring.sleuth.redis.enabled` property to `false`.
[[sleuth-redis-legacy-integration]]
=== Redis With Legacy Brave Only Support
To use the Brave only supported feature you need to set the value of `spring.sleuth.redis.legacy.enabled` to `true`. This is the default mechanism available up till version 3.1.0 of Spring Cloud Sleuth.
We set `tracing` property to Lettuce `ClientResources` instance to enable Brave tracing built in Lettuce.
Spring Cloud Sleuth will provide a traced version of the `ClientResources` bean. If you have your own implementation of that bean, remember to customize the `ClientResources.Builder` with a stream of `ClientResourcesBuilderCustomizer`s like presented below:
[source,java,indent=0]
----
@Bean(destroyMethod = "shutdown")
DefaultClientResources myLettuceClientResources(ObjectProvider<ClientResourcesBuilderCustomizer> customizer) {
DefaultClientResources.Builder builder = DefaultClientResources.builder();
// setting up the builder manually
customizer.stream().forEach(c -> c.customize(builder));
return builder.build();
}
----
[[sleuth-runnablecallable-integration]]
== Runnable and Callable
This feature is available for all tracer implementations.
If you wrap your logic in `Runnable` or `Callable`, you can wrap those classes in their Sleuth representative, as shown in the following example for `Runnable`:
[source,java,indent=0]
----
include::{brave_path}/src/test/java/org/springframework/cloud/sleuth/brave/SpringCloudSleuthDocTests.java[tags=trace_runnable,indent=0]
----
The following example shows how to do so for `Callable`:
[source,java,indent=0]
----
include::{brave_path}/src/test/java/org/springframework/cloud/sleuth/brave/SpringCloudSleuthDocTests.java[tags=trace_callable,indent=0]
----
That way, you ensure that a new span is created and closed for each execution.
[[sleuth-rpc-integration]]
== RPC
This feature is available for Brave tracer implementation.
Sleuth automatically configures the `RpcTracing` bean which serves as a foundation for RPC instrumentation such as gRPC or Dubbo.
If a customization of client / server sampling of the RPC traces is required, just register a bean of type `brave.sampler.SamplerFunction<RpcRequest>` and name the bean `sleuthRpcClientSampler` for client sampler and
`sleuthRpcServerSampler` for server sampler.
For your convenience the `@RpcClientSampler` and `@RpcServerSampler`
annotations can be used to inject the proper beans or to reference the bean names via their static String `NAME` fields.
Ex.
Here's a sampler that traces 100 "GetUserToken" server requests per second.
This doesn't start new traces for requests to the health check service.
Other requests will use the global sampling configuration.
[source,java,indent=0]
----
@Configuration(proxyBeanMethods = false)
class Config {
include::{autoconfig_path}/src/test/java/org/springframework/cloud/sleuth/autoconfig/brave/instrument/rpc/BraveRpcAutoConfigurationIntegrationTests.java[tags=custom_rpc_server_sampler,indent=2]
}
----
For more, see https://github.com/openzipkin/brave/tree/master/instrumentation/rpc#sampling-policy
[[sleuth-rpc-dubbo-integration]]
=== Dubbo RPC support
Via the integration with Brave, Spring Cloud Sleuth supports https://dubbo.apache.org/[Dubbo].
It's enough to add the `brave-instrumentation-dubbo` dependency:
[source,xml,indent=0]
----
<dependency>
<groupId>io.zipkin.brave</groupId>
<artifactId>brave-instrumentation-dubbo</artifactId>
</dependency>
----
You need to also set a `dubbo.properties` file with the following contents:
```properties
dubbo.provider.filter=tracing
dubbo.consumer.filter=tracing
```
You can read more about Brave - Dubbo integration https://github.com/openzipkin/brave/tree/master/instrumentation/dubbo-rpc[here].
An example of Spring Cloud Sleuth and Dubbo can be found https://github.com/openzipkin/sleuth-webmvc-example/compare/add-dubbo-tracing[here].
[[sleuth-rpc-grpc-integration]]
=== gRPC
Spring Cloud Sleuth provides instrumentation for https://grpc.io/[gRPC] via the Brave tracer.
You can disable it entirely by setting `spring.sleuth.grpc.enabled` to `false`.
[[sleuth-rpc-grpc-variant1-integration]]
==== Variant 1
[[sleuth-rpc-grpc-variant1-dependencies-integration]]
===== Dependencies
IMPORTANT: The gRPC integration relies on two external libraries to instrument clients and servers and both of those libraries must be on the class path to enable the instrumentation.
Maven:
```
<dependency>
<groupId>io.github.lognet</groupId>
<artifactId>grpc-spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>io.zipkin.brave</groupId>
<artifactId>brave-instrumentation-grpc</artifactId>
</dependency>
```
Gradle:
```
compile("io.github.lognet:grpc-spring-boot-starter")
compile("io.zipkin.brave:brave-instrumentation-grpc")
```
[[sleuth-rpc-grpc-variant1-server-integration]]
===== Server Instrumentation
Spring Cloud Sleuth leverages grpc-spring-boot-starter to register Brave's gRPC server interceptor with all services annotated with `@GRpcService`.
[[sleuth-rpc-grpc-variant1-client-integration]]
===== Client Instrumentation
gRPC clients leverage a `ManagedChannelBuilder` to construct a `ManagedChannel` used to communicate to the gRPC server.
The native `ManagedChannelBuilder` provides static methods as entry points for construction of `ManagedChannel` instances, however, this mechanism is outside the influence of the Spring application context.
IMPORTANT: Spring Cloud Sleuth provides a `SpringAwareManagedChannelBuilder` that can be customized through the Spring application context and injected by gRPC clients.
*This builder must be used when creating `ManagedChannel` instances.*
Sleuth creates a `TracingManagedChannelBuilderCustomizer` which inject Brave's client interceptor into the `SpringAwareManagedChannelBuilder`.
[[sleuth-rpc-grpc-variant2-integration]]
==== Variant 2
https://github.com/yidongnan/grpc-spring-boot-starter[Grpc Spring Boot Starter] automatically detects the presence of Spring Cloud Sleuth and Brave's instrumentation for gRPC and registers the necessary client and/or server tooling.
[[sleuth-rxjava-integration]]
== RxJava
This feature is available for all tracer implementations.
We registering a custom https://github.com/ReactiveX/RxJava/wiki/Plugins#rxjavaschedulershook[`RxJavaSchedulersHook`] that wraps all `Action0` instances in their Sleuth representative, which is called `TraceAction`.
The hook either starts or continues a span, depending on whether tracing was already going on before the Action was scheduled.
To disable the custom `RxJavaSchedulersHook`, set the `spring.sleuth.rxjava.schedulers.hook.enabled` to `false`.
You can define a list of regular expressions for thread names for which you do not want spans to be created.
To do so, provide a comma-separated list of regular expressions in the `spring.sleuth.rxjava.schedulers.ignoredthreads` property.
IMPORTANT: The suggested approach to reactive programming and Sleuth is to use the Reactor support.
[[sleuth-circuitbreaker-integration]]
== Spring Cloud CircuitBreaker
This feature is available for all tracer implementations.
If you have Spring Cloud CircuitBreaker on the classpath, we will wrap the passed command `Supplier` and the fallback `Function` in its trace representations. We will also instrument the reactive implementation of the CircuitBreaker.
In order to disable this instrumentation set `spring.sleuth.circuitbreaker.enabled` to `false`.
[[sleuth-config-server-integration]]
== Spring Cloud Config Server
This feature is available for all tracer implementations.
If you have Spring Cloud Config Server running on the classpath, we will wrap the `EnvironmentRepository` in a span.
In order to disable this instrumentation set `spring.sleuth.config.server.enabled` to `false`.
[[sleuth-deployer-integration]]
== Spring Cloud Deployer
This feature is available for all tracer implementations.
If you have Spring Cloud Deployer running on the classpath, we wrap the `AppDeployer` in a trace representation. We are polling the application for its status at a default interval. You can change that default by setting the `spring.sleuth.deployer.status-poll-delay` property.
In order to disable this instrumentation set `spring.sleuth.deployer.enabled` to `false`.
[[sleuth-rsocket-integration]]
== Spring RSocket
This feature is available for all tracer implementations.
If you have Spring RSocket running on the classpath, we wrap the inbound and outbound communication to propagate the tracing context via the metadata.
In order to disable this instrumentation set `spring.sleuth.rsocket.enabled` to `false`.
[[sleuth-batch-integration]]
== Spring Batch
This feature is available for all tracer implementations.
If you have Spring Batch running on the classpath, we wrap the `StepBuilderFactory` and the `JobBuilderFactory` to propagate the tracing context.
In order to disable this instrumentation set `spring.sleuth.batch.enabled` to `false`.
[[sleuth-task-integration]]
== Spring Cloud Task
This feature is available for all tracer implementations.
If you have Spring Cloud Task running on the classpath, we're instrumenting `TaskExecutionListener` and `CommandLineRunner` and `ApplicationRunner`.
In order to disable this instrumentation set `spring.sleuth.task.enabled` to `false`.
[[sleuth-tx-integration]]
== Spring Tx
This feature is available for all tracer implementations.
If you have Spring Tx on the classpath we will instrument the `PlatformTransactionManager` and the `ReactiveTransactionManager` to create a span whenever a new transaction is created.
In order to disable this instrumentation set `spring.sleuth.tx.enabled` to `false`.
[[sleuth-security-integration]]
== Spring Security
This feature is available for all tracer implementations.
If you have Spring Security on the classpath, we create an implementation of `SecurityContextChangedListener` that annotates a current span with an event when context has changed.
In order to disable this instrumentation set `spring.sleuth.security.enabled` to `false`.
[[sleuth-r2dbc-integration]]
== R2DBC
This feature is available for all tracer implementations.
If you have R2DBC Proxy on the classpath we will instrument the `ConnectionFactory`so that it contains a custom `ProxyExecutionListener`.
In order to disable this instrumentation set `spring.sleuth.r2dbc.enabled` to `false`.
[[sleuth-vault-integration]]
== Spring Vault
This feature is available for all tracer implementations.
We're instrumenting the `RestTemplate` or `WebClient` instances used by Spring Vault to communicate with Vault.
In order to disable this instrumentation set `spring.sleuth.vault.enabled` to `false`.
[[sleuth-tomcat-integration]]
== Spring Tomcat
This feature is available for all tracer implementations.
We're adding an instrumented Tomcat's `Valve` that originates the span.
In order to disable this instrumentation set `spring.sleuth.web.tomcat.enabled` to `false`.
[[sleuth-cassandra-integration]]
== Spring Data Cassandra
This feature is available for all tracer implementations.
We're instrumenting Casandra's `CqlSession` and `ReactiveSession` interfaces and we're providing our own implementation of the `RequestTracker`.
In order to disable this instrumentation set `spring.sleuth.cassandra.enabled` to `false`.
[[sleuth-jdbc-integration]]
== Spring JDBC
This feature is available for all tracer implementations. It has been ported from the https://github.com/gavlyukovskiy/spring-boot-data-source-decorator/[spring-boot-datasource-decorator] project.
We're decorating `DataSource`s in a trace representation. We delegate actual proxying to either https://github.com/p6spy/p6spy[p6spy] or https://github.com/ttddyy/datasource-proxy[datasource-proxy]. In order to use this feature you need to have them on the classpath.
====
[source,xml,indent=0,subs="verbatim,attributes",role="primary"]
.P6Spy Maven
----
<dependency>
<groupId>p6spy</groupId>
<artifactId>p6spy</artifactId>
<version>${p6spy.version}</version>
<scope>runtime</scope>
</dependency>
----
[source,yml,indent=0,subs="verbatim,attributes",role="secondary"]
.P6Spy Gradle
----
runtimeOnly "p6spy:p6spy:${p6spyVersion}"
----
[source,xml,indent=0,subs="verbatim,attributes",role="secondary"]
.Datasource Proxy Maven
----
<dependency>
<groupId>net.ttddyy</groupId>
<artifactId>datasource-proxy</artifactId>
<version>${datasource-proxy.version}</version>
<scope>runtime</scope>
</dependency>
----
[source,groovy,indent=0,subs="verbatim,attributes",role="secondary"]
.Datasource Proxy Gradle
----
runtimeOnly "net.ttddyy:datasource-proxy:${datasourceProxyVersion}"
----
====
Please check the <<appendix.adoc#appendix,appendix>> page under `spring.sleuth.jdbc.p6spy` for all p6spy configuration options and `spring.sleuth.jdbc.datasource-proxy` for all datasource proxy configuration options.
For P6Spy by default logging parameter values will be disabled, set `spring.sleuth.jdbc.p6spy.tracing.include-parameter-values` to `true` to enable it.
You can configure P6Spy manually using one of available configuration methods. For more information please refer to the http://p6spy.readthedocs.io/en/latest/configandusage.html[P6Spy Configuration Guide].
For Datasource Proxy by default logging queries will be disabled, set `spring.sleuth.jdbc.datasource-proxy.slow-query.enable-logging` to `true` to enable logging slow queries
and set `spring.sleuth.jdbc.datasource-proxy.query.enable-logging` to `true` to enable logging all queries.
In order to disable this instrumentation set `spring.sleuth.jdbc.enabled` to `false`.
[[sleuth-mongodb-integration]]
== MongoDB
This feature is available for all tracer implementations.
We're adding command listeners that wrap all commands in a span.
If you want to have additional socket address related tags on the span set the `spring.sleuth.mongodb.socket-address-span-customizer.enabled` to `true`.
In order to disable this instrumentation set ``spring.sleuth.mongodb.enabled`` to `false`.
[[sleuth-session-integration]]
== Spring Session
This feature is available for all tracer implementations.
We're instrumenting the `Session` repositories that wraps all operations in a span.
In order to disable this instrumentation set `spring.sleuth.session.enabled` to `false`.
[[sleuth-kotlin-integration]]
== Kotlin Coroutines
This feature is available for all tracer implementations.
We're adding Kotlin Coroutines that allow you to retrieve the current span via the `Tracer` bean. You can either pass the bean to the Kotlin Coroutine context via `Tracer.asContextElement()` method execution or if you have Reactor Kotlin Coroutine integration on the classpath, we will retrieve it from Reactor's context. To retrieve the current span you can call the `currentSpan()` method within the Kotlin Coroutine.

View File

@@ -1,8 +0,0 @@
[[legal]]
= Legal
{project-version}
Copyright &#169; 2012-2021
Copies of this document may be made for your own use and for distribution to others, provided that you do not charge any fee for such copies and further provided that each copy contains this Copyright Notice, whether distributed in print or electronically.

View File

@@ -1,72 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<include resource="org/springframework/boot/logging/logback/defaults.xml"/>
<springProperty scope="context" name="springAppName" source="spring.application.name"/>
<!-- Example for logging into the build folder of your project -->
<property name="LOG_FILE" value="${BUILD_FOLDER:-build}/${springAppName}"/>
<!-- You can override this to have a custom pattern -->
<property name="CONSOLE_LOG_PATTERN"
value="%clr(%d{yyyy-MM-dd HH:mm:ss.SSS}){faint} %clr(${LOG_LEVEL_PATTERN:-%5p}) %clr(${PID:- }){magenta} %clr(---){faint} %clr([%15.15t]){faint} %clr(%-40.40logger{39}){cyan} %clr(:){faint} %m%n${LOG_EXCEPTION_CONVERSION_WORD:-%wEx}"/>
<!-- Appender to log to console -->
<appender name="console" class="ch.qos.logback.core.ConsoleAppender">
<filter class="ch.qos.logback.classic.filter.ThresholdFilter">
<!-- Minimum logging level to be presented in the console logs-->
<level>DEBUG</level>
</filter>
<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>
{
"timestamp": "@timestamp",
"severity": "%level",
"service": "${springAppName:-}",
"trace": "%X{traceId:-}",
"span": "%X{spanId:-}",
"pid": "${PID:-}",
"thread": "%thread",
"class": "%logger{40}",
"rest": "%message"
}
</pattern>
</pattern>
</providers>
</encoder>
</appender>
<root level="INFO">
<appender-ref ref="console"/>
<!-- uncomment this to have also JSON logs -->
<!--<appender-ref ref="logstash"/>-->
<!--<appender-ref ref="flatfile"/>-->
</root>
</configuration>

View File

@@ -1,506 +0,0 @@
[[features]]
[[project-features]]
= Spring Cloud Sleuth Features
include::_attributes.adoc[]
This section dives into the details of {project-full-name}.
Here you can learn about the key features that you may want to use and customize.
If you have not already done so, you might want to read the "<<getting-started.adoc#getting-started>>" and "<<using.adoc#using>>" sections, so that you have a good grounding in the basics.
[[features-context-propagation]]
== Context Propagation
Traces connect from service to service using header propagation.
The default format is https://github.com/openzipkin/b3-propagation[B3].
Similar to data formats, you can configure alternate header formats also, provided trace and span IDs are compatible with B3. Most notably, this means the trace ID and span IDs are lower-case hex, not UUIDs.
Besides trace identifiers, other properties (Baggage) can also be passed along with the request.
Remote Baggage must be predefined, but is flexible otherwise.
To use the provided defaults you can set the `spring.sleuth.propagation.type` property.
The value can be a list in which case you will propagate more tracing headers.
For Brave we support `AWS`, `B3`, `W3C` propagation types.
You can read more about how to provide custom context propagation in this "<<howto.adoc#how-to-change-context-propagation,how to section>>".
[[features-sampling]]
== Sampling
Spring Cloud Sleuth pushes the sampling decision down to the tracer implementation.
However, there are cases where you can change the sampling decision at runtime.
One of such cases is skip reporting of certain client spans.
To achieve that you can set the `spring.sleuth.web.client.skip-pattern` with the path patterns to be skipped.
Another option is to provide your own custom `org.springframework.cloud.sleuth.SamplerFunction<`org.springframework.cloud.sleuth.http.HttpRequest>` implementation and define when a given `HttpRequest` should not be sampled.
[[features-baggage]]
== Baggage
Distributed tracing works by propagating fields inside and across services that connect the trace together: traceId and spanId notably.
The context that holds these fields can optionally push other fields that need to be consistent regardless of many services are touched.
The simple name for these extra fields is "Baggage".
Sleuth allows you to define which baggage are permitted to exist in the trace context, including what header names are used.
The following example shows setting baggage values using Spring Cloud Sleuth's API:
[source,java,indent=0]
----
include::{common_tests_path}/src/main/java/org/springframework/cloud/sleuth/baggage/multiple/MultipleHopsIntegrationTests.java[tags=baggage,indent=0]
----
IMPORTANT: There is currently no limitation of the count or size of baggage items.
Keep in mind that too many can decrease system throughput or increase RPC latency.
In extreme cases, too much baggage can crash the application, due to exceeding transport-level message or header capacity.
You can use properties to define fields that have no special configuration such as name mapping:
* `spring.sleuth.baggage.remote-fields` is a list of header names to accept and propagate to remote services.
* `spring.sleuth.baggage.local-fields` is a list of names to propagate locally
No prefixing applies with these keys.
What you set is literally what is used.
A name set in either of these properties will result in a `Baggage` of the same name.
In order to automatically set the baggage values to Slf4j's MDC, you have to set the `spring.sleuth.baggage.correlation-fields` property with a list of allowed local or remote keys. E.g. `spring.sleuth.baggage.correlation-fields=country-code` will set the value of the `country-code` baggage into MDC.
Note that the extra field is propagated and added to MDC starting with the next downstream trace context.
To immediately add the extra field to MDC in the current trace context, configure the field to flush on update:
```
// configuration
@Bean
BaggageField countryCodeField() {
return BaggageField.create("country-code");
}
@Bean
ScopeDecorator mdcScopeDecorator() {
return MDCScopeDecorator.newBuilder()
.clear()
.add(SingleCorrelationField.newBuilder(countryCodeField())
.flushOnUpdate()
.build())
.build();
}
// service
@Autowired
BaggageField countryCodeField;
countryCodeField.updateValue("new-value");
```
IMPORTANT: Remember that adding entries to MDC can drastically decrease the performance of your application!
If you want to add the baggage entries as tags, to make it possible to search for spans via the baggage entries, you can set the value of
`spring.sleuth.baggage.tag-fields` with a list of allowed baggage keys.
To disable the feature you have to pass the `spring.sleuth.propagation.tag.enabled=false` property.
[[features-baggage-vs-tags]]
=== Baggage versus Tags
Like trace IDs, Baggage is attached to messages or requests, usually as headers.
Tags are key value pairs sent in a Span to Zipkin.
Baggage values are not added spans by default, which means you can't search based on Baggage unless you opt-in.
To make baggage also tags, use the property `spring.sleuth.baggage.tag-fields`
like so:
[source,yml]
----
include::{brave_path}/src/test/resources/application-baggage.yml[indent=0]
----
[[features-brave]]
== OpenZipkin Brave Tracer Integration
Spring Cloud Sleuth integrates with the OpenZipkin Brave tracer via the bridge that is available in the `spring-cloud-sleuth-brave` module.
In this section you can read about specific Brave integrations.
You can choose to use either Sleuth's API or the Brave API directly in your code (e.g. either Sleuth's `Tracer` or Brave's `Tracer`).
If you want to use this tracer implementation's API directly please read https://github.com/openzipkin/brave[their documentation to learn more about it].
[[features-brave-basics]]
=== Brave Basics
Here are the most core types you might use:
* `brave.SpanCustomizer` - to change the span currently in progress
* `brave.Tracer` - to get a start new spans ad-hoc
Here are the most relevant links from the OpenZipkin Brave project:
* https://github.com/openzipkin/brave/tree/master/brave[Brave's core library]
* https://github.com/openzipkin/brave/tree/master/brave#baggage[Baggage (propagated fields)]
* https://github.com/openzipkin/brave/tree/master/instrumentation/http[HTTP tracing]
[[features-brave-sampling]]
=== Brave Sampling
Sampling only applies to tracing backends, such as Zipkin.
Trace IDs appear in logs regardless of sample rate.
Sampling is a way to prevent overloading the system, by consistently tracing some, but not all requests.
The default rate of 10 traces per second is controlled by the `spring.sleuth.sampler.rate`
property and applies when we know Sleuth is used for reasons besides logging.
Use a rate above 100 traces per second with extreme caution as it can overload your tracing system.
The sampler can be set by Java Config also, as shown in the following example:
[source,java,indent=0]
----
include::{brave_path}/src/test/java/org/springframework/cloud/sleuth/brave/SpringCloudSleuthDocTests.java[tags=always_sampler,indent=0]
----
TIP: You can set the HTTP header `b3` to `1`, or, when doing messaging, you can set the `spanFlags` header to `1`.
Doing so forces the current request to be sampled regardless of configuration.
By default samplers will work with the refresh scope mechanism.
That means that you can change the sampling properties at runtime, refresh the application and the changes will be reflected.
However, sometimes the fact of creating a proxy around samplers and calling it from too early (from `@PostConstruct` annotated method) may lead to dead locks.
In such a case either create a sampler bean explicitly, or set the property `spring.sleuth.sampler.refresh.enabled` to `false` to disable the refresh scope support.
[[features-brave-baggage]]
=== Brave Baggage Java configuration
If you need to do anything more advanced than above, do not define properties and instead use a
`@Bean` config for the baggage fields you use.
* `BaggagePropagationCustomizer` sets up baggage fields
* Add a `SingleBaggageField` to control header names for a `Baggage`.
* `CorrelationScopeCustomizer` sets up MDC fields
* Add a `SingleCorrelationField` to change the MDC name of a `Baggage` or if updates flush.
[[features-brave-customizations]]
=== Brave Customizations
The `brave.Tracer` object is fully managed by sleuth, so you rarely need to affect it.
That said, Sleuth supports a number of `Customizer` types, that allow you to configure anything not already done by Sleuth with auto-configuration or properties.
If you define one of the following as a `Bean`, Sleuth will invoke it to customize behaviour:
* `RpcTracingCustomizer` - for RPC tagging and sampling policy
* `HttpTracingCustomizer` - for HTTP tagging and sampling policy
* `MessagingTracingCustomizer` - for messaging tagging and sampling policy
* `CurrentTraceContextCustomizer` - to integrate decorators such as correlation.
* `BaggagePropagationCustomizer` - for propagating baggage fields in process and over headers
* `CorrelationScopeDecoratorCustomizer` - for scope decorations such as MDC (logging) field correlation
[[features-brave-sampling-customizations]]
==== Brave Sampling Customizations
If client /server sampling is required, just register a bean of type
`brave.sampler.SamplerFunction<HttpRequest>` and name the bean
`sleuthHttpClientSampler` for client sampler and `sleuthHttpServerSampler`
for server sampler.
For your convenience the `@HttpClientSampler` and `@HttpServerSampler`
annotations can be used to inject the proper beans or to reference the bean names via their static String `NAME` fields.
Check out Brave's code to see an example of how to make a path-based sampler
https://github.com/openzipkin/brave/tree/master/instrumentation/http#sampling-policy
If you want to completely rewrite the `HttpTracing` bean you can use the `SkipPatternProvider`
interface to retrieve the URL `Pattern` for spans that should be not sampled.
Below you can see an example of usage of `SkipPatternProvider` inside a server side, `Sampler<HttpRequest>`.
[source,java,indent=0]
----
@Configuration(proxyBeanMethods = false)
class Config {
include::{tests_path}/brave/spring-cloud-sleuth-instrumentation-mvc-tests/src/test/java/org/springframework/cloud/sleuth/brave/instrument/web/TraceFilterWebIntegrationTests.java[tags=custom_server_sampler,indent=2]
}
----
[[features-brave-messaging]]
=== Brave Messaging
Sleuth automatically configures the `MessagingTracing` bean which serves as a foundation for Messaging instrumentation such as Kafka or JMS.
If a customization of producer / consumer sampling of messaging traces is required, just register a bean of type `brave.sampler.SamplerFunction<MessagingRequest>` and name the bean `sleuthProducerSampler` for producer sampler and `sleuthConsumerSampler`
for consumer sampler.
For your convenience the `@ProducerSampler` and `@ConsumerSampler`
annotations can be used to inject the proper beans or to reference the bean names via their static String `NAME` fields.
Ex.
Here's a sampler that traces 100 consumer requests per second, except for the "alerts" channel.
Other requests will use a global rate provided by the
`Tracing` component.
[source,java,indent=0]
----
@Configuration(proxyBeanMethods = false)
class Config {
include::{autoconfig_path}/src/test/java/org/springframework/cloud/sleuth/autoconfig/brave/instrument/messaging/BraveMessagingAutoConfigurationIntegrationTests.java[tags=custom_messaging_consumer_sampler,indent=2]
}
----
For more, see https://github.com/openzipkin/brave/tree/master/instrumentation/messaging#sampling-policy
[[features-brave-opentracing]]
=== Brave Opentracing
You can integrate with Brave and https://opentracing.io/[OpenTracing] via the
`io.opentracing.brave:brave-opentracing` bridge.
Just add it to the classpath and the OpenTracing `Tracer` will be set up automatically.
[[features-zipkin]]
== Sending Spans to Zipkin
Spring Cloud Sleuth provides various integrations with the https://zipkin.io[OpenZipkin] distributed tracing system.
Regardless of the chosen tracer implementation it's enough to add `spring-cloud-sleuth-zipkin` to the classpath to start sending spans to Zipkin.
You can choose whether to do that via HTTP or messaging.
You can read more about how to do that in "<<howto.adoc#how-to-set-up-sleuth-with-brave-zipkin-messaging,how to section>>".
When the span is closed, it is sent to Zipkin over HTTP. The communication is asynchronous.
You can configure the URL by setting the `spring.zipkin.baseUrl` property, as follows:
[source,yaml]
----
spring.zipkin.baseUrl: https://192.168.99.100:9411/
----
If you want to find Zipkin through service discovery, you can pass the Zipkin's service ID inside the URL, as shown in the following example for `zipkinserver` service ID:
[source,yaml]
----
spring.zipkin.baseUrl: https://zipkinserver/
----
To disable this feature just set `spring.zipkin.discovery-client-enabled` to `false`.
When the Discovery Client feature is enabled, Sleuth uses
`LoadBalancerClient` to find the URL of the Zipkin Server.
It means that you can set up the load balancing configuration.
If you have `web`, `rabbit`, `activemq` or `kafka` together on the classpath, you might need to pick the means by which you would like to send spans to zipkin.
To do so, set `web`, `rabbit`, `activemq` or `kafka` to the `spring.zipkin.sender.type` property.
The following example shows setting the sender type for `web`:
[source,yaml]
----
spring.zipkin.sender.type: web
----
To customize the `RestTemplate` that sends spans to Zipkin via HTTP, you can register the `ZipkinRestTemplateCustomizer` bean.
[source,java,indent=0]
----
@Configuration(proxyBeanMethods = false)
class MyConfig {
@Bean ZipkinRestTemplateCustomizer myCustomizer() {
return new ZipkinRestTemplateCustomizer() {
@Override
void customize(RestTemplate restTemplate) {
// customize the RestTemplate
}
};
}
}
----
If, however, you would like to control the full process of creating the `RestTemplate`
object, you will have to create a bean of `ZipkinRestTemplateProvider` type.
[source,java,indent=0]
----
@Bean
ZipkinRestTemplateProvider myZipkinRestTemplateProvider() {
return MyRestTemplate::new;
}
----
By default, api path will be set to `api/v2/spans` or `api/v1/spans` depending on the encoder version. If you want to use a custom api path, you can configure it using the following property (empty case, set ""):
[source,yaml]
----
spring.zipkin.api-path: v2/path2
----
[[features-zipkin-custom-service-name]]
=== Custom service name
By default, Sleuth assumes that, when you send a span to Zipkin, you want the span's service name to be equal to the value of the `spring.application.name` property.
That is not always the case, though.
There are situations in which you want to explicitly provide a different service name for all spans coming from your application.
To achieve that, you can pass the following property to your application to override that value (the example is for a service named `myService`):
[source,yaml]
----
spring.zipkin.service.name: myService
----
[[features-zipkin-host-locator]]
=== Host Locator
IMPORTANT: This section is about defining *host* from service discovery.
It is *NOT* about finding Zipkin through service discovery.
To define the host that corresponds to a particular span, we need to resolve the host name and port.
The default approach is to take these values from server properties.
If those are not set, we try to retrieve the host name from the network interfaces.
If you have the discovery client enabled and prefer to retrieve the host address from the registered instance in a service registry, you have to set the `spring.zipkin.locator.discovery.enabled` property (it is applicable for both HTTP-based and Stream-based span reporting), as follows:
[source,yaml]
----
spring.zipkin.locator.discovery.enabled: true
----
[[features-zipkin-custom-reported-spans]]
=== Customization of Reported Spans
In Sleuth, we generate spans with a fixed name.
Some users want to modify the name depending on values of tags.
Sleuth registers a `SpanFilter` bean that can automatically skip reporting spans of given name patterns.
The property `spring.sleuth.span-filter.span-name-patterns-to-skip` contains the default skip patterns for span names.
The property `spring.sleuth.span-filter.additional-span-name-patterns-to-skip` will append the provided span name patterns to the existing ones.
In order to disable this functionality just set `spring.sleuth.span-filter.enabled` to `false`.
[[features-zipkin-custom-reported-spans-brave]]
==== Brave Customization of Reported Spans
IMPORTANT: This section is applicable for Brave tracer only.
Before reporting spans (for example, to Zipkin) you may want to modify that span in some way.
You can do so by implementing a `SpanHandler`.
The following example shows how to register two beans that implement `SpanHandler`:
[source,java,indent=0]
----
include::{autoconfig_path}/src/test/java/org/springframework/cloud/sleuth/autoconfig/brave/SpanHandlerTests.java[tags=spanHandler,indent=0]
----
The preceding example results in changing the name of the reported span to `foo bar`, just before it gets reported (for example, to Zipkin).
=== Overriding the auto-configuration of Zipkin
Spring Cloud Sleuth supports sending traces to multiple tracing systems as of version 2.1.0. In order to get this to work, every tracing system needs to have a `Reporter<Span>` and `Sender`.
If you want to override the provided beans you need to give them a specific name.
To do this you can use respectively `ZipkinAutoConfiguration.REPORTER_BEAN_NAME` and `ZipkinAutoConfiguration.SENDER_BEAN_NAME`.
[source,java,indent=0]
----
include::{common_tests_path}/src/main/java/org/springframework/cloud/sleuth/autoconfig/zipkin2/ZipkinAutoConfigurationTests.java[tags=override_default_beans,indent=0]
----
[[features-log-integration]]
== Log integration
Sleuth configures the logging context with variables including the service name (`%{spring.zipkin.service.name}` or `%{spring.application.name}` if the previous one was not set), span ID (`%{spanId}`) and the trace ID (`%{traceId}`).
These help you connect logs with distributed traces and allow you choice in what tools you use to troubleshoot your services.
Once you find any log with an error, you can look for the trace ID in the message.
Paste that into your distributed tracing system to visualize the entire trace, regardless of how many services the first request ended up hitting.
[source]
----
backend.log: 2020-04-09 17:45:40.516 ERROR [backend,5e8eeec48b08e26882aba313eb08f0a4,dcc1df555b5777b3] 97203 --- [nio-9000-exec-1] o.s.c.s.i.web.ExceptionLoggingFilter : Uncaught exception thrown
frontend.log:2020-04-09 17:45:40.574 ERROR [frontend,5e8eeec48b08e26882aba313eb08f0a4,82aba313eb08f0a4] 97192 --- [nio-8081-exec-2] o.s.c.s.i.web.ExceptionLoggingFilter : Uncaught exception thrown
----
Above, you'll notice the trace ID is `5e8eeec48b08e26882aba313eb08f0a4`, for example.
This log configuration was automatically setup by Sleuth.
You can disable it by disabling Sleuth via `spring.sleuth.enabled=false` property or putting your own `logging.pattern.level` property.
If you use a log aggregating tool (such as https://www.elastic.co/products/kibana[Kibana], https://www.splunk.com/[Splunk], and others), you can order the events that took place.
An example from Kibana would resemble the following image:
image::{github-raw}/docs/src/main/asciidoc/images/kibana.png[Log correlation with Kibana]
If you want to use https://www.elastic.co/guide/en/logstash/current/index.html[Logstash], the following listing shows the Grok pattern for Logstash:
[source]
----
filter {
# pattern matching logback pattern
grok {
match => { "message" => "%{TIMESTAMP_ISO8601:timestamp}\s+%{LOGLEVEL:severity}\s+\[%{DATA:service},%{DATA:trace},%{DATA:span}\]\s+%{DATA:pid}\s+---\s+\[%{DATA:thread}\]\s+%{DATA:class}\s+:\s+%{GREEDYDATA:rest}" }
}
date {
match => ["timestamp", "ISO8601"]
}
mutate {
remove_field => ["timestamp"]
}
}
----
NOTE: If you want to use Grok together with the logs from Cloud Foundry, you have to use the following pattern:
[source]
----
filter {
# pattern matching logback pattern
grok {
match => { "message" => "(?m)OUT\s+%{TIMESTAMP_ISO8601:timestamp}\s+%{LOGLEVEL:severity}\s+\[%{DATA:service},%{DATA:trace},%{DATA:span}\]\s+%{DATA:pid}\s+---\s+\[%{DATA:thread}\]\s+%{DATA:class}\s+:\s+%{GREEDYDATA:rest}" }
}
date {
match => ["timestamp", "ISO8601"]
}
mutate {
remove_field => ["timestamp"]
}
}
----
[[features-log-integration-json-logback]]
=== JSON Logback with Logstash
Often, you do not want to store your logs in a text file but in a JSON file that Logstash can immediately pick.
To do so, you have to do the following (for readability, we pass the dependencies in the `groupId:artifactId:version` notation).
*Dependencies Setup*
. Ensure that Logback is on the classpath (`ch.qos.logback:logback-core`).
. Add Logstash Logback encode.
For example, to use version `4.6`, add `net.logstash.logback:logstash-logback-encoder:4.6`.
*Logback Setup*
Consider the following example of a Logback configuration file (logback-spring.xml).
[source,xml]
-----
include::{project-root}/docs/src/main/asciidoc/logback-spring.xml[]
-----
That Logback configuration file:
* Logs information from the application in a JSON format to a `build/${spring.application.name}.json` file.
* Has commented out two additional appenders: console and standard log file.
* Has the same logging pattern as the one presented in the previous section.
NOTE: If you use a custom `logback-spring.xml`, you must pass the `spring.application.name` in the `bootstrap` rather than the `application` property file.
Otherwise, your custom logback file does not properly read the property.
[[features-self-documenting-spans]]
== Self Documenting Spans
A declarative format of representing span configuration was introduced via the `DocumentedSpan` abstraction. By analyzing Sleuth's source code an appendix with all span characteristics is created (including allowed tag keys and event names). You can check the <<appendix.adoc#sleuth-spans, Sleuth Spans appendix>> for more information.
[[features-traces-actuator]]
== Traces Actuator Endpoint
Spring Cloud Sleuth comes with a `traces` Actuator endpoint that can store finished spans. The endpoint can be queried either via an HTTP Get method to simply retrieve the list of stored spans or via HTTP Post method to retrieve the list and clear it.
The size of the queue where the spans are stored can be configured via the `management.endpoint.traces.queue-size` property.
Please read the https://docs.spring.io/spring-boot/docs/current/reference/htmlsingle/#actuator[Spring Boot Actuator: Production-ready Features] section of the documentation to read more about the Actuator endpoints configuration options.
[[features-whats-next]]
== What to Read Next
If you want to learn more about any of the classes discussed in this section, you can browse the
{github-code}[source code directly].
If you have specific questions, see the
<<howto.adoc#howto, how-to>> section.
If you are comfortable with {project-full-name}'s core features, you can continue on and read about
<<integrations.adoc, {project-full-name}'s integrations>>.

View File

@@ -1,75 +0,0 @@
Add Sleuth to your classpath:
Maven
```xml
<dependencyManagement>
<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>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-sleuth</artifactId>
</dependency>
</dependencies>
```
Gradle
```groovy
buildscript {
dependencies {
classpath "io.spring.gradle:dependency-management-plugin:0.5.2.RELEASE"
}
}
apply plugin: "io.spring.dependency-management"
dependencyManagement {
imports {
mavenBom "org.springframework.cloud:spring-cloud-dependencies:${releaseTrainVersion}"
}
}
dependencies {
compile 'org.springframework.cloud:spring-cloud-starter-sleuth'
}
```
As long as Spring Cloud Sleuth is on the classpath any Spring Boot application will generate trace data:
```java
@SpringBootApplication
@RestController
public class Application {
private static Logger log = LoggerFactory.getLogger(DemoController.class);
@RequestMapping("/")
public String home() {
log.info("Handling home");
return "Hello World";
}
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
```
Run this app and then hit the home page.
You will see traceId and spanId populated in the logs.
If this app calls out to another one (e.g. with `RestTemplate`) it will send the trace data in headers and if the receiver is another Sleuth app you will see the trace continue there.
* Instead of logging the request in the handler explicitly, you could set `logging.level.org.springframework.web.servlet.DispatcherServlet=DEBUG`
* Sleuth defaults to a rate limited sampler.
That means that it will sample up to 1000 transactions per second.
* Set `spring.application.name=bar` (for instance) to see the service name as well as the trace and span ids.

View File

@@ -1,13 +0,0 @@
Spring Cloud Sleuth provides Spring Boot auto-configuration for distributed tracing.
## Features
Sleuth configures everything you need to get started.
This includes where trace data (spans) are reported to, how many traces to keep (sampling), if remote fields (baggage) are sent, and which libraries are traced.
Specifically, Spring Cloud Sleuth...
* Adds trace and span ids to the Slf4J MDC, so you can extract all the logs from a given trace or span in a log aggregator.
* Instruments common ingress and egress points from Spring applications (servlet filter, rest template, scheduled actions, message channels, feign client).
* If `spring-cloud-sleuth-zipkin` is available then the app will generate and report https://zipkin.io[Zipkin]-compatible traces via HTTP. By default it sends them to a Zipkin collector service on localhost (port 9411).
Configure the location of the service using `spring.zipkin.baseUrl`.

View File

@@ -1,18 +0,0 @@
[[spring-cloud-sleuth-reference-documentation]]
= Spring Cloud Sleuth Reference Documentation
Adrian Cole, Spencer Gibb, Marcin Grzejszczak, Dave Syer, Jay Bryant
:docinfo: shared
include::_attributes.adoc[]
The reference documentation consists of the following sections:
[horizontal]
<<legal.adoc#legal,Legal>> :: Legal information.
<<documentation-overview.adoc#sleuth-documentation-about,Documentation Overview>> :: About the Documentation, Getting Help, First Steps, and more.
<<getting-started.adoc#getting-started,Getting Started>> :: Introducing {project-full-name}, Developing Your First {project-full-name}-based Application
<<using.adoc#using,Using {project-full-name}>> :: {project-full-name} usage examples and workflows.
<<project-features.adoc#features,{project-full-name} Features>> :: Span creation, context propagation, and more.
<<howto.adoc#howto,"`How-to`" Guides>> :: Add sampling, propagate remote tags, and more.
<<integrations.adoc#sleuth-integration,{project-full-name} Integrations>> :: Instrumentation configuration, context propagation, and more.
<<appendix.adoc#appendix,Appendices>> :: Span definitions and configuration properties.

View File

@@ -1,14 +0,0 @@
[[spring-cloud-sleuth-reference-documentation]]
= Spring Cloud Sleuth Reference Documentation
Adrian Cole, Spencer Gibb, Marcin Grzejszczak, Dave Syer, Jay Bryant
:docinfo: shared
include::_attributes.adoc[]
include::legal.adoc[leveloffset=+1]
include::getting-started.adoc[leveloffset=+1]
include::using.adoc[leveloffset=+1]
include::project-features.adoc[leveloffset=+1]
include::howto.adoc[leveloffset=+1]
include::integrations.adoc[leveloffset=+1]
include::appendix.adoc[leveloffset=+1]

View File

@@ -1,13 +0,0 @@
[[spring-cloud-sleuth-reference-documentation]]
= Spring Cloud Sleuth Reference Documentation
Adrian Cole, Spencer Gibb, Marcin Grzejszczak, Dave Syer, Jay Bryant
include::_attributes.adoc[]
include::legal.adoc[leveloffset=+1]
include::getting-started.adoc[leveloffset=+1]
include::using.adoc[leveloffset=+1]
include::project-features.adoc[leveloffset=+1]
include::howto.adoc[leveloffset=+1]
include::integrations.adoc[leveloffset=+1]
include::appendix.adoc[leveloffset=+1]

View File

@@ -1,286 +0,0 @@
[[using]]
= Using Spring Cloud Sleuth
include::_attributes.adoc[]
This section goes into more detail about how you should use {project-full-name}.
It covers topics such as controlling the span lifecycle with {project-full-name} API or via annotations.
We also cover some {project-full-name} best practices.
If you are starting out with {project-full-name}, you should probably read the
<<getting-started.adoc#getting-started, Getting Started>> guide before diving into this section.
[[using-span-lifecycle]]
== Span Lifecycle with Spring Cloud Sleuth's API
Spring Cloud Sleuth Core in its `api` module contains all necessary interfaces to be implemented by a tracer.
The project comes with OpenZipkin Brave implementation.
You can check how the tracers are bridged to the Sleuth's API by looking at the `org.springframework.cloud.sleuth.brave.bridge`.
The most commonly used interfaces are:
* `org.springframework.cloud.sleuth.Tracer` - Using a tracer, you can create a root span capturing the critical path of a request.
* `org.springframework.cloud.sleuth.Span` - Span is a single unit of work that needs to be started and stopped.
Contains timing information and events and tags.
You can also use your tracer implementation's API directly.
Let's look at the following Span lifecycle actions.
* <<using-creating-and-ending-spans, start>>: When you start a span, its name is assigned and the start timestamp is recorded.
* <<using-creating-and-ending-spans, end>>: The span gets finished (the end time of the span is recorded) and, if the span is sampled, it is eligible for collection (e.g. to Zipkin).
* <<using-continuing-spans, continue>>: The span gets continued e.g. in another thread.
* <<using-creating-spans-with-explicit-parent, create with explicit parent>>: You can create a new span and set an explicit parent for it.
TIP: Spring Cloud Sleuth creates an instance of `Tracer` for you.
In order to use it, you can autowire it.
[[using-creating-and-ending-spans]]
=== Creating and Ending Spans
You can manually create spans by using the `Tracer`, as shown in the following example:
[source,java,indent=0]
----
include::{brave_path}/src/test/java/org/springframework/cloud/sleuth/brave/SpringCloudSleuthDocTests.java[tags=manual_span_creation,indent=0]
----
In the preceding example, we could see how to create a new instance of the span.
If there is already a span in this thread, it becomes the parent of the new span.
IMPORTANT: Always clean after you create a span.
IMPORTANT: If your span contains a name greater than 50 chars, that name is truncated to 50 chars.
Your names have to be explicit and concrete.
Big names lead to latency issues and sometimes even exceptions.
[[using-continuing-spans]]
=== Continuing Spans
Sometimes, you do not want to create a new span but you want to continue one.
An example of such a situation might be as follows:
* *AOP*: If there was already a span created before an aspect was reached, you might not want to create a new span.
To continue a span, you can store the span in one thread and pass it on to another one as shown in the example below.
[source,java,indent=0]
----
include::{brave_path}/src/test/java/org/springframework/cloud/sleuth/brave/SpringCloudSleuthDocTests.java[tags=manual_span_continuation,indent=0]
----
[[using-creating-spans-with-explicit-parent]]
=== Creating a Span with an explicit Parent
You might want to start a new span and provide an explicit parent of that span.
Assume that the parent of a span is in one thread and you want to start a new span in another thread.
Whenever you call `Tracer.nextSpan()`, it creates a span in reference to the span that is currently in scope.
You can put the span in scope and then call `Tracer.nextSpan()`, as shown in the following example:
[source,java,indent=0]
----
include::{brave_path}/src/test/java/org/springframework/cloud/sleuth/brave/SpringCloudSleuthDocTests.java[tags=manual_span_joining,indent=0]
----
IMPORTANT: After creating such a span, you must finish it.
Otherwise it is not reported (e.g. to Zipkin).
You can also use the `Tracer.nextSpan(Span parentSpan)` version to provide the parent span explicitly.
[[using-naming-spans]]
== Naming Spans
Picking a span name is not a trivial task.
A span name should depict an operation name.
The name should be low cardinality, so it should not include identifiers.
Since there is a lot of instrumentation going on, some span names are artificial:
* `controller-method-name` when received by a Controller with a method name of `controllerMethodName`
* `async` for asynchronous operations done with wrapped `Callable` and `Runnable` interfaces.
* Methods annotated with `@Scheduled` return the simple name of the class.
Fortunately, for asynchronous processing, you can provide explicit naming.
[[using-naming-spans-annotation]]
=== `@SpanName` Annotation
You can name the span explicitly by using the `@SpanName` annotation, as shown in the following example:
[source,java,indent=0]
----
include::{brave_path}/src/test/java/org/springframework/cloud/sleuth/brave/SpringCloudSleuthDocTests.java[tags=span_name_annotation,indent=0]
----
In this case, when processed in the following manner, the span is named `calculateTax`:
[source,java,indent=0]
----
include::{brave_path}/src/test/java/org/springframework/cloud/sleuth/brave/SpringCloudSleuthDocTests.java[tags=span_name_annotated_runnable_execution,indent=0]
----
[[using-naming-spans-to-string]]
=== `toString()` Method
It is pretty rare to create separate classes for `Runnable` or `Callable`.
Typically, one creates an anonymous instance of those classes.
You cannot annotate such classes.
To overcome that limitation, if there is no `@SpanName` annotation present, we check whether the class has a custom implementation of the `toString()` method.
Running such code leads to creating a span named `calculateTax`, as shown in the following example:
[source,java,indent=0]
----
include::{brave_path}/src/test/java/org/springframework/cloud/sleuth/brave/SpringCloudSleuthDocTests.java[tags=span_name_to_string_runnable_execution,indent=0]
----
[[using-annotations]]
== Managing Spans with Annotations
There are a number of good reasons to manage spans with annotations, including:
* API-agnostic means to collaborate with a span.
Use of annotations lets users add to a span with no library dependency on a span api.
Doing so lets Sleuth change its core API to create less impact to user code.
* Reduced surface area for basic span operations.
Without this feature, you must use the span api, which has lifecycle commands that could be used incorrectly.
By only exposing scope, tag, and log functionality, you can collaborate without accidentally breaking span lifecycle.
* Collaboration with runtime generated code.
With libraries such as Spring Data and Feign, the implementations of interfaces are generated at runtime.
Consequently, span wrapping of objects was tedious.
Now you can provide annotations over interfaces and the arguments of those interfaces.
[[using-annotations-new-spans]]
=== Creating New Spans
If you do not want to create local spans manually, you can use the `@NewSpan` annotation.
Also, we provide the `@SpanTag` annotation to add tags in an automated fashion.
Now we can consider some examples of usage.
[source,java,indent=0]
----
include::{common_tests_path}/src/main/java/org/springframework/cloud/sleuth/instrument/annotation/SleuthSpanCreatorAspectTests.java[tags=annotated_method,indent=0]
----
Annotating the method without any parameter leads to creating a new span whose name equals the annotated method name.
[source,java,indent=0]
----
include::{common_tests_path}/src/main/java/org/springframework/cloud/sleuth/instrument/annotation/SleuthSpanCreatorAspectTests.java[tags=custom_name_on_annotated_method,indent=0]
----
If you provide the value in the annotation (either directly or by setting the `name` parameter), the created span has the provided value as the name.
[source,java,indent=0]
----
// method declaration
include::{common_tests_path}/src/main/java/org/springframework/cloud/sleuth/instrument/annotation/SleuthSpanCreatorAspectTests.java[tags=custom_name_and_tag_on_annotated_method,indent=0]
// and method execution
include::{common_tests_path}/src/main/java/org/springframework/cloud/sleuth/instrument/annotation/SleuthSpanCreatorAspectTests.java[tags=execution,indent=0]
----
You can combine both the name and a tag.
Let's focus on the latter.
In this case, the value of the annotated method's parameter runtime value becomes the value of the tag.
In our sample, the tag key is `testTag`, and the tag value is `test`.
[source,java,indent=0]
----
include::{common_tests_path}/src/main/java/org/springframework/cloud/sleuth/instrument/annotation/SleuthSpanCreatorAspectTests.java[tags=name_on_implementation,indent=0]
----
You can place the `@NewSpan` annotation on both the class and an interface.
If you override the interface's method and provide a different value for the `@NewSpan` annotation, the most concrete one wins (in this case `customNameOnTestMethod3` is set).
[[using-annotations-continuing-spans]]
=== Continuing Spans
If you want to add tags and annotations to an existing span, you can use the `@ContinueSpan` annotation, as shown in the following example:
[source,java,indent=0]
----
// method declaration
include::{common_tests_path}/src/main/java/org/springframework/cloud/sleuth/instrument/annotation/SleuthSpanCreatorAspectTests.java[tags=continue_span,indent=0]
// method execution
include::{common_tests_path}/src/main/java/org/springframework/cloud/sleuth/instrument/annotation/SleuthSpanCreatorAspectTests.java[tags=continue_span_execution,indent=0]
----
(Note that, in contrast with the `@NewSpan` annotation ,you can also add logs with the `log` parameter.)
That way, the span gets continued and:
* Log entries named `testMethod11.before` and `testMethod11.after` are created.
* If an exception is thrown, a log entry named `testMethod11.afterFailure` is also created.
* A tag with a key of `testTag11` and a value of `test` is created.
[[using-annotations-advanced-tag-setting]]
=== Advanced Tag Setting
There are 3 different ways to add tags to a span.
All of them are controlled by the `SpanTag` annotation.
The precedence is as follows:
. Try with a bean of `TagValueResolver` type and a provided name.
. If the bean name has not been provided, try to evaluate an expression.
We search for a `TagValueExpressionResolver` bean.
The default implementation uses SPEL expression resolution.
**IMPORTANT** You can only reference properties from the SPEL expression.
Method execution is not allowed due to security constraints.
. If we do not find any expression to evaluate, return the `toString()` value of the parameter.
[[using-annotations-custom-extractor]]
==== Custom Extractor
The value of the tag for the following method is computed by an implementation of `TagValueResolver` interface.
Its class name has to be passed as the value of the `resolver` attribute.
Consider the following annotated method:
[source,java,indent=0]
----
include::{common_tests_path}/src/main/java/org/springframework/cloud/sleuth/instrument/annotation/SpanTagAnnotationHandlerTests.java[tags=resolver_bean,indent=0]
----
Now further consider the following `TagValueResolver` bean implementation:
[source,java,indent=0]
----
include::{common_tests_path}/src/main/java/org/springframework/cloud/sleuth/instrument/annotation/SpanTagAnnotationHandlerTests.java[tags=custom_resolver,indent=0]
----
The two preceding examples lead to setting a tag value equal to `Value from myCustomTagValueResolver`.
[[using-annotations-resolving-expressions]]
==== Resolving Expressions for a Value
Consider the following annotated method:
[source,java,indent=0]
----
include::{common_tests_path}/src/main/java/org/springframework/cloud/sleuth/instrument/annotation/SpanTagAnnotationHandlerTests.java[tags=spel,indent=0]
----
No custom implementation of a `TagValueExpressionResolver` leads to evaluation of the SPEL expression, and a tag with a value of `hello characters` is set on the span.
If you want to use some other expression resolution mechanism, you can create your own implementation of the bean.
[[using-annotations-to-string]]
==== Using The `toString()` Method
Consider the following annotated method:
[source,java,indent=0]
----
include::{common_tests_path}/src/main/java/org/springframework/cloud/sleuth/instrument/annotation/SpanTagAnnotationHandlerTests.java[tags=toString,indent=0]
----
Running the preceding method with a value of `15` leads to setting a tag with a String value of `"15"`.
[[using-whats-next]]
== What to Read Next
You should now understand how you can use {project-full-name} and some best practices that you should follow.
You can now go on to learn about specific
<<project-features#project-features, {project-full-name} features>>, or you could skip ahead and read about the link:integrations[integrations available in {project-full-name}].

View File

@@ -1,74 +0,0 @@
/*
* Copyright 2013-2020 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
*
* https://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 org.springframework.cloud.sleuth.documentation;
import java.io.File;
import java.io.IOException;
import java.nio.file.FileVisitor;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.Collection;
import java.util.TreeSet;
import java.util.regex.Pattern;
public class DocsFromSources {
private final File projectRoot;
private final Pattern inclusionPattern;
private final File outputDir;
public DocsFromSources(File projectRoot, Pattern inclusionPattern, File outputDir) {
this.projectRoot = projectRoot;
this.inclusionPattern = inclusionPattern;
this.outputDir = outputDir;
}
public static void main(String... args) {
String projectRoot = args[0];
String inclusionPattern = args[1];
inclusionPattern = inclusionPattern.replace("/", File.separator);
String output = args[2];
new DocsFromSources(new File(projectRoot), Pattern.compile(inclusionPattern), new File(output)).generate();
}
public void generate() {
Path path = this.projectRoot.toPath();
System.out.println("Inclusion pattern is [" + this.inclusionPattern + "]");
Collection<SpanEntry> spanEntries = new TreeSet<>();
FileVisitor<Path> fv = new SpanSearchingFileVisitor(this.inclusionPattern, spanEntries);
try {
Files.walkFileTree(path, fv);
Path output = new File(this.outputDir, "_spans.adoc").toPath();
StringBuilder stringBuilder = new StringBuilder();
System.out.println("======================================");
System.out.println("Summary of sources analysis");
System.out.println("Found [" + spanEntries.size() + "] spans");
System.out.println(
"Found [" + spanEntries.stream().flatMap(e -> e.tagKeys.stream()).distinct().count() + "] tags");
System.out.println(
"Found [" + spanEntries.stream().flatMap(e -> e.events.stream()).distinct().count() + "] events");
spanEntries.forEach(spanEntry -> stringBuilder.append(spanEntry.toString()).append("\n\n"));
Files.write(output, stringBuilder.toString().getBytes());
}
catch (IOException e) {
throw new IllegalArgumentException(e);
}
}
}

View File

@@ -1,67 +0,0 @@
/*
* Copyright 2013-2020 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
*
* https://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 org.springframework.cloud.sleuth.documentation;
import java.util.Objects;
class KeyValueEntry implements Comparable<KeyValueEntry> {
final String name;
final String description;
KeyValueEntry(String name, String description) {
this.name = name;
this.description = description;
}
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
KeyValueEntry tag = (KeyValueEntry) o;
return Objects.equals(name, tag.name) && Objects.equals(description, tag.description);
}
@Override
public int hashCode() {
return Objects.hash(name, description);
}
@Override
public int compareTo(KeyValueEntry o) {
return name.compareTo(o.name);
}
@Override
public String toString() {
return "|" + name + "|" + description();
}
private String description() {
String suffix = "";
if (this.name.contains("%s")) {
suffix = " (since the name contains `%s` the final value will be resolved at runtime)";
}
return description + suffix;
}
}

View File

@@ -1,110 +0,0 @@
/*
* Copyright 2013-2020 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
*
* https://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 org.springframework.cloud.sleuth.documentation;
import java.util.Arrays;
import java.util.Collection;
import java.util.Locale;
import java.util.Objects;
import java.util.stream.Collectors;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;
class SpanEntry implements Comparable<SpanEntry> {
final String name;
final String enclosingClass;
final String enumName;
final String description;
final String prefix;
final Collection<KeyValueEntry> tagKeys;
final Collection<KeyValueEntry> events;
SpanEntry(String name, String enclosingClass, String enumName, String description, String prefix,
Collection<KeyValueEntry> tagKeys, Collection<KeyValueEntry> events) {
Assert.isTrue(StringUtils.hasText(name), "Span name must not be empty");
Assert.isTrue(StringUtils.hasText(description), "Span description must not be empty");
this.name = name;
this.enclosingClass = enclosingClass;
this.enumName = enumName;
this.description = description;
this.prefix = prefix;
this.tagKeys = tagKeys;
this.events = events;
}
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
SpanEntry spanEntry = (SpanEntry) o;
return Objects.equals(name, spanEntry.name) && Objects.equals(enclosingClass, spanEntry.enclosingClass)
&& Objects.equals(enumName, spanEntry.enumName) && Objects.equals(description, spanEntry.description)
&& Objects.equals(tagKeys, spanEntry.tagKeys) && Objects.equals(events, spanEntry.events);
}
@Override
public int hashCode() {
return Objects.hash(name, enclosingClass, enumName, description, tagKeys, events);
}
@Override
public int compareTo(SpanEntry o) {
return enumName.compareTo(o.enumName);
}
@Override
//@formatter:off
public String toString() {
StringBuilder text = new StringBuilder()
.append("=== ").append(Arrays.stream(enumName.replace("_", " ").split(" ")).map(s -> StringUtils.capitalize(s.toLowerCase(Locale.ROOT))).collect(Collectors.joining(" ")))
.append("\n\n> ").append(description).append("\n\n")
.append("**Span name** `").append(name).append("`");
if (name.contains("%s")) {
text.append(" - since it contains `%s`, the name is dynamic and will be resolved at runtime.");
}
else {
text.append(".");
}
text.append("\n\n").append("Fully qualified name of the enclosing class `").append(this.enclosingClass).append("`");
if (StringUtils.hasText(prefix)) {
text.append("\n\nIMPORTANT: All tags and events must be prefixed with `").append(this.prefix).append("` prefix!");
}
if (!tagKeys.isEmpty()) {
text.append("\n\n.Tag Keys\n|===\n|Name | Description\n").append(this.tagKeys.stream().map(KeyValueEntry::toString).collect(Collectors.joining("\n")))
.append("\n|===");
}
if (!events.isEmpty()) {
text.append("\n\n.Event Values\n|===\n|Name | Description\n").append(this.events.stream().map(KeyValueEntry::toString).collect(Collectors.joining("\n")))
.append("\n|===");
}
return text.toString();
}
//@formatter:on
}

View File

@@ -1,234 +0,0 @@
/*
* Copyright 2013-2020 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
*
* https://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 org.springframework.cloud.sleuth.documentation;
import java.io.IOException;
import java.io.InputStream;
import java.nio.file.FileVisitResult;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.SimpleFileVisitor;
import java.nio.file.attribute.BasicFileAttributes;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.TreeSet;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.jboss.forge.roaster.Roaster;
import org.jboss.forge.roaster._shade.org.eclipse.jdt.core.dom.Expression;
import org.jboss.forge.roaster._shade.org.eclipse.jdt.core.dom.MethodDeclaration;
import org.jboss.forge.roaster._shade.org.eclipse.jdt.core.dom.MethodInvocation;
import org.jboss.forge.roaster._shade.org.eclipse.jdt.core.dom.ReturnStatement;
import org.jboss.forge.roaster._shade.org.eclipse.jdt.core.dom.StringLiteral;
import org.jboss.forge.roaster.model.JavaType;
import org.jboss.forge.roaster.model.JavaUnit;
import org.jboss.forge.roaster.model.impl.JavaEnumImpl;
import org.jboss.forge.roaster.model.source.EnumConstantSource;
import org.jboss.forge.roaster.model.source.JavaSource;
import org.jboss.forge.roaster.model.source.MemberSource;
import org.springframework.cloud.sleuth.docs.DocumentedSpan;
import org.springframework.cloud.sleuth.docs.EventValue;
import org.springframework.cloud.sleuth.docs.TagKey;
class SpanSearchingFileVisitor extends SimpleFileVisitor<Path> {
private final Pattern pattern;
private final Collection<SpanEntry> spanEntries;
SpanSearchingFileVisitor(Pattern pattern, Collection<SpanEntry> spanEntries) {
this.pattern = pattern;
this.spanEntries = spanEntries;
}
@Override
public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
if (!pattern.matcher(file.toString()).matches()) {
return FileVisitResult.CONTINUE;
}
else if (!file.toString().endsWith(".java")) {
return FileVisitResult.CONTINUE;
}
try (InputStream stream = Files.newInputStream(file)) {
JavaUnit unit = Roaster.parseUnit(stream);
JavaType myClass = unit.getGoverningType();
if (!(myClass instanceof JavaEnumImpl)) {
return FileVisitResult.CONTINUE;
}
JavaEnumImpl myEnum = (JavaEnumImpl) myClass;
if (!myEnum.getInterfaces().contains(DocumentedSpan.class.getCanonicalName())) {
return FileVisitResult.CONTINUE;
}
System.out.println("Checking [" + myEnum.getName() + "]");
if (myEnum.getEnumConstants().size() == 0) {
return FileVisitResult.CONTINUE;
}
for (EnumConstantSource enumConstant : myEnum.getEnumConstants()) {
SpanEntry entry = parseSpan(enumConstant, myEnum);
if (entry != null) {
spanEntries.add(entry);
System.out.println(
"Found [" + entry.tagKeys.size() + "] tags and [" + entry.events.size() + "] events");
}
}
return FileVisitResult.CONTINUE;
}
}
private SpanEntry parseSpan(EnumConstantSource enumConstant, JavaEnumImpl myEnum) {
List<MemberSource<EnumConstantSource.Body, ?>> members = enumConstant.getBody().getMembers();
if (members.isEmpty()) {
return null;
}
String name = "";
String description = enumConstant.getJavaDoc().getText();
String prefix = "";
Collection<KeyValueEntry> tags = new TreeSet<>();
Collection<KeyValueEntry> events = new TreeSet<>();
for (MemberSource<EnumConstantSource.Body, ?> member : members) {
Object internal = member.getInternal();
if (!(internal instanceof MethodDeclaration)) {
return null;
}
MethodDeclaration methodDeclaration = (MethodDeclaration) internal;
String methodName = methodDeclaration.getName().getIdentifier();
if ("getName".equals(methodName)) {
name = readStringReturnValue(methodDeclaration);
}
else if ("getTagKeys".equals(methodName)) {
tags.addAll(keyValueEntries(myEnum, methodDeclaration, TagKey.class));
}
else if ("getEvents".equals(methodName)) {
events.addAll(keyValueEntries(myEnum, methodDeclaration, EventValue.class));
}
else if ("prefix".equals(methodName)) {
prefix = readStringReturnValue(methodDeclaration);
}
}
return new SpanEntry(name, myEnum.getCanonicalName(), enumConstant.getName(), description, prefix, tags,
events);
}
private Collection<KeyValueEntry> keyValueEntries(JavaEnumImpl myEnum, MethodDeclaration methodDeclaration,
Class requiredClass) {
Collection<String> enumNames = readClassValue(methodDeclaration);
Collection<KeyValueEntry> keyValues = new TreeSet<>();
enumNames.forEach(enumName -> {
List<JavaSource<?>> nestedTypes = myEnum.getNestedTypes();
JavaSource<?> nestedSource = nestedTypes.stream()
.filter(javaSource -> javaSource.getName().equals(enumName)).findFirst().orElseThrow(
() -> new IllegalStateException("There's no nested type with name [" + enumName + "]"));
updateKeyValuesFromEnum(myEnum, nestedSource, requiredClass, keyValues);
});
return keyValues;
}
private void updateKeyValuesFromEnum(JavaEnumImpl parentEnum, JavaSource<?> source, Class requiredClass,
Collection<KeyValueEntry> keyValues) {
if (!(source instanceof JavaEnumImpl)) {
return;
}
JavaEnumImpl myEnum = (JavaEnumImpl) source;
if (!myEnum.getInterfaces().contains(requiredClass.getCanonicalName())) {
return;
}
System.out.println("Checking [" + parentEnum.getName() + "." + myEnum.getName() + "]");
if (myEnum.getEnumConstants().size() == 0) {
return;
}
for (EnumConstantSource enumConstant : myEnum.getEnumConstants()) {
String keyValue = enumKeyValue(enumConstant);
keyValues.add(new KeyValueEntry(keyValue, enumConstant.getJavaDoc().getText()));
}
}
private String enumKeyValue(EnumConstantSource enumConstant) {
List<MemberSource<EnumConstantSource.Body, ?>> members = enumConstant.getBody().getMembers();
if (members.isEmpty()) {
System.err.println("No method declarations in the enum.");
return "";
}
Object internal = members.get(0).getInternal();
if (!(internal instanceof MethodDeclaration)) {
System.err.println("Can't read the member [" + internal.getClass() + "] as a method declaration.");
return "";
}
MethodDeclaration methodDeclaration = (MethodDeclaration) internal;
if (methodDeclaration.getBody().statements().isEmpty()) {
System.err.println("Body was empty. Continuing...");
return "";
}
return stringFromReturnMethodDeclaration(methodDeclaration);
}
private String stringFromReturnMethodDeclaration(MethodDeclaration methodDeclaration) {
Object statement = methodDeclaration.getBody().statements().get(0);
if (!(statement instanceof ReturnStatement)) {
System.err.println("Statement [" + statement.getClass() + "] is not a return statement.");
return "";
}
ReturnStatement returnStatement = (ReturnStatement) statement;
Expression expression = returnStatement.getExpression();
if (!(expression instanceof StringLiteral)) {
System.err.println("Statement [" + statement.getClass() + "] is not a string literal statement.");
return "";
}
return ((StringLiteral) expression).getLiteralValue();
}
private String readStringReturnValue(MethodDeclaration methodDeclaration) {
return stringFromReturnMethodDeclaration(methodDeclaration);
}
private Collection<String> readClassValue(MethodDeclaration methodDeclaration) {
Object statement = methodDeclaration.getBody().statements().get(0);
if (!(statement instanceof ReturnStatement)) {
System.err.println("Statement [" + statement.getClass() + "] is not a return statement.");
return Collections.emptyList();
}
ReturnStatement returnStatement = (ReturnStatement) statement;
Expression expression = returnStatement.getExpression();
if (!(expression instanceof MethodInvocation)) {
System.err.println("Statement [" + statement.getClass() + "] is not a method invocation.");
return Collections.emptyList();
}
MethodInvocation methodInvocation = (MethodInvocation) expression;
if ("merge".equals(methodInvocation.getName().getIdentifier())) {
// TODO: There must be a better way to do this...
// TagKey.merge(TestSpanTags.values(),AsyncSpanTags.values())
String invocationString = methodInvocation.toString();
Matcher matcher = Pattern.compile("([a-zA-Z]+.values)").matcher(invocationString);
Collection<String> classNames = new TreeSet<>();
while (matcher.find()) {
String className = matcher.group(1).split("\\.")[0];
classNames.add(className);
}
return classNames;
}
else if (!methodInvocation.toString().endsWith(".values()")) {
throw new IllegalStateException("You have to use the static .values() method on the enum that implements "
+ TagKey.class + " or " + EventValue.class
+ " interface or use [TagKey.merge(...)] method to merge multiple values from tags");
}
// will return Tags
return Collections.singletonList(methodInvocation.getExpression().toString());
}
}

View File

@@ -1,45 +0,0 @@
/*
* Copyright 2013-2020 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
*
* https://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 org.springframework.cloud.sleuth.documentation;
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.util.regex.Pattern;
import org.assertj.core.api.BDDAssertions;
import org.junit.jupiter.api.Test;
class DocsFromSourcesTests {
@Test
void should_build_a_table_out_of_enum_tag_key() throws IOException {
File root = new File(".");
File output = new File(root, "target");
new DocsFromSources(root, Pattern.compile(".*"), output).generate();
BDDAssertions.then(new String(Files.readAllBytes(new File(output, "_spans.adoc").toPath())))
.contains("=== Async Annotation Span").contains("> Span that wraps a")
.contains("**Span name** `%s` - since").contains("Fully qualified name of")
.contains("|class|Class name where a method got annotated with @Async.")
.contains("=== Annotation New Or Continue Span")
.contains("|%s.before|Annotated before executing a method annotated with @ContinueSpan or @NewSpan.")
.contains("=== Test Span").contains("**Span name** `fixed`.").contains("|foooooo|Test foo");
}
}

View File

@@ -1,111 +0,0 @@
/*
* Copyright 2013-2021 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
*
* https://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 org.springframework.cloud.sleuth.documentation;
import org.springframework.cloud.sleuth.docs.DocumentedSpan;
import org.springframework.cloud.sleuth.docs.EventValue;
import org.springframework.cloud.sleuth.docs.TagKey;
enum SleuthAnnotationSpan implements DocumentedSpan {
/**
* Span that wraps a @NewSpan or @ContinueSpan annotations.
*/
ANNOTATION_NEW_OR_CONTINUE_SPAN {
@Override
public String getName() {
return "%s";
}
@Override
public TagKey[] getTagKeys() {
return Tags.values();
}
@Override
public EventValue[] getEvents() {
return Events.values();
}
};
/**
* Tags related to Sleuth annotations.
*
* @author Marcin Grzejszczak
* @since 3.0.3
*/
enum Tags implements TagKey {
/**
* Class name where a method got annotated with a Sleuth annotation.
*/
CLASS {
@Override
public String getKey() {
return "class";
}
},
/**
* Method name that got annotated with Sleuth annotation.
*/
METHOD {
@Override
public String getKey() {
return "method";
}
}
}
enum Events implements EventValue {
/**
* Annotated before executing a method annotated with @ContinueSpan or @NewSpan.
*/
BEFORE {
@Override
public String getValue() {
return "%s.before";
}
},
/**
* Annotated after executing a method annotated with @ContinueSpan or @NewSpan.
*/
AFTER {
@Override
public String getValue() {
return "%s.after";
}
},
/**
* Annotated after throwing an exception from a method annotated
* with @ContinueSpan or @NewSpan.
*/
AFTER_FAILURE {
@Override
public String getValue() {
return "%.afterFailure";
}
}
}
}

View File

@@ -1,95 +0,0 @@
/*
* Copyright 2013-2021 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
*
* https://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 org.springframework.cloud.sleuth.documentation;
import org.springframework.cloud.sleuth.docs.DocumentedSpan;
import org.springframework.cloud.sleuth.docs.TagKey;
enum SleuthAsyncSpan implements DocumentedSpan {
/**
* Span that wraps a @Async annotation. Either continues an existing one or creates a
* new one if there was no present one.
*/
ASYNC_ANNOTATION_SPAN {
@Override
public String getName() {
return "%s";
}
@Override
public TagKey[] getTagKeys() {
return AsyncSpanTags.values();
}
},
/**
* Test span.
*/
TEST_SPAN {
@Override
public String getName() {
return "fixed";
}
@Override
public TagKey[] getTagKeys() {
return TagKey.merge(TestSpanTags.values(), AsyncSpanTags.values());
}
};
enum AsyncSpanTags implements TagKey {
/**
* Class name where a method got annotated with @Async.
*/
CLASS {
@Override
public String getKey() {
return "class";
}
},
/**
* Method name that got annotated with @Async.
*/
METHOD {
@Override
public String getKey() {
return "method";
}
}
}
enum TestSpanTags implements TagKey {
/**
* Test foo
*/
FOO {
@Override
public String getKey() {
return "foooooo";
}
}
}
}

263
mvnw vendored
View File

@@ -1,263 +0,0 @@
#!/bin/sh
# ----------------------------------------------------------------------------
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you 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
#
# https://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.
# ----------------------------------------------------------------------------
# ----------------------------------------------------------------------------
# Maven2 Start Up Batch script
#
# Required ENV vars:
# ------------------
# JAVA_HOME - location of a JDK home dir
#
# Optional ENV vars
# -----------------
# M2_HOME - location of maven2's installed home dir
# MAVEN_OPTS - parameters passed to the Java VM when running Maven
# e.g. to debug Maven itself, use
# set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000
# MAVEN_SKIP_RC - flag to disable loading of mavenrc files
# ----------------------------------------------------------------------------
if [ -z "$MAVEN_SKIP_RC" ]; then
if [ -f /etc/mavenrc ]; then
. /etc/mavenrc
fi
if [ -f "$HOME/.mavenrc" ]; then
. "$HOME/.mavenrc"
fi
fi
# OS specific support. $var _must_ be set to either true or false.
cygwin=false
darwin=false
mingw=false
case "$(uname)" in
CYGWIN*) cygwin=true ;;
MINGW*) mingw=true ;;
Darwin*)
darwin=true
#
# Look for the Apple JDKs first to preserve the existing behaviour, and then look
# for the new JDKs provided by Oracle.
#
if [ -z "$JAVA_HOME" ] && [ -L /System/Library/Frameworks/JavaVM.framework/Versions/CurrentJDK ]; then
#
# Apple JDKs
#
export JAVA_HOME=/System/Library/Frameworks/JavaVM.framework/Versions/CurrentJDK/Home
fi
if [ -z "$JAVA_HOME" ] && [ -L /System/Library/Java/JavaVirtualMachines/CurrentJDK ]; then
#
# Apple JDKs
#
export JAVA_HOME=/System/Library/Java/JavaVirtualMachines/CurrentJDK/Contents/Home
fi
if [ -z "$JAVA_HOME" ] && [ -L "/Library/Java/JavaVirtualMachines/CurrentJDK" ]; then
#
# Oracle JDKs
#
export JAVA_HOME=/Library/Java/JavaVirtualMachines/CurrentJDK/Contents/Home
fi
if [ -z "$JAVA_HOME" ] && [ -x "/usr/libexec/java_home" ]; then
#
# Apple JDKs
#
export JAVA_HOME=$(/usr/libexec/java_home)
fi
;;
esac
if [ -z "$JAVA_HOME" ]; then
if [ -r /etc/gentoo-release ]; then
JAVA_HOME=$(java-config --jre-home)
fi
fi
if [ -z "$M2_HOME" ]; then
## resolve links - $0 may be a link to maven's home
PRG="$0"
# need this for relative symlinks
while [ -h "$PRG" ]; do
ls=$(ls -ld "$PRG")
link=$(expr "$ls" : '.*-> \(.*\)$')
if expr "$link" : '/.*' >/dev/null; then
PRG="$link"
else
PRG="$(dirname "$PRG")/$link"
fi
done
saveddir=$(pwd)
M2_HOME=$(dirname "$PRG")/..
# make it fully qualified
M2_HOME=$(cd "$M2_HOME" && pwd)
cd "$saveddir"
# echo Using m2 at $M2_HOME
fi
# For Cygwin, ensure paths are in UNIX format before anything is touched
if $cygwin; then
[ -n "$M2_HOME" ] &&
M2_HOME=$(cygpath --unix "$M2_HOME")
[ -n "$JAVA_HOME" ] &&
JAVA_HOME=$(cygpath --unix "$JAVA_HOME")
[ -n "$CLASSPATH" ] &&
CLASSPATH=$(cygpath --path --unix "$CLASSPATH")
fi
# For Migwn, ensure paths are in UNIX format before anything is touched
if $mingw; then
[ -n "$M2_HOME" ] &&
M2_HOME="$( (
cd "$M2_HOME"
pwd
))"
[ -n "$JAVA_HOME" ] &&
JAVA_HOME="$( (
cd "$JAVA_HOME"
pwd
))"
# TODO classpath?
fi
if [ -z "$JAVA_HOME" ]; then
javaExecutable="$(which javac)"
if [ -n "$javaExecutable" ] && ! [ "$(expr \"$javaExecutable\" : '\([^ ]*\)')" = "no" ]; then
# readlink(1) is not available as standard on Solaris 10.
readLink=$(which readlink)
if [ ! $(expr "$readLink" : '\([^ ]*\)') = "no" ]; then
if $darwin; then
javaHome="$(dirname \"$javaExecutable\")"
javaExecutable="$(cd \"$javaHome\" && pwd -P)/javac"
else
javaExecutable="$(readlink -f \"$javaExecutable\")"
fi
javaHome="$(dirname \"$javaExecutable\")"
javaHome=$(expr "$javaHome" : '\(.*\)/bin')
JAVA_HOME="$javaHome"
export JAVA_HOME
fi
fi
fi
if [ -z "$JAVACMD" ]; then
if [ -n "$JAVA_HOME" ]; then
if [ -x "$JAVA_HOME/jre/sh/java" ]; then
# IBM's JDK on AIX uses strange locations for the executables
JAVACMD="$JAVA_HOME/jre/sh/java"
else
JAVACMD="$JAVA_HOME/bin/java"
fi
else
JAVACMD="$(which java)"
fi
fi
if [ ! -x "$JAVACMD" ]; then
echo "Error: JAVA_HOME is not defined correctly." >&2
echo " We cannot execute $JAVACMD" >&2
exit 1
fi
if [ -z "$JAVA_HOME" ]; then
echo "Warning: JAVA_HOME environment variable is not set."
fi
CLASSWORLDS_LAUNCHER=org.codehaus.plexus.classworlds.launcher.Launcher
# For Cygwin, switch paths to Windows format before running java
if $cygwin; then
[ -n "$M2_HOME" ] &&
M2_HOME=$(cygpath --path --windows "$M2_HOME")
[ -n "$JAVA_HOME" ] &&
JAVA_HOME=$(cygpath --path --windows "$JAVA_HOME")
[ -n "$CLASSPATH" ] &&
CLASSPATH=$(cygpath --path --windows "$CLASSPATH")
fi
# traverses directory structure from process work directory to filesystem root
# first directory with .mvn subdirectory is considered project base directory
find_maven_basedir() {
local basedir=$(pwd)
local wdir=$(pwd)
while [ "$wdir" != '/' ]; do
if [ -d "$wdir"/.mvn ]; then
basedir=$wdir
break
fi
wdir=$(
cd "$wdir/.."
pwd
)
done
echo "${basedir}"
}
# concatenates all lines of a file
concat_lines() {
if [ -f "$1" ]; then
echo "$(tr -s '\n' ' ' <"$1")"
fi
}
export MAVEN_PROJECTBASEDIR=${MAVEN_BASEDIR:-$(find_maven_basedir)}
MAVEN_OPTS="$(concat_lines "$MAVEN_PROJECTBASEDIR/.mvn/jvm.config") $MAVEN_OPTS"
# Provide a "standardized" way to retrieve the CLI args that will
# work with both Windows and non-Windows executions.
MAVEN_CMD_LINE_ARGS="$MAVEN_CONFIG $@"
export MAVEN_CMD_LINE_ARGS
WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain
echo "Running version check"
VERSION=$(sed '\!<parent!,\!</parent!d' $(dirname $0)/pom.xml | grep '<version' | head -1 | sed -e 's/.*<version>//' -e 's!</version>.*$!!')
echo "The found version is [${VERSION}]"
if echo $VERSION | egrep -q 'M|RC'; then
echo Activating \"milestone\" profile for version=\"$VERSION\"
echo $MAVEN_ARGS | grep -q milestone || MAVEN_ARGS="$MAVEN_ARGS -Pmilestone"
else
echo Deactivating \"milestone\" profile for version=\"$VERSION\"
echo $MAVEN_ARGS | grep -q milestone && MAVEN_ARGS=$(echo $MAVEN_ARGS | sed -e 's/-Pmilestone//')
fi
if echo $VERSION | egrep -q 'RELEASE'; then
echo Activating \"central\" profile for version=\"$VERSION\"
echo $MAVEN_ARGS | grep -q milestone || MAVEN_ARGS="$MAVEN_ARGS -Pcentral"
else
echo Deactivating \"central\" profile for version=\"$VERSION\"
echo $MAVEN_ARGS | grep -q central && MAVEN_ARGS=$(echo $MAVEN_ARGS | sed -e 's/-Pcentral//')
fi
exec "$JAVACMD" \
$MAVEN_OPTS \
-classpath "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar" \
"-Dmaven.home=${M2_HOME}" "-Dmaven.multiModuleProjectDirectory=${MAVEN_PROJECTBASEDIR}" \
${WRAPPER_LAUNCHER} ${MAVEN_ARGS} "$@"

145
mvnw.cmd vendored
View File

@@ -1,145 +0,0 @@
@REM ----------------------------------------------------------------------------
@REM Licensed to the Apache Software Foundation (ASF) under one
@REM or more contributor license agreements. See the NOTICE file
@REM distributed with this work for additional information
@REM regarding copyright ownership. The ASF licenses this file
@REM to you under the Apache License, Version 2.0 (the
@REM "License"); you may not use this file except in compliance
@REM with the License. You may obtain a copy of the License at
@REM
@REM https://www.apache.org/licenses/LICENSE-2.0
@REM
@REM Unless required by applicable law or agreed to in writing,
@REM software distributed under the License is distributed on an
@REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
@REM KIND, either express or implied. See the License for the
@REM specific language governing permissions and limitations
@REM under the License.
@REM ----------------------------------------------------------------------------
@REM ----------------------------------------------------------------------------
@REM Maven2 Start Up Batch script
@REM
@REM Required ENV vars:
@REM JAVA_HOME - location of a JDK home dir
@REM
@REM Optional ENV vars
@REM M2_HOME - location of maven2's installed home dir
@REM MAVEN_BATCH_ECHO - set to 'on' to enable the echoing of the batch commands
@REM MAVEN_BATCH_PAUSE - set to 'on' to wait for a key stroke before ending
@REM MAVEN_OPTS - parameters passed to the Java VM when running Maven
@REM e.g. to debug Maven itself, use
@REM set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000
@REM MAVEN_SKIP_RC - flag to disable loading of mavenrc files
@REM ----------------------------------------------------------------------------
@REM Begin all REM lines with '@' in case MAVEN_BATCH_ECHO is 'on'
@echo off
@REM enable echoing my setting MAVEN_BATCH_ECHO to 'on'
@if "%MAVEN_BATCH_ECHO%" == "on" echo %MAVEN_BATCH_ECHO%
@REM set %HOME% to equivalent of $HOME
if "%HOME%" == "" (set "HOME=%HOMEDRIVE%%HOMEPATH%")
@REM Execute a user defined script before this one
if not "%MAVEN_SKIP_RC%" == "" goto skipRcPre
@REM check for pre script, once with legacy .bat ending and once with .cmd ending
if exist "%HOME%\mavenrc_pre.bat" call "%HOME%\mavenrc_pre.bat"
if exist "%HOME%\mavenrc_pre.cmd" call "%HOME%\mavenrc_pre.cmd"
:skipRcPre
@setlocal
set ERROR_CODE=0
@REM To isolate internal variables from possible post scripts, we use another setlocal
@setlocal
@REM ==== START VALIDATION ====
if not "%JAVA_HOME%" == "" goto OkJHome
echo.
echo Error: JAVA_HOME not found in your environment. >&2
echo Please set the JAVA_HOME variable in your environment to match the >&2
echo location of your Java installation. >&2
echo.
goto error
:OkJHome
if exist "%JAVA_HOME%\bin\java.exe" goto init
echo.
echo Error: JAVA_HOME is set to an invalid directory. >&2
echo JAVA_HOME = "%JAVA_HOME%" >&2
echo Please set the JAVA_HOME variable in your environment to match the >&2
echo location of your Java installation. >&2
echo.
goto error
@REM ==== END VALIDATION ====
:init
set MAVEN_CMD_LINE_ARGS=%*
@REM Find the project base dir, i.e. the directory that contains the folder ".mvn".
@REM Fallback to current working directory if not found.
set MAVEN_PROJECTBASEDIR=%MAVEN_BASEDIR%
IF NOT "%MAVEN_PROJECTBASEDIR%"=="" goto endDetectBaseDir
set EXEC_DIR=%CD%
set WDIR=%EXEC_DIR%
:findBaseDir
IF EXIST "%WDIR%"\.mvn goto baseDirFound
cd ..
IF "%WDIR%"=="%CD%" goto baseDirNotFound
set WDIR=%CD%
goto findBaseDir
:baseDirFound
set MAVEN_PROJECTBASEDIR=%WDIR%
cd "%EXEC_DIR%"
goto endDetectBaseDir
:baseDirNotFound
set MAVEN_PROJECTBASEDIR=%EXEC_DIR%
cd "%EXEC_DIR%"
:endDetectBaseDir
IF NOT EXIST "%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config" goto endReadAdditionalConfig
@setlocal EnableExtensions EnableDelayedExpansion
for /F "usebackq delims=" %%a in ("%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config") do set JVM_CONFIG_MAVEN_PROPS=!JVM_CONFIG_MAVEN_PROPS! %%a
@endlocal & set JVM_CONFIG_MAVEN_PROPS=%JVM_CONFIG_MAVEN_PROPS%
:endReadAdditionalConfig
SET MAVEN_JAVA_EXE="%JAVA_HOME%\bin\java.exe"
set WRAPPER_JAR="".\.mvn\wrapper\maven-wrapper.jar""
set WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain
%MAVEN_JAVA_EXE% %JVM_CONFIG_MAVEN_PROPS% %MAVEN_OPTS% %MAVEN_DEBUG_OPTS% -classpath %WRAPPER_JAR% "-Dmaven.multiModuleProjectDirectory=%MAVEN_PROJECTBASEDIR%" %WRAPPER_LAUNCHER% %MAVEN_CMD_LINE_ARGS%
if ERRORLEVEL 1 goto error
goto end
:error
set ERROR_CODE=1
:end
@endlocal & set ERROR_CODE=%ERROR_CODE%
if not "%MAVEN_SKIP_RC%" == "" goto skipRcPost
@REM check for post script, once with legacy .bat ending and once with .cmd ending
if exist "%HOME%\mavenrc_post.bat" call "%HOME%\mavenrc_post.bat"
if exist "%HOME%\mavenrc_post.cmd" call "%HOME%\mavenrc_post.cmd"
:skipRcPost
@REM pause the script if MAVEN_BATCH_PAUSE is set to 'on'
if "%MAVEN_BATCH_PAUSE%" == "on" pause
if "%MAVEN_TERMINATE_CMD%" == "on" exit %ERROR_CODE%
exit /B %ERROR_CODE%

514
pom.xml
View File

@@ -1,514 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
~ Copyright 2013-2018 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
~
~ https://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:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://maven.apache.org/POM/4.0.0"
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>
<artifactId>spring-cloud-sleuth</artifactId>
<version>3.1.1-SNAPSHOT</version>
<packaging>pom</packaging>
<name>Spring Cloud Sleuth</name>
<description>Spring Cloud Sleuth</description>
<parent>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-build</artifactId>
<version>3.1.1-SNAPSHOT</version>
<relativePath/>
<!-- lookup parent from repository -->
</parent>
<scm>
<url>https://github.com/spring-cloud/spring-cloud-sleuth</url>
<connection>scm:git:git://github.com/spring-cloud/spring-cloud-sleuth.git
</connection>
<developerConnection>
scm:git:ssh://git@github.com/spring-cloud/spring-cloud-sleuth.git
</developerConnection>
<tag>HEAD</tag>
</scm>
<modules>
<module>spring-cloud-sleuth-dependencies</module>
<module>spring-cloud-sleuth-api</module>
<module>spring-cloud-sleuth-instrumentation</module>
<module>spring-cloud-sleuth-brave</module>
<module>spring-cloud-sleuth-autoconfigure</module>
<module>tests</module>
<module>spring-cloud-sleuth-zipkin</module>
<module>spring-cloud-starter-sleuth</module>
<module>spring-cloud-sleuth-samples</module>
<module>docs</module>
</modules>
<properties>
<maven.compiler.target>1.8</maven.compiler.target>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.testTarget>1.8</maven.compiler.testTarget>
<maven.compiler.testSource>1.8</maven.compiler.testSource>
<spring-cloud-build.version>3.1.1-SNAPSHOT</spring-cloud-build.version>
<spring-cloud-commons.version>3.1.1-SNAPSHOT</spring-cloud-commons.version>
<spring-cloud-gateway.version>3.1.1-SNAPSHOT</spring-cloud-gateway.version>
<spring-cloud-config.version>3.1.1-SNAPSHOT</spring-cloud-config.version>
<spring-cloud-circuitbreaker.version>2.1.1-SNAPSHOT</spring-cloud-circuitbreaker.version>
<spring-cloud-stream.version>3.2.1</spring-cloud-stream.version>
<spring-cloud-function.version>3.2.1</spring-cloud-function.version>
<spring-cloud-netflix.version>3.1.1-SNAPSHOT</spring-cloud-netflix.version>
<spring-cloud-openfeign.version>3.1.1-SNAPSHOT</spring-cloud-openfeign.version>
<spring-cloud-task.version>2.4.1-SNAPSHOT</spring-cloud-task.version>
<spring-cloud-deployer.version>2.5.1</spring-cloud-deployer.version>
<brave.version>5.13.6</brave.version>
<opentracing.version>0.32.0</opentracing.version>
<spring-security-boot-autoconfigure.version>2.3.4.RELEASE</spring-security-boot-autoconfigure.version>
<spring-security-oauth2.version>2.2.0.RELEASE</spring-security-oauth2.version>
<spring-security-version>5.6.0</spring-security-version>
<disable.nohttp.checks>false</disable.nohttp.checks>
<okhttp.version>4.9.0</okhttp.version>
<mockwebserver.version>4.8.0</mockwebserver.version>
<guava.version>20.0</guava.version>
<javax.resource-api.version>1.7.1</javax.resource-api.version>
<cglib-nodep.version>3.3.0</cglib-nodep.version>
<objenesis.version>3.0.1</objenesis.version>
<p6spy.version>3.9.1</p6spy.version>
<datasource-proxy.version>1.7</datasource-proxy.version>
<tomcat-jdbc.version>10.0.6</tomcat-jdbc.version>
<commons-dbcp2.version>2.8.0</commons-dbcp2.version>
<kotlin.version>1.5.20</kotlin.version>
<!-- Until we switch it to true in sc-build -->
<javadoc.failOnError>true</javadoc.failOnError>
<javadoc.failOnWarnings>false</javadoc.failOnWarnings>
<commons-lang3.version>3.8.1</commons-lang3.version>
<hamcrest-core.version>2.2</hamcrest-core.version>
<awaitility.version>4.0.3</awaitility.version>
<brave-propagation-aws.version>0.21.3</brave-propagation-aws.version>
<archunit-junit5.version>0.14.1</archunit-junit5.version>
<testcontainers.version>1.15.3</testcontainers.version>
<build-helper-maven-plugin.version>3.2.0</build-helper-maven-plugin.version>
</properties>
<build>
<pluginManagement>
<plugins>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.1</version>
<executions>
<execution>
<id>default-compile</id>
<configuration>
<showDeprecation>true</showDeprecation>
<showWarnings>true</showWarnings>
<compilerArguments>
<source>${maven.compiler.source}</source>
<target>${maven.compiler.target}</target>
</compilerArguments>
</configuration>
</execution>
<execution>
<id>default-testCompile</id>
<configuration>
<showDeprecation>true</showDeprecation>
<showWarnings>true</showWarnings>
<compilerArguments>
<source>${maven.compiler.testSource}</source>
<target>${maven.compiler.testTarget}</target>
</compilerArguments>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<artifactId>maven-enforcer-plugin</artifactId>
<version>1.3.1</version>
<executions>
<execution>
<id>enforce-java</id>
<goals>
<goal>enforce</goal>
</goals>
<configuration>
<rules>
<requireJavaVersion>
<version>${maven.compiler.testTarget}</version>
</requireJavaVersion>
</rules>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<artifactId>maven-deploy-plugin</artifactId>
<version>2.8.2</version>
</plugin>
<plugin>
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
<systemPropertyVariables>
<spring.cloud.sleuth.assertions.enabled>true</spring.cloud.sleuth.assertions.enabled>
</systemPropertyVariables>
</configuration>
</plugin>
</plugins>
</pluginManagement>
<plugins>
<plugin>
<groupId>io.spring.javaformat</groupId>
<artifactId>spring-javaformat-maven-plugin</artifactId>
</plugin>
<plugin>
<artifactId>maven-checkstyle-plugin</artifactId>
</plugin>
</plugins>
</build>
<reporting>
<plugins>
<plugin>
<artifactId>maven-checkstyle-plugin</artifactId>
</plugin>
<plugin>
<artifactId>maven-surefire-report-plugin</artifactId>
</plugin>
</plugins>
</reporting>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-sleuth-dependencies</artifactId>
<version>${project.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-netflix-dependencies</artifactId>
<version>${spring-cloud-netflix.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-commons-dependencies</artifactId>
<version>${spring-cloud-commons.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-gateway-dependencies</artifactId>
<version>${spring-cloud-gateway.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-circuitbreaker-dependencies</artifactId>
<version>${spring-cloud-circuitbreaker.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-stream-dependencies</artifactId>
<version>${spring-cloud-stream.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-function-dependencies</artifactId>
<version>${spring-cloud-function.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-openfeign-dependencies</artifactId>
<version>${spring-cloud-openfeign.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-config-dependencies</artifactId>
<version>${spring-cloud-config.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-task-dependencies</artifactId>
<version>${spring-cloud-task.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-deployer-dependencies</artifactId>
<version>${spring-cloud-deployer.version}</version>
<scope>import</scope>
<type>pom</type>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-bom</artifactId>
<version>${spring-security-version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>org.springframework.security.oauth.boot</groupId>
<artifactId>spring-security-oauth2-autoconfigure</artifactId>
<version>${spring-security-boot-autoconfigure.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.security.oauth</groupId>
<artifactId>spring-security-oauth2</artifactId>
<version>${spring-security-oauth2.version}</version>
</dependency>
<dependency>
<groupId>cglib</groupId>
<artifactId>cglib-nodep</artifactId>
<version>${cglib-nodep.version}</version>
</dependency>
<dependency>
<groupId>org.objenesis</groupId>
<artifactId>objenesis</artifactId>
<version>${objenesis.version}</version>
<!-- not test because we need it in stream -->
</dependency>
<dependency>
<groupId>com.squareup.okhttp3</groupId>
<artifactId>mockwebserver</artifactId>
<version>${mockwebserver.version}</version>
</dependency>
<dependency>
<groupId>io.zipkin.aws</groupId>
<artifactId>brave-propagation-aws</artifactId>
<version>${brave-propagation-aws.version}</version>
</dependency>
<dependency>
<groupId>p6spy</groupId>
<artifactId>p6spy</artifactId>
<version>${p6spy.version}</version>
</dependency>
<dependency>
<groupId>net.ttddyy</groupId>
<artifactId>datasource-proxy</artifactId>
<version>${datasource-proxy.version}</version>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-dbcp2</artifactId>
<version>${commons-dbcp2.version}</version>
</dependency>
<dependency>
<groupId>org.apache.tomcat</groupId>
<artifactId>tomcat-jdbc</artifactId>
<version>${tomcat-jdbc.version}</version>
</dependency>
<dependency>
<groupId>org.hamcrest</groupId>
<artifactId>hamcrest-core</artifactId>
<version>${hamcrest-core.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.awaitility</groupId>
<artifactId>awaitility</artifactId>
<version>${awaitility.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.tngtech.archunit</groupId>
<artifactId>archunit-junit5</artifactId>
<version>${archunit-junit5.version}</version>
</dependency>
<dependency>
<groupId>org.testcontainers</groupId>
<artifactId>testcontainers-bom</artifactId>
<version>${testcontainers.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<profiles>
<profile>
<id>spring</id>
<repositories>
<repository>
<id>spring-snapshots</id>
<name>Spring Snapshots</name>
<url>https://repo.spring.io/snapshot</url>
<snapshots>
<enabled>true</enabled>
</snapshots>
<releases>
<enabled>false</enabled>
</releases>
</repository>
<!-- BRAVE -->
<repository>
<id>jfrog-snapshots</id>
<name>JFrog Snapshots</name>
<url>https://oss.jfrog.org/oss-snapshot-local/</url>
<snapshots>
<enabled>true</enabled>
</snapshots>
<releases>
<enabled>false</enabled>
</releases>
</repository>
<repository>
<id>spring-milestones</id>
<name>Spring Milestones</name>
<url>https://repo.spring.io/milestone</url>
<snapshots>
<enabled>false</enabled>
</snapshots>
</repository>
<repository>
<id>spring-releases</id>
<name>Spring Releases</name>
<url>https://repo.spring.io/release</url>
<snapshots>
<enabled>false</enabled>
</snapshots>
</repository>
</repositories>
<pluginRepositories>
<pluginRepository>
<id>spring-snapshots</id>
<name>Spring Snapshots</name>
<url>https://repo.spring.io/snapshot</url>
<snapshots>
<enabled>true</enabled>
</snapshots>
<releases>
<enabled>false</enabled>
</releases>
</pluginRepository>
<pluginRepository>
<id>spring-milestones</id>
<name>Spring Milestones</name>
<url>https://repo.spring.io/milestone</url>
<snapshots>
<enabled>false</enabled>
</snapshots>
</pluginRepository>
<pluginRepository>
<id>spring-releases</id>
<name>Spring Releases</name>
<url>https://repo.spring.io/release</url>
<snapshots>
<enabled>false</enabled>
</snapshots>
</pluginRepository>
</pluginRepositories>
</profile>
<profile>
<id>ide</id>
<activation>
<activeByDefault>false</activeByDefault>
</activation>
<build>
<plugins>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>${maven.compiler.testSource}</source>
<target>${maven.compiler.testTarget}</target>
</configuration>
</plugin>
</plugins>
</build>
</profile>
<profile>
<id>benchmarks</id>
<activation>
<activeByDefault>false</activeByDefault>
</activation>
<modules>
<module>benchmarks</module>
</modules>
</profile>
<profile>
<id>sonar</id>
<build>
<plugins>
<plugin>
<groupId>org.jacoco</groupId>
<artifactId>jacoco-maven-plugin</artifactId>
<executions>
<execution>
<id>pre-unit-test</id>
<goals>
<goal>prepare-agent</goal>
</goals>
<configuration>
<propertyName>surefireArgLine</propertyName>
<destFile>${project.build.directory}/jacoco.exec
</destFile>
</configuration>
</execution>
<execution>
<id>post-unit-test</id>
<phase>test</phase>
<goals>
<goal>report</goal>
</goals>
<configuration>
<!-- Sets the path to the file which contains the execution data. -->
<dataFile>${project.build.directory}/jacoco.exec
</dataFile>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
<!-- Sets the VM argument line used when unit tests are run. -->
<argLine>${surefireArgLine}</argLine>
</configuration>
</plugin>
</plugins>
</build>
</profile>
<profile>
<id>withoutDockerTests</id>
<build>
<plugins>
<plugin>
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
<excludedGroups>DockerRequired</excludedGroups>
</configuration>
</plugin>
</plugins>
</build>
</profile>
</profiles>
</project>

View File

@@ -1,20 +0,0 @@
#!/bin/bash
set -o errexit
mkdir -p target
SCRIPT_URL="https://raw.githubusercontent.com/spring-cloud-samples/brewery/main/runAcceptanceTests.sh"
AT_WHAT_TO_TEST="SLEUTH"
BRANCH_NAME="main"
cd target
curl "${SCRIPT_URL}" --output runAcceptanceTests.sh
chmod +x runAcceptanceTests.sh
echo "Killing all running apps"
./runAcceptanceTests.sh -t "${AT_WHAT_TO_TEST}" -n -br "${BRANCH_NAME}"
./runAcceptanceTests.sh --whattotest "${AT_WHAT_TO_TEST}" --killattheend -br "${BRANCH_NAME}"

View File

@@ -1,17 +0,0 @@
#!/bin/bash
set -o errexit
mkdir -p target
REPO_URL="https://github.com/spring-cloud-samples/sleuth-documentation-apps.git"
BRANCH_NAME="main"
pushd target
git clone "${REPO_URL}"
pushd sleuth-documentation-apps
./scripts/runAcceptanceTests.sh
popd
popd

View File

@@ -1,20 +0,0 @@
#!/bin/bash
set -o errexit
mkdir -p target
SCRIPT_URL="https://raw.githubusercontent.com/spring-cloud-samples/brewery/main/runAcceptanceTests.sh"
AT_WHAT_TO_TEST="SLEUTH_STREAM"
BRANCH_NAME="main"
cd target
curl "${SCRIPT_URL}" --output runAcceptanceTests.sh
chmod +x runAcceptanceTests.sh
echo "Killing all running apps"
./runAcceptanceTests.sh -t "${AT_WHAT_TO_TEST}" -n -br "${BRANCH_NAME}"
./runAcceptanceTests.sh --whattotest "${AT_WHAT_TO_TEST}" --killattheend -br "${BRANCH_NAME}"

View File

@@ -1,20 +0,0 @@
#!/bin/bash
set -o errexit
mkdir -p target
SCRIPT_URL="https://raw.githubusercontent.com/spring-cloud-samples/brewery/main/runAcceptanceTests.sh"
AT_WHAT_TO_TEST="SLEUTH_STREAM"
BRANCH_NAME="main"
cd target
curl "${SCRIPT_URL}" --output runAcceptanceTests.sh
chmod +x runAcceptanceTests.sh
echo "Killing all running apps"
./runAcceptanceTests.sh -t "${AT_WHAT_TO_TEST}" -n -br "${BRANCH_NAME}"
./runAcceptanceTests.sh --kafka --whattotest "${AT_WHAT_TO_TEST}" --killattheend -cli "1.3.3.BUILD-SNAPSHOT" -br "${BRANCH_NAME}"

View File

@@ -1,17 +0,0 @@
#!/bin/bash
set -o errexit
mkdir -p target
SCRIPT_URL="https://raw.githubusercontent.com/spring-cloud-samples/brewery/main/runAcceptanceTests.sh"
AT_WHAT_TO_TEST="SLEUTH"
BRANCH_NAME="main"
cd target
curl "${SCRIPT_URL}" --output runAcceptanceTests.sh
chmod +x runAcceptanceTests.sh
./runAcceptanceTests.sh --whattotest "${AT_WHAT_TO_TEST}" --usecloudfoundry --reset -br "${BRANCH_NAME}"

View File

@@ -1,9 +0,0 @@
#!/bin/bash
echo "Killing the remaining apps - if something went wrong previously"
pkill -f SleuthBenchmarkingSpringApp || echo "No apps to kill"
echo "Running JMeter Benchmarks"
./mvnw clean verify --projects benchmarks --also-make -Pbenchmarks,jmeter
echo "Killing the remaining apps - if something went wrong after the tests"
pkill -f SleuthBenchmarkingSpringApp || echo "No apps to kill"

View File

@@ -1,11 +0,0 @@
#!/bin/bash
echo "Running JMH Benchmarks"
ROOT="$(pwd)"
JMH_RESULT_FILE_PARENT="${ROOT}"
mkdir -p "${JMH_RESULT_FILE_PARENT}"
JMH_RESULT_FILE="${JMH_RESULT_FILE_PARENT}/jmh-result.csv"
echo "Will produce results under [${JMH_RESULT_FILE}]"
./mvnw clean install -Pbenchmarks -pl benchmarks --also-make -DskipTests && ./mvnw verify -DpublishTo=csv:"${JMH_RESULT_FILE}" -pl benchmarks -Pbenchmarks
# java -Djmh.ignoreLock=true -jar benchmarks/target/benchmarks.jar org.springframework.cloud.sleuth.benchmarks.jmh.* -rf csv -rff jmh-result.csv | tee target/benchmarks.log

View File

@@ -1,90 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
~ Copyright 2013-2018 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
~
~ https://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:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://maven.apache.org/POM/4.0.0"
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>
<artifactId>spring-cloud-sleuth-api</artifactId>
<packaging>jar</packaging>
<name>Spring Cloud Sleuth API</name>
<description>Spring Cloud Sleuth API</description>
<parent>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-sleuth</artifactId>
<version>3.1.1-SNAPSHOT</version>
<relativePath>..</relativePath>
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<optional>true</optional>
</dependency>
<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-autoconfigure-processor</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.awaitility</groupId>
<artifactId>awaitility</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.tngtech.archunit</groupId>
<artifactId>archunit-junit5</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<profiles>
<profile>
<id>fast</id>
<activation>
<activeByDefault>false</activeByDefault>
</activation>
<build>
<plugins>
<plugin>
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
<forkCount>4</forkCount>
<reuseForks>true</reuseForks>
<argLine>-Xmx1024m -XX:MaxPermSize=256m</argLine>
</configuration>
</plugin>
</plugins>
</build>
</profile>
</profiles>
</project>

View File

@@ -1,80 +0,0 @@
/*
* Copyright 2013-2021 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
*
* https://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 org.springframework.cloud.sleuth;
import java.io.Closeable;
import org.springframework.lang.Nullable;
/**
* Inspired by OpenZipkin Brave's {@code BaggageField}. Since some tracer implementations
* require a scope to be wrapped around baggage, baggage must be closed so that the scope
* does not leak. Some tracer implementations make baggage immutable (e.g. OpenTelemetry),
* so when the value gets updated they might create new scope (others will return the same
* one - e.g. OpenZipkin Brave).
*
* Represents a single baggage entry.
*
* @author Marcin Grzejszczak
* @since 3.0.0
*/
public interface BaggageInScope extends Closeable {
/**
* @return name of the baggage entry
*/
String name();
/**
* @return value of the baggage entry or {@code null} if not set.
*/
@Nullable
String get();
/**
* Retrieves baggage from the given {@link TraceContext}.
* @param traceContext context containing baggage
* @return value of the baggage entry or {@code null} if not set.
*/
@Nullable
String get(TraceContext traceContext);
/**
* Sets the baggage value.
* @param value to set
* @return new scope
*/
BaggageInScope set(String value);
/**
* Sets the baggage value for the given {@link TraceContext}.
* @param traceContext context containing baggage
* @param value to set
* @return new scope
*/
BaggageInScope set(TraceContext traceContext, String value);
/**
* Sets the current baggage in scope.
* @return this in scope
*/
BaggageInScope makeCurrent();
@Override
void close();
}

View File

@@ -1,72 +0,0 @@
/*
* Copyright 2013-2021 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
*
* https://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 org.springframework.cloud.sleuth;
import java.util.Map;
import org.springframework.lang.Nullable;
/**
* Manages {@link BaggageInScope} entries. Upon retrieval / creation of a baggage entry
* puts it in scope. Scope must be closed.
*
* @author OpenTelemetry Authors
* @author Marcin Grzejszczak
* @since 3.0.0
*/
public interface BaggageManager {
/**
* @return mapping of all baggage entries from the given scope
*/
Map<String, String> getAllBaggage();
/**
* Retrieves {@link BaggageInScope} for the given name.
* @param name baggage name
* @return baggage or {@code null} if not present
*/
@Nullable
BaggageInScope getBaggage(String name);
/**
* Retrieves {@link BaggageInScope} for the given name.
* @param traceContext trace context with baggage attached to it
* @param name baggage name
* @return baggage or {@code null} if not present
*/
@Nullable
BaggageInScope getBaggage(TraceContext traceContext, String name);
/**
* Creates a new {@link BaggageInScope} entry for the given name or returns an
* existing one if it's already present.
* @param name baggage name
* @return new or already created baggage
*/
BaggageInScope createBaggage(String name);
/**
* Creates a new {@link BaggageInScope} entry for the given name or returns an
* existing one if it's already present.
* @param name baggage name
* @param value baggage value
* @return new or already created baggage
*/
BaggageInScope createBaggage(String name, String value);
}

View File

@@ -1,102 +0,0 @@
/*
* Copyright 2013-2021 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
*
* https://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 org.springframework.cloud.sleuth;
import java.io.Closeable;
import java.util.concurrent.Callable;
import java.util.concurrent.Executor;
import java.util.concurrent.ExecutorService;
import org.springframework.lang.Nullable;
/**
* This API was heavily influenced by Brave. Parts of its documentation were taken
* directly from Brave.
*
* This makes a given span the current span by placing it in scope (usually but not always
* a thread local scope).
*
* @author OpenZipkin Brave Authors
* @author Marcin Grzejszczak
* @since 3.0.0
*/
public interface CurrentTraceContext {
/**
* @return current {@link TraceContext} or {@code null} if not set.
*/
@Nullable
TraceContext context();
/**
* Sets the current span in scope until the returned object is closed. It is a
* programming error to drop or never close the result. Using try-with-resources is
* preferred for this reason.
* @param context span to place into scope or {@code null} to clear the scope
* @return the scope with the span set
*/
CurrentTraceContext.Scope newScope(@Nullable TraceContext context);
/**
* Like {@link #newScope(TraceContext)}, except returns a noop scope if the given
* context is already in scope.
* @param context span to place into scope or {@code null} to clear the scope
* @return the scope with the span set
*/
CurrentTraceContext.Scope maybeScope(@Nullable TraceContext context);
/**
* Wraps a task in a trace representation.
* @param task task to wrap
* @param <C> task return type
* @return wrapped task
*/
<C> Callable<C> wrap(Callable<C> task);
/**
* Wraps a task in a trace representation.
* @param task task to wrap
* @return wrapped task
*/
Runnable wrap(Runnable task);
/**
* Wraps an executor in a trace representation.
* @param delegate executor to wrap
* @return wrapped executor
*/
Executor wrap(Executor delegate);
/**
* Wraps an executor service in a trace representation.
* @param delegate executor service to wrap
* @return wrapped executor service
*/
ExecutorService wrap(ExecutorService delegate);
/**
* Scope of a span. Needs to be closed so that resources are let go (e.g. MDC is
* cleared).
*/
interface Scope extends Closeable {
@Override
void close();
}
}

View File

@@ -1,123 +0,0 @@
/*
* Copyright 2013-2021 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
*
* https://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 org.springframework.cloud.sleuth;
import org.springframework.lang.Nullable;
/**
* This API was heavily influenced by Brave. Parts of its documentation were taken
* directly from Brave.
*
* Decides whether to start a new trace based on request properties such as an HTTP path.
*
* @param <T> type of the input, for example a request or method
* @author OpenZipkin Brave Authors
* @author Marcin Grzejszczak
* @since 3.0.0
*/
public interface SamplerFunction<T> {
/**
* Returns an overriding sampling decision for a new trace.
* @param arg parameter to evaluate for a sampling decision. {@code null} input
* results in a {@code null} result
* @return {@code true} to sample a new trace or {@code false} to deny. {@code null}
* defers the decision.
*/
@Nullable
Boolean trySample(@Nullable T arg);
/**
* Always deferring {@link SamplerFunction}.
* @param <T> type of the input, for example a request or method
* @return decision deferring sampler function
*/
static <T> SamplerFunction<T> deferDecision() {
return (SamplerFunction<T>) Constants.DEFER_DECISION;
}
/**
* Never sampling {@link SamplerFunction}.
* @param <T> type of the input, for example a request or method
* @return never sampling sampler function
*/
static <T> SamplerFunction<T> neverSample() {
return (SamplerFunction<T>) Constants.NEVER_SAMPLE;
}
/**
* Always sampling {@link SamplerFunction}.
* @param <T> type of the input, for example a request or method
* @return always sampling sampler function
*/
static <T> SamplerFunction<T> alwaysSample() {
return (SamplerFunction<T>) Constants.ALWAYS_SAMPLE;
}
/**
* Constant {@link SamplerFunction}s.
*/
enum Constants implements SamplerFunction<Object> {
/**
* Always defers sampling decision.
*/
DEFER_DECISION {
@Override
public Boolean trySample(Object request) {
return null;
}
@Override
public String toString() {
return "DeferDecision";
}
},
/**
* Will never sample this trace.
*/
NEVER_SAMPLE {
@Override
public Boolean trySample(Object request) {
return false;
}
@Override
public String toString() {
return "NeverSample";
}
},
/**
* Will always sample this trace.
*/
ALWAYS_SAMPLE {
@Override
public Boolean trySample(Object request) {
return true;
}
@Override
public String toString() {
return "AlwaysSample";
}
}
}
}

View File

@@ -1,74 +0,0 @@
/*
* Copyright 2013-2021 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
*
* https://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 org.springframework.cloud.sleuth;
/**
* Represents the "current span" until {@link ScopedSpan#end()} ()} is called.
*
* @author OpenZipkin Brave Authors
* @author Marcin Grzejszczak
* @since 3.0.0
*/
public interface ScopedSpan {
/**
* @return {@code true} when no recording is done and nothing is reported to an
* external system. However, this span should still be injected into outgoing
* requests. Use this flag to avoid performing expensive computation.
*/
boolean isNoop();
/**
* @return {@link TraceContext} corresponding to this span.
*/
TraceContext context();
/**
* Sets a name on this span.
* @param name name to set on the span
* @return this span
*/
ScopedSpan name(String name);
/**
* Sets a tag on this span.
* @param key tag key
* @param value tag value
* @return this span
*/
ScopedSpan tag(String key, String value);
/**
* Sets an event on this span.
* @param value event name to set on the span
* @return this span
*/
ScopedSpan event(String value);
/**
* Records an exception for this span.
* @param throwable to record
* @return this span
*/
ScopedSpan error(Throwable throwable);
/**
* Ends the span. The span gets stopped and recorded if not noop.
*/
void end();
}

View File

@@ -1,234 +0,0 @@
/*
* Copyright 2013-2021 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
*
* https://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 org.springframework.cloud.sleuth;
import org.springframework.cloud.sleuth.propagation.Propagator;
/**
*
* This API was heavily influenced by Brave. Parts of its documentation were taken
* directly from Brave.
*
* Span is a single unit of work that needs to be started and stopped. Contains timing
* information and events and tags.
*
* @author OpenZipkin Brave Authors
* @author Marcin Grzejszczak
* @since 3.0.0
*/
public interface Span extends SpanCustomizer {
/**
* @return {@code true} when no recording is done and nothing is reported to an
* external system. However, this span should still be injected into outgoing
* requests. Use this flag to avoid performing expensive computation.
*/
boolean isNoop();
/**
* @return {@link TraceContext} corresponding to this span.
*/
TraceContext context();
/**
* Starts this span.
* @return this span
*/
Span start();
/**
* Sets a name on this span.
* @param name name to set on the span
* @return this span
*/
Span name(String name);
/**
* Sets an event on this span.
* @param value event name to set on the span
* @return this span
*/
Span event(String value);
/**
* Sets a tag on this span.
* @param key tag key
* @param value tag value
* @return this span
*/
Span tag(String key, String value);
/**
* Records an exception for this span.
* @param throwable to record
* @return this span
*/
Span error(Throwable throwable);
/**
* Ends the span. The span gets stopped and recorded if not noop.
*/
void end();
/**
* Ends the span. The span gets stopped but does not get recorded.
*/
void abandon();
/**
* Sets the remote service name for the span.
* @param remoteServiceName remote service name
* @return this span
* @since 3.0.3
*/
default Span remoteServiceName(String remoteServiceName) {
return this;
}
/**
* Sets the remote url on the span.
* @param ip remote ip
* @param port remote port
* @return this span
* @since 3.1.0
*/
default Span remoteIpAndPort(String ip, int port) {
return this;
}
/**
* Type of span. Can be used to specify additional relationships between spans in
* addition to a parent/child relationship.
*
* Documentation of the enum taken from OpenTelemetry.
*/
enum Kind {
/**
* Indicates that the span covers server-side handling of an RPC or other remote
* request.
*/
SERVER,
/**
* Indicates that the span covers the client-side wrapper around an RPC or other
* remote request.
*/
CLIENT,
/**
* Indicates that the span describes producer sending a message to a broker.
* Unlike client and server, there is no direct critical path latency relationship
* between producer and consumer spans.
*/
PRODUCER,
/**
* Indicates that the span describes consumer receiving a message from a broker.
* Unlike client and server, there is no direct critical path latency relationship
* between producer and consumer spans.
*/
CONSUMER
}
/**
* In some cases (e.g. when dealing with
* {@link Propagator#extract(Object, Propagator.Getter)}'s we want to create a span
* that has not yet been started, yet it's heavily configurable (some options are not
* possible to be set when a span has already been started). We can achieve that by
* using a builder.
*
* Inspired by OpenZipkin Brave and OpenTelemetry API.
*/
interface Builder {
/**
* Sets the parent of the built span.
* @param context parent's context
* @return this
*/
Builder setParent(TraceContext context);
/**
* Sets no parent of the built span.
* @return this
*/
Builder setNoParent();
/**
* Sets the name of the span.
* @param name span name
* @return this
*/
Builder name(String name);
/**
* Sets an event on the span.
* @param value event value
* @return this
*/
Builder event(String value);
/**
* Sets a tag on the span.
* @param key tag key
* @param value tag value
* @return this
*/
Builder tag(String key, String value);
/**
* Sets an error on the span.
* @param throwable error to set
* @return this
*/
Builder error(Throwable throwable);
/**
* Sets the kind on the span.
* @param spanKind kind of the span
* @return this
*/
Builder kind(Span.Kind spanKind);
/**
* Sets the remote service name for the span.
* @param remoteServiceName remote service name
* @return this
*/
Builder remoteServiceName(String remoteServiceName);
/**
* Sets the remote URL for the span.
* @param ip remote service ip
* @param port remote service port
* @return this
*/
default Builder remoteIpAndPort(String ip, int port) {
return this;
}
/**
* Builds and starts the span.
* @return started span
*/
Span start();
}
}

View File

@@ -1,68 +0,0 @@
/*
* Copyright 2013-2021 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
*
* https://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 org.springframework.cloud.sleuth;
import java.io.Closeable;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
/**
* Container object for {@link Span} and its corresponding {@link Tracer.SpanInScope}.
*
* @author Marcin Grzejszczak
* @author Arthur Gavlyukovskiy
* @since 3.1.0
*/
public class SpanAndScope implements Closeable {
private static final Log log = LogFactory.getLog(SpanAndScope.class);
private final Span span;
private final Tracer.SpanInScope scope;
public SpanAndScope(Span span, Tracer.SpanInScope scope) {
this.span = span;
this.scope = scope;
}
public Span getSpan() {
return this.span;
}
public Tracer.SpanInScope getScope() {
return this.scope;
}
@Override
public String toString() {
return "SpanAndScope{" + "span=" + this.span + '}';
}
@Override
public void close() {
if (log.isTraceEnabled()) {
log.trace("Closing span [" + this.span + "]");
}
if (this.scope != null) {
this.scope.close();
}
this.span.end();
}
}

View File

@@ -1,50 +0,0 @@
/*
* Copyright 2013-2021 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
*
* https://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 org.springframework.cloud.sleuth;
/**
* Allows to customize the current span in scope.
*
* @author OpenZipkin Brave Authors
* @author Marcin Grzejszczak
* @since 3.0.0
*/
public interface SpanCustomizer {
/**
* Sets a name on a span.
* @param name name to set on a span
* @return this, for chaining
*/
SpanCustomizer name(String name);
/**
* Sets a tag on a span.
* @param key tag key
* @param value tag value
* @return this, for chaining
*/
SpanCustomizer tag(String key, String value);
/**
* Sets an event on a span.
* @param value event name
* @return this, for chaining
*/
SpanCustomizer event(String value);
}

View File

@@ -1,74 +0,0 @@
/*
* Copyright 2013-2021 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
*
* https://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 org.springframework.cloud.sleuth;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* Annotation to provide the name for the span. You should annotate all your custom
* {@link Runnable Runnable} or {@link java.util.concurrent.Callable Callable} classes for
* the instrumentation logic to pick up how to name the span.
* <p>
*
* Having for example the following code <pre>{@code
* &#64;SpanName("custom-operation")
* class CustomRunnable implements Runnable {
* &#64;Override
* public void run() {
* // latency of this method will be recorded in a span named "custom-operation"
* }
* }
* }</pre>
*
* Will result in creating a span with name {@code custom-operation}.
* <p>
*
* When there's no @SpanName annotation, {@code toString} is used. Here's an example of
* the above, but via an anonymous instance. <pre>{@code
* return new Runnable() {
* -- snip --
*
* &#64;Override
* public String toString() {
* return "custom-operation";
* }
* };
* }</pre>
*
* Starting with version {@code 1.3.0} you can also put the annotation on an
* {@link org.springframework.scheduling.annotation.Async} annotated method and the value
* of that annotation will be used as the span name.
*
* @author Marcin Grzejszczak
* @since 1.0.0
*/
@Target({ ElementType.TYPE, ElementType.METHOD })
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface SpanName {
/**
* Name of the span to be resolved at runtime.
* @return - value of the span name.
*/
String value();
}

View File

@@ -1,38 +0,0 @@
/*
* Copyright 2013-2021 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
*
* https://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 org.springframework.cloud.sleuth;
/**
* Describes how for a given object a span should be named. In the vast majority of cases
* a name should be provided explicitly. In case of instrumentation where the name has to
* be resolved at runtime this interface will provide the name of the span.
*
* @author Marcin Grzejszczak
* @since 1.0.0
*/
public interface SpanNamer {
/**
* Retrieves the span name for the given object.
* @param object - object for which span name should be picked
* @param defaultValue - the default valued to be returned if span name can't be
* calculated
* @return span name
*/
String name(Object object, String defaultValue);
}

Some files were not shown because too many files have changed in this diff Show More