Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adds Micrometer Tracing Example #110

Merged
merged 1 commit into from
Feb 6, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .dockerignore
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
!jersey2-cassandra3/src/main/**
!netty4-grpc/src/main/**
!webflux5-sleuth/src/main/**
!webflux6-micrometer/src/main/**
!webmvc3-jetty/src/main/**
!webmvc4-boot/src/main/**
!webmvc4-jetty/src/main/**
Expand Down
46 changes: 46 additions & 0 deletions .github/workflows/deploy-webflux6-micrometer.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
# yamllint --format github .github/workflows/deploy.yml
---
name: deploy webflux6-micrometer

on:
# We deploy non-tagged pushes to master relevant for this project. We can't opt out of
# documentation-only commits because GH actions does not permit paths and paths-ignore.
push:
tags: ''
branches: master
paths:
- "build-bin/**"
- "docker/**"
- "webflux6-micrometer/**"
- ".github/workflows/deploy-webflux6-micrometer.yaml"
- "parent-pom.xml"

jobs:
deploy:
runs-on: ubuntu-22.04 # newest available distribution, aka jellyfish
steps:
- name: Checkout Repository
uses: actions/checkout@v4
with:
fetch-depth: 1
- name: Cache local Maven repository
uses: actions/cache@v3
with:
path: ./m2repository # Shared with the Docker build context via .dockerignore
key: ${{ runner.os }}-webflux6-micrometer-maven-${{ hashFiles('parent-pom.xml', 'webflux6-micrometer/pom.xml') }}
restore-keys: ${{ runner.os }}-webflux6-micrometer-maven-
# Don't attempt to cache Docker. Sensitive information can be stolen
# via forks, and login session ends up in ~/.docker. This is ok because
# we publish DOCKER_PARENT_IMAGE to ghcr.io, hence local to the runner.
- name: Deploy webflux6-micrometer
env:
# GH_USER=<user that created GH_TOKEN>
GH_USER: ${{ secrets.GH_USER }}
# GH_TOKEN=<hex token value>
# - pushes Docker images to ghcr.io
# - create via https://github.com/settings/tokens
# - needs repo:status, public_repo, write:packages, delete:packages
GH_TOKEN: ${{ secrets.GH_TOKEN }}
run: |
build-bin/configure_deploy webflux6-micrometer &&
build-bin/deploy webflux6-micrometer
37 changes: 37 additions & 0 deletions .github/workflows/test-webflux6-micrometer.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
# yamllint --format github .github/workflows/test.yml
---
name: test webflux6-micrometer

on:
# We deploy non-tagged pushes to master relevant for this project. We can't opt out of
# documentation-only commits because GH actions does not permit paths and paths-ignore.
pull_request:
branches: master
paths:
- "build-bin/**"
- "docker/**"
- "webflux6-micrometer/**"
- ".github/workflows/test-webflux6-micrometer.yaml"
- "parent-pom.xml"

jobs:
test:
runs-on: ubuntu-22.04 # newest available distribution, aka jellyfish
steps:
- name: Checkout Repository
uses: actions/checkout@v4
with:
fetch-depth: 1
- name: Cache local Maven repository
uses: actions/cache@v3
with:
path: ./m2repository # Shared with the Docker build context via .dockerignore
key: ${{ runner.os }}-webflux6-micrometer-maven-${{ hashFiles('parent-pom.xml', 'webflux6-micrometer/pom.xml') }}
restore-keys: ${{ runner.os }}-webflux6-micrometer-maven-
# Don't attempt to cache Docker. Sensitive information can be stolen
# via forks, and login session ends up in ~/.docker. This is ok because
# we publish DOCKER_PARENT_IMAGE to ghcr.io, hence local to the runner.
- name: Test webflux6-micrometer
run: |
build-bin/configure_test webflux6-micrometer &&
build-bin/test webflux6-micrometer
4 changes: 4 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,10 @@ Here are the example projects you can try:
* Trace Instrumentation: [WebFlux Server](https://github.com/spring-cloud/spring-cloud-sleuth/blob/2.2.x/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/web/TraceWebFilter.java), [WebFlux Client](https://github.com/spring-cloud/spring-cloud-sleuth/blob/2.2.x/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/web/client/TraceWebClientBeanPostProcessor.java), [Reactor Context](https://github.com/spring-cloud/spring-cloud-sleuth/blob/2.2.x/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/reactor/ScopePassingSpanSubscriber.java), [SLF4J](https://github.com/openzipkin/brave/tree/master/context/slf4j)
* Trace Configuration: [Spring Cloud Sleuth](https://github.com/spring-cloud/spring-cloud-sleuth/tree/2.2.x/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/autoconfig) [Properties](webflux5-sleuth/src/main/resources/application.properties)

* [webflux6-micrometer](webflux6-micrometer) `BRAVE_EXAMPLE=webflux6-micrometer docker-compose up`
* Runtime: Spring 6, Reactor Netty, Spring Boot 3, Micrometer, Log4J 2, JRE 21
* Trace Configuration: [Spring Boot Actuator](https://github.com/spring-projects/spring-boot/blob/3.2.x/spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/tracing/TracingProperties.java)
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

normally I add a 'Trace Instrumentation' section with links as you can see above, but this time, I have no idea where they are! Also, I don't see any canonical page on properties in docs, so I'm referencing the java type directly.


* [webmvc25-jetty](webmvc25-jetty) `BRAVE_EXAMPLE=webmvc25-jetty docker-compose up`
* Runtime: Spring 2.5, Apache HttpClient 4.3, Servlet 2.5, Jetty 7.6, Log4J 1.2, JRE 6
* Trace Instrumentation: [Servlet](https://github.com/openzipkin/brave/tree/master/instrumentation/servlet), [Spring MVC](https://github.com/openzipkin/brave/tree/master/instrumentation/spring-webmvc), [Apache HttpClient](https://github.com/openzipkin/brave/tree/master/instrumentation/httpclient), [Log4J 1.2](https://github.com/openzipkin/brave/tree/master/context/log4j12)
Expand Down
8 changes: 8 additions & 0 deletions build-bin/docker/docker_args
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,14 @@ if [ -n "${DOCKER_TARGET}" ]; then
docker_args="${docker_args} --target ${DOCKER_TARGET}"
fi

# When non-empty, becomes the layer that builds the maven projects.
# e.g. ghcr.io/openzipkin/java:11.0.22_p7
#
# This must include maven and a full JDK.
if [ -n "${DOCKER_BUILD_IMAGE}" ]; then
docker_args="${docker_args} --build-arg docker_build_image=${DOCKER_BUILD_IMAGE}"
fi

# When non-empty, becomes the base layer including tag appropriate for the image being built.
# e.g. ghcr.io/openzipkin/java:21.0.2_p13-jre
#
Expand Down
8 changes: 7 additions & 1 deletion build-bin/docker_args
Original file line number Diff line number Diff line change
Expand Up @@ -14,30 +14,36 @@ DOCKER_ARCHS="amd64 arm64"

case "${JRE_VERSION}" in
6 )
DOCKER_BUILD_IMAGE=ghcr.io/openzipkin/java:11.0.22_p7
DOCKER_PARENT_IMAGE=ghcr.io/openzipkin/java:1.6.0-119
# single arch image
DOCKER_ARCHS=amd64
;;
7 )
DOCKER_BUILD_IMAGE=ghcr.io/openzipkin/java:11.0.22_p7
DOCKER_PARENT_IMAGE=ghcr.io/openzipkin/java:1.7.0_285
# single arch image
DOCKER_ARCHS=amd64
;;
8 )
DOCKER_BUILD_IMAGE=ghcr.io/openzipkin/java:11.0.22_p7
DOCKER_PARENT_IMAGE=ghcr.io/openzipkin/java:8.392.08-jre
;;
11 )
DOCKER_BUILD_IMAGE=ghcr.io/openzipkin/java:11.0.22_p7
DOCKER_PARENT_IMAGE=ghcr.io/openzipkin/java:11.0.22_p7-jre
;;
17 )
DOCKER_BUILD_IMAGE=ghcr.io/openzipkin/java:21.0.2_p13
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

had to parameterize this as spring boot requires minimal JRE 17.. the first project to require this.

DOCKER_PARENT_IMAGE=ghcr.io/openzipkin/java:17.0.10_p7-jre
;;
21 )
DOCKER_BUILD_IMAGE=ghcr.io/openzipkin/java:21.0.2_p13
DOCKER_PARENT_IMAGE=ghcr.io/openzipkin/java:21.0.2_p13-jre
;;
* )
echo "Invalid JRE_VERSION: ${JRE_VERSION}"
exit 1
esac

export DOCKER_PARENT_IMAGE DOCKER_ARCHS
export DOCKER_BUILD_IMAGE DOCKER_PARENT_IMAGE DOCKER_ARCHS
5 changes: 3 additions & 2 deletions docker/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@

# The image binaries this example builds are installed over
ARG docker_parent_image=ghcr.io/openzipkin/java:21.0.2_p13
## Use JDK 11 to build projects, as that can still compile Java 6
ARG docker_build_image=ghcr.io/openzipkin/java:11.0.22_p7

# We copy files from the context into a scratch container first to avoid a problem where docker and
# docker-compose don't share layer hashes https://github.com/docker/compose/issues/883 normally.
Expand All @@ -11,8 +13,7 @@ FROM scratch as scratch

COPY . /code/

## Use JDK 11 to build projects, as that can still compile Java 6
FROM ghcr.io/openzipkin/java:11.0.22_p7 as install
FROM $docker_build_image as install

WORKDIR /code
COPY --from=scratch /code .
Expand Down
15 changes: 15 additions & 0 deletions webflux6-micrometer/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
## Tracing Example: Spring 6/Reactor Netty/Spring Boot 3/Micrometer/Log4J 2

Instead of servlet, this uses Spring Boot 3 to create a self-contained
application that runs Spring WebFlux 6 controllers.

* brave.example.Frontend and Backend: Rest controllers
* brave.example.AppAutoConfiguration: Sets up the WebClient used in the Frontend.

Application code doesn't show any tracing configuration because that's handled
by [Micrometer Tracing](https://docs.micrometer.io/tracing/reference/index.html),
configured by [Spring Boot](https://docs.spring.io/spring-boot/docs/3.2.2/reference/htmlsingle/#actuator.micrometer-tracing.tracer-implementations.brave-zipkin).

Micrometer Tracing has its own Tracer API that can bridge to Brave's with a
plugin. This allows users to mix Micrometer with native Brave instrumentation.
However, this example does not use any native Brave instrumentation.
91 changes: 91 additions & 0 deletions webflux6-micrometer/pom.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>io.zipkin.brave.example</groupId>
<artifactId>brave-example-parent</artifactId>
<version>1.0-SNAPSHOT</version>
<relativePath>../parent-pom.xml</relativePath>
</parent>

<artifactId>brave-example-webflux6-micrometer</artifactId>
<packaging>jar</packaging>

<name>brave-example-webflux6-micrometer</name>
<description>Tracing Example: Spring 6, Reactor Netty, Spring Boot 3, Micrometer, Log4J 2, JRE 21</description>

<properties>
<jre.version>21</jre.version>
<maven.compiler.release>17</maven.compiler.release>

<spring-boot.version>3.2.2</spring-boot.version>
<micrometer.version>1.2.2</micrometer.version>

<!-- pinned to old brave until this commit is released
https://github.com/micrometer-metrics/tracing/commit/d11d8039c73d901e44197b87103e66c392b6d7a8 -->
<brave.version>5.17.1</brave.version>
<zipkin-reporter.version>2.17.2</zipkin-reporter.version>
</properties>

<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>${spring-boot.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>

<dependencies>
<!-- Configures Spring Boot with WebFlux SLF4J logging -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-webflux</artifactId>
</dependency>
<!-- Adds /actuator/health endpoint we re-map to /health used by our Docker HEALTHCHECK -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
<version>${spring-boot.version}</version>
</dependency>

<!-- micrometer-tracing-bridge-brave configures instrumentation including what's in Brave and their own. -->
<dependency>
<groupId>io.micrometer</groupId>
<artifactId>micrometer-tracing-bridge-brave</artifactId>
<version>${micrometer.version}</version>
</dependency>
<dependency>
<groupId>io.zipkin.reporter2</groupId>
<artifactId>zipkin-reporter-brave</artifactId>
<version>${zipkin-reporter.version}</version>
</dependency>
</dependencies>

<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>
</executions>
<configuration>
<!-- This can be overridden to brave.example.Frontend also -->
<mainClass>brave.example.Backend</mainClass>
<classifier>exec</classifier>
<executable>true</executable>
</configuration>
</plugin>
</plugins>
</build>
</project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package brave.example;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.reactive.function.client.WebClient;

/** The application is simple, it only uses WebFlux. */
// This type makes support easier as forks can make a diff off a working AutoConfiguration type */
@Configuration
public class AppAutoConfiguration {
@Bean WebClient.Builder webClientBuilder() {
return WebClient.builder();
}
}
30 changes: 30 additions & 0 deletions webflux6-micrometer/src/main/java/brave/example/Backend.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package brave.example;

