Context:
I have to rewrite a parent library from Java EE to a more modern one in Spring Boot. For example, it has got some deprecated dependencies and CDI parts, Microprofiles that are not Spring compatible.
Problem:
I have hardly used OpenTelemetry and OpenTracing. I understand only the high-level concepts but I have never coded such things. I have trouble rewriting a part that involves OpenTracing. I know OpenTracing is deprecated and I should use OpenTelemetry. There is a dependency called 'Tracer Resolver'.
Its description from Github: Resolver API for OpenTracing Tracer implementations. NOTE: The Tracer Resolver mechanism is only intended to be used at application startup/initialization time. This responsibility should be handled by the application, possibly using some runtime-specific support (e.g. providing a Tracer #Bean in Spring Boot, or a CDI producer). Framework integrations used to instrument-specific technologies should not use this library, but should allow a Tracer to be injected instead, with fallback to the GlobalTracer.
In the code the only OpenTracing dependency:
<dependency>
<groupId>io.opentracing.contrib</groupId>
<artifactId>opentracing-tracerresolver</artifactId>
<version>0.1.8</version>
</dependency>
And I found the usage in the code as:
#ApplicationScoped
public class OpenTraceResolver {
#Inject
private Instance<Tracer> tracerInstance;
...
or
#Provider
public class OpenTraceErrorResponseFilter implements ContainerResponseFilter {
#Inject
private Tracer configuredTracer;
...
How should I do the same with OpenTelemetry? Is there a way to use it in such a simple way?
Thank you for your help!
First of all Spring uses Spring Cloud Sleuth project for implementing distributed tracing and you need add it to your project before configure open telemetry. By default Spring Cloud Sleuth uses OpenZipkin Brave by default which is different from OpenTelemetry (Otel) implementation.
To configure you project to use OpenTelemetry you need to decide if you will go with auto-instrumentation which is easier (using agents on not) or with manual instrumentation, with gives you more flexibility.
With auto-instrumentation you just need change your pom.xml and configure an exporter backend in your application.yaml and it will automatically generate and export the traces for you.
application.yaml
spring.sleuth.otel.exporter.otlp.endpoint=[URL TO YOUR OTEL BACKEND]
you can send the traces do zipkin, grafana tempo and etc..
pom.xml
<properties>
<spring-cloud.version>2021.0.0-M2</spring-cloud.version>
<spring-cloud-sleuth-otel.version>1.1.0-M3</spring-cloud-sleuth-otel.version>
<opentelemetry-exporter-otlp>1.7.0</opentelemetry-exporter-otlp>
<grpc-netty-shaded>1.41.0</grpc-netty-shaded>
</properties>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${spring-cloud.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<!-- Spring Cloud Sleuth OTel requires a Spring Cloud Sleuth OTel BOM -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-sleuth-otel-dependencies</artifactId>
<version>${spring-cloud-sleuth-otel.version}</version>
<scope>import</scope>
<type>pom</type>
</dependency>
</dependencies>
</dependencyManagement>
<!-- Sleuth with Brave tracer implementation -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-sleuth</artifactId>
<exclusions>
<!-- Exclude Brave (the default) -->
<exclusion>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-sleuth-brave</artifactId>
</exclusion>
</exclusions>
</dependency>
<!-- Add OpenTelemetry tracer -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-sleuth-otel-autoconfigure</artifactId>
</dependency>
<!-- https://mvnrepository.com/artifact/io.opentelemetry/opentelemetry-exporter-otlp -->
<dependency>
<groupId>io.opentelemetry</groupId>
<artifactId>opentelemetry-exporter-otlp</artifactId>
<version>${opentelemetry-exporter-otlp}</version>
</dependency>
<!-- https://mvnrepository.com/artifact/io.grpc/grpc-netty -->
<dependency>
<groupId>io.grpc</groupId>
<artifactId>grpc-netty-shaded</artifactId>
<version>${grpc-netty-shaded}</version>
</dependency>
<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>
More references
https://opentelemetry.io/docs/instrumentation/java/
https://github.com/spring-projects-experimental/spring-cloud-sleuth-otel
Related
I'm trying to use Azure Monitor OpenTelemetry Exporter client library for Java to export all traces/spans from Spring Cloud Sleuth to Azure Monitor. This integration seems to only work with the newest version of Spring Cloud Sleuth after the recent dependency version updates.
However instead of using azureMonitorExporter.export(spanData) manually, I would like to export all traces/spans automatically for the whole application by just adding a configuration for Azure exporter. This could then easily be added to a new project.
I don't have much experience using Spring/Sleuth/OpenTelemetry, but AzureMonitorExporter implements SpanExporter, so I thought one option could be to create a configuration class that contains the following.
#Bean
public SpanExporter exporter() {
return new AzureMonitorExporterBuilder()
.instrumentationKey("{KEY}")
.buildExporter();
};
And then it could be used in the main class using:
#Autowired
SpanExporter exporter;
However I'm not sure if this is the right way or how to continue from here to actually get the exporter to start exporting traces/spans automatically to Azure monitor.
My pom.xml looks like this:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.4.2-SNAPSHOT</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.example</groupId>
<artifactId>trace-demo-5-updated</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>trace-demo-5-updated</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>11</java.version>
<spring-cloud.version>2020.0.0-SNAPSHOT</spring-cloud.version>
</properties>
<dependencies>
<!-- Sleuth with Brave tracer implementation -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-sleuth</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.azure</groupId>
<artifactId>opentelemetry-exporters-azuremonitor</artifactId>
<version>1.0.0-beta.1</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web-services</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-sleuth-otel</artifactId>
<version>3.0.0-M6</version>
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${spring-cloud.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
<repositories>
<repository>
<id>spring-milestones</id>
<name>Spring Milestones</name>
<url>https://repo.spring.io/milestone</url>
</repository>
<repository>
<id>spring-snapshots</id>
<name>Spring Snapshots</name>
<url>https://repo.spring.io/snapshot</url>
<snapshots>
<enabled>true</enabled>
</snapshots>
</repository>
</repositories>
<pluginRepositories>
<pluginRepository>
<id>spring-milestones</id>
<name>Spring Milestones</name>
<url>https://repo.spring.io/milestone</url>
</pluginRepository>
<pluginRepository>
<id>spring-snapshots</id>
<name>Spring Snapshots</name>
<url>https://repo.spring.io/snapshot</url>
<snapshots>
<enabled>true</enabled>
</snapshots>
</pluginRepository>
</pluginRepositories>
Update (2020-01-26):
With today's release of Spring Cloud Sleuth OTel (spring-cloud-sleuth-otel:1.0.0-M3) and The OTel upgrade in the Azure SDK, your original issue should disappear.
Original Answer
(TL;DR: last paragraph)
The Sleuth 3.0 Migration Guide can help you out a lot here. Sleuth supports two tracing systems Brave (default) and OpenTelemetry (incubator).
In order to use OpenTelemetry, you need to remove Brave (just exclude spring-cloud-sleuth-brave) and add OpenTelemetry (spring-cloud-sleuth-otel-autoconfigure with spring-cloud-sleuth-otel-dependencies). See the docs I linked.
After you do this, your SpanExporter should be used, here's a pom.xml I created based on yours. Btw, adding a sample project (e.g.: in a GitHub repo) could help a lot for everyone who is trying to help so that they don't need to create one themselves.
Unfortunately, this still won't work, you will still face with this exception at startup:
Caused by: java.lang.ClassNotFoundException: io.opentelemetry.common.AttributeValue
This is because opentelemetry-exporters-azuremonitor:1.0.0-beta.1 depends on OpenTelemetry 0.8.0 while the latest spring-cloud-sleuth-otel (1.0.0-M2, we released it today) is using the latest OpenTelemetry (0.13.1). Also, OpenTelemetry introduced breaking changes between minor versions, e.g.: the AttributeValue class was removed in OpenTelemetry 0.9.1.
Sleuth supports OpenTelemetry since Sleuth 3.0.0-M5, The OpenTelemetry version was 0.10 back then so there is no Sleuth version available that would support an OpenTelemetry version as old as opentelemetry-exporters-azuremonitor:1.0.0-beta.1 needs.
So the solution would be fixing your pom.xml and opentelemetry-exporters-azuremonitor supporting the latest OpenTelemetry.
In pom.xml I have a dependency management section.
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${spring-cloud.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
And custom repository that overrides path to central repo.maven. (Note: I know it's not a best practice but it's a project need.).
<repositories>
<repository>
<id>central</id>
<name>central</name>
<url>https://SOME_PATH</url>
</repository>
</repositories>
So I expect that all dependency will be download from the custom repository. But all dependency from spring-cloud-dependencies (inside are a lot of dependency with scope import also) downloaded from maven central.
As a workaround, we setup mirror in settings.xml but I want to knot why repository settings don't work for this dependency.
Also, I found a strange behavior if I add a second repository with some unexisting id like 'import' or 'other' those dependency will be downloaded from the custom repository.
I am using confluent and according to the official document, I only have to configure below in pom.xml like this:
<repositories>
<repository>
<id>confluent</id>
<url>http://packages.confluent.io/maven/</url>
</repository>
<!-- further repository entries here -->
</repositories>
<dependencies>
<dependency>
<groupId>org.apache.kafka</groupId>
<artifactId>kafka_2.11</artifactId>
<!-- For CP 3.1.0 -->
<version>0.10.1.0-cp1</version>
</dependency>
</dependencies>
But seems kafka_2.11 with version 0.10.1.0-cp1 does not exits.
The website http://packages.confluent.io/maven/ cannot be reached too.
How can I get it?
I am using below maven dependancy its working fine for me :
<dependency>
<groupId>org.apache.kafka</groupId>
<artifactId>connect-api</artifactId>
<version>0.10.2.0-cp1</version>
</dependency>
<repository>
<id>confluent</id>
<name>Confluent</name>
<url>http://packages.confluent.io/maven/</url>
</repository>
Hopefully this will help
import org.apache.camel.builder.RouteBuilder;
import org.apache.camel.component.infinispan.InfinispanConstants;
import org.apache.camel.component.jackson.JacksonDataFormat;
import org.apache.camel.model.dataformat.JsonLibrary;
import uk.co.sammy.model.Collection;
public class InfinispanRoute extends RouteBuilder {
private JacksonDataFormat json = new JacksonDataFormat(Collection.class);
#Override
public void configure() throws Exception {
from("file:src/data?noop=true&include=.*.json")
.choice()
.when()
.jsonpath("$..CustInfo[?(#.firstName == 'Sammy')]").unmarshal(json)
.log("Got customer data for ${body.custInfo.firstName}")
.setHeader(InfinispanConstants.OPERATION, constant(InfinispanConstants.PUT_IF_ABSENT))
.setHeader(InfinispanConstants.KEY, simple("${body.custInfo.firstName}"))
.to("infinispan://localhost")
.marshal().json(JsonLibrary.Jackson)
.to("activemq:queue:incomingApplication", "activemq:queue:customerDetails");
from("activemq:queue:incomingApplication")
.setHeader(InfinispanConstants.OPERATION, constant(InfinispanConstants.GET))
.setHeader(InfinispanConstants.KEY, constant("${body.custInfo.firstName}"))
.to("infinispan://foo?cacheName=localCache")
.setBody(simple("${header.CamelInfinispanOperationResult}"))
.to("activemq:output");
}
}
My pom.xml looks like the below
<properties>
<activemq.version>5.14.1</activemq.version>
<camel.version>2.18.0</camel.version>
<infinispan.version>8.3.0.Final-redhat-1</infinispan.version>
<camel-jbossdatagrid.version>6.6.1.Final-redhat-1</camel-jbossdatagrid.version>
</properties>
<dependencies>
<dependency>
<groupId>org.apache.camel</groupId>
<artifactId>camel-core</artifactId>
<version>${camel.version}</version>
</dependency>
<dependency>
<groupId>org.apache.camel</groupId>
<artifactId>camel-jackson</artifactId>
<version>${camel.version}</version>
</dependency>
<dependency>
<groupId>org.apache.camel</groupId>
<artifactId>camel-jsonpath</artifactId>
<version>${camel.version}</version>
</dependency>
<dependency>
<groupId>org.infinispan</groupId>
<artifactId>infinispan-embedded</artifactId>
<version>${infinispan.version}</version>
</dependency>
<dependency>
<groupId>org.apache.camel</groupId>
<artifactId>camel-jbossdatagrid</artifactId>
<version>${camel-jbossdatagrid.version}</version>
</dependency>
<!--ActiveMQ -->
<dependency>
<groupId>org.apache.activemq</groupId>
<artifactId>activemq-camel</artifactId>
<version>${activemq.version}</version>
</dependency>
<dependency>
<groupId>org.apache.activemq</groupId>
<artifactId>activemq-pool</artifactId>
<version>${activemq.version}</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.16.10</version>
</dependency>
<dependency>
<groupId>org.ow2.asm</groupId>
<artifactId>asm-all</artifactId>
<version>5.1</version>
</dependency>
</dependencies>
<repositories>
<repository>
<id>fuse-release</id>
<name>jboss Release Repository</name>
<releases>
<updatePolicy>never</updatePolicy>
</releases>
<snapshots>
<enabled>false</enabled>
</snapshots>
<url>http://repo.fusesource.com/nexus/content/groups/public/</url>
</repository>
</repositories>
</project>
I have tried for three days to get this simple sample code to work with Infinispan using the REdhat getting started guide and downloaded the quickstart zip to run that but still won't work! I keep getting the error "cannot connect to foo:11222" or "pool not open" by Spring JMS then a warning about mixing Uber and Jars version. I started off using ehcache which was a pain to implement because of limited simple examples that show how to store, retrieve and clear a cache from rest calls etc. Now, I need this to work so I can easily migrate it to Openshift but, still won't work! Every time I restart the project, I get different errors. Please any help to step by step setup Infinispan to work using my above code will be SERIOUSLY appreciated. Thanks guys!
P.S: I've read through the Redhat data grid getting started page and followed their instructions before doing this as my last resort!!!
Using the "infinispan://localhost" uri format will try to connect to an Infinispan server. To use an embedded cache, you should use something like "infinispan://?cacheName=localCache"
I see a few errors in the example you have provided:
1st route:
You should set the value you want to put in the cache with InfinispanConstants.VALUE
2nd route:
You should use the same cache uses by the first route (i.e. same cache name)
You should use simple to set InfinispanConstants.KEY
Is there a public Maven repository that contains spring-core 3 yet?
I can find 2.5.4 all day long but not 3. If there answer is yes, please include the location in the answer.
You can get the milestones and release candidates from Spring's Maven repository. The repository is difficult to browse, but the files are there, e.g. the spring-core 3.0.0.RC1 pom
Here is an example repository declaration and dependency:
<repositories>
<repository>
<id>springsource maven repo</id>
<url>http://maven.springframework.org/milestone</url>
</repository>
</repositories>
...
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>3.0.0.RC1</version>
</dependency>
</dependencies>
Since the question was asked, the Spring Enterprise Bundle Repository has been put online and is easier to browse.
Browse by Library, and then by Spring Framework, and you'll find what you're looking for.
<repository>
<id>com.springsource.repository.bundles.release</id>
<name>SpringSource Enterprise Bundle Repository - SpringSource Bundle Releases</name>
<url>http://repository.springsource.com/maven/bundles/release</url>
</repository>
...
<dependency>
<groupId>org.springframework</groupId>
<artifactId>org.springframework.core</artifactId>
<version>3.0.2.RELEASE</version>
</dependency>