import java.time.LocalDate;
import java.util.Optional;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestHeader;
import org.springframework.web.bind.annotation.RestController;
import reactor.core.publisher.Mono;

@EnableAutoConfiguration
@RestController
public class Backend {

@GetMapping("/api")
public Mono<String> printDate(@RequestHeader("user_name") Optional<String> username) {
return Mono.fromSupplier(() -> {
String date = LocalDate.now().toString();
return username.map(u -> date + " " + u).orElse(date);
});
}

public static void main(String[] args) {
SpringApplication.run(Backend.class,
"--spring.application.name=backend",
"--server.port=9000"
);
}
}
32 changes: 32 additions & 0 deletions webflux6-micrometer/src/main/java/brave/example/Frontend.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
package brave.example;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.reactive.function.client.WebClient;
import reactor.core.publisher.Mono;

@EnableAutoConfiguration
@RestController
public class Frontend {
final WebClient webClient;

@Autowired Frontend(WebClient.Builder webClientBuilder,
@Value("${backend.endpoint:http://127.0.0.1:9000/api}") String backendEndpoint) {
this.webClient = webClientBuilder.baseUrl(backendEndpoint).build();
}

@GetMapping("/") public Mono<String> callBackend() {
return webClient.get().uri("").retrieve().bodyToMono(String.class);
}

public static void main(String[] args) {
SpringApplication.run(Frontend.class,
"--spring.application.name=frontend",
"--server.port=8081"
);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
brave.example.AppAutoConfiguration
Loading
Loading