Spring Sleuth stuck sending 10 percent of request to Zipkin - spring-cloud

By default Spring Sleuth only sends 10% of requests to Zipkin. By setting spring.sleuth.sampler.percentage you can increase the percentage. Unfortunately it is stuck at 10% regardless of what value I set it to. I have tried 1.0, 0.5, 1, 100.
Output from /env
"spring.sleuth.sampler.percentage": {
"value": 1,
"origin": "class path resource [application.yml]:77:19"
}
Regardless of the value, when I make multiple requests, only 10% make it to Zipkin.
We are using version Finchley.M8 of Spring Cloud and 2.0.0.RELEASE of Spring Boot.
Below are relevant POM settings.
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.0.0.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version>
<spring-cloud.version>Finchley.M8</spring-cloud.version>
</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>
</dependencies>
</dependencyManagement>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-zipkin</artifactId>
</dependency>
Could this be a bug?

Ok we found the problem and also a work around.
It looks like all the documentation out there is wrong, at least for the version of Spring Cloud Sleuth we are using. The correct property is not spring.sleuth.sampler.percentage. The correct property is spring.sleuth.sampler.probability
And here is a workaround we found right before noticing that the property was wrong.
#Bean
public Sampler alwaysSampler() {
return Sampler.ALWAYS_SAMPLE;
}
Here are some official documentation from Spring Cloud that contain the wrong property.
https://cloud.spring.io/spring-cloud-static/spring-cloud-sleuth/2.0.0.M5/single/spring-cloud-sleuth.html
https://cloud.spring.io/spring-cloud-sleuth/single/spring-cloud-sleuth.html
Here is the source code that is being used and it is using probability not percentage.
https://github.com/spring-cloud/spring-cloud-sleuth/blob/master/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/sampler/SamplerProperties.java

Related

Working example of Spring boot reactive and EventSource

I'm trying to have a working spring boot with reactive mongodb and EventSource.
However, I'm facing issues with the repetitive reopening of the connection because it's closed by the server. I even have some doubt if this could really work since I didn't find any working example with a reactive db and Event source...
Could you please point me to a working example or tell me what's wrong with my code?
Here the main parts of the code:
pom.xml
<properties>
<java.version>1.8</java.version>
<junit-jupiter.version>5.3.2</junit-jupiter.version>
</properties>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.3.5.RELEASE</version>
</parent>
<dependencies>
<!-- webflux reactive -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-webflux</artifactId>
</dependency>
<!-- thymeleaf -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-mongodb-reactive</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
</dependency>
<!-- exclude junit 4, prefer junit 5 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
</exclusion>
</exclusions>
</dependency>
<!-- junit 5 -->
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-engine</artifactId>
<version>${junit-jupiter.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
</dependencies>
As you see in the pom, I'm using the embedded tomcat (I already tried with Netty, the default spring boot server...).
Also, I'm deploying the app to any remote server but just trying on my local (windows 10).
Web:
let source = new EventSource("/comment/stream");
source.addEventListener("message", function (event) {
// These events are JSON, so parsing and DOM fiddling are needed
var comment = JSON.parse(event.data);
console.log(comment );
});
source.addEventListener("error", function (event) {
console.log("error", event);
this.close();
});
RestController:
#RestController
public class CommentController {
#Autowired
private CommentRepository commentRepository;
#PostMapping(path = "/comment")
public Mono<Comment> comment(#RequestBody Comment comment) {
return this.commentRepository.save(comment);
}
#GetMapping(path = "/comment/stream", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
public Flux<Comment> feed() {
return this.commentRepository.findAll();
}
}
DB Repository:
#Repository
public interface CommentRepository extends ReactiveSortingRepository<Comment, String> {
Flux<Comment> findAll();
}
Again, the web client that uses EventSource, keeps reconnecting every second because the connection is closed by the server.
Thank you!
Im not really sure, you are giving us too little information as to why your connection is closing. No logs, and you are not disclosing anything about where it being deployed.
i will only answer this question based on personal experience. I deployed an application to heroku that uses event streams and they have a proxy/loadbalancer infront of every application that will kill any connection that does not send anything after up to 60 sec.
As mentioned here Why are event sources closed after 30-60 sec it confirmes what i have been noticing.
To work around this you can if using websockets implement ping/pong messages or if using ServerSentEvents as i did, i implemented keep alive messages.
.GET("", accept(TEXT_EVENT_STREAM), request -> ok()
.contentType(TEXT_EVENT_STREAM)
.header("Cache-Control", "no-transform")
.body(Flux.merge(myHandler.getEvents()),
Flux.interval(Duration.ofSeconds(15))
.map(aLong -> ServerSentEvent.builder()
.comment("keep alive")
.build())),
new ParameterizedTypeReference<List<MyClass>>() {}))
I have taken this code snippet from one of my projects. Here you can see that i merge with my current stream a flux that at given intervals (15 sec) will emit a ServerSentEvent with only a keep alive comment. Since it is a comment it will get ignored by the client.
Just need to mention, the regular stream myHandler.getEvents returns data wrapped in ServerSentEvents.

#RefreshScope and /refresh not working

I have tried to implement spring external configurations using Config Server. It is working fine for the very first time when the application is started but any changes to the properties file are not being reflected. I tried to use /refresh endpoint to refresh my properties on the fly but it doesn't seem to be working. Any help on this would be greatly helpful.
I tried POSTing to localhost:8080/refresh but getting a 404 Error response.
Below is the code of my application class
#SpringBootApplication
public class Config1Application {
public static void main(String[] args) {
SpringApplication.run(Config1Application.class, args);
}
}
#RestController
#RefreshScope
class MessageRestController {
#Value("${message:Hello default}")
private String message;
#RequestMapping("/message")
String getMessage() {
return this.message;
}
}
and POM file is
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.0.0.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version>
<spring-cloud.version>Finchley.M8</spring-cloud.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-config</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</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>
<snapshots>
<enabled>false</enabled>
</snapshots>
</repository>
</repositories>
and bootstrap.properties
spring.application.name=xxx
spring.cloud.config.uri=https://xxxxxx.com
management.security.enabled=false
endpoints.actuator.enabled=true
The endpoint is now /actuator/refresh for Spring 2 and greater
From the comments:
You do need to have the management.endpoints.web.exposure.include=refresh set in the bootstrap.properties/bootstrap.yml
Note: If you're new to Spring-Cloud and not quite sure of what all keywords can go in web.exposure you can set it to * (management.endpoints.web.exposure.include=*) to have all exposed and you can get to know the endpoints and their restrictions later.
It worked for me after adding the property "management.endpoints.web.exposure.include=*" in bootstrap.properties and changing the url to /actuator/refresh for spring version above 2.0.0
For spring version 1.0.5 url is /refresh
For YAML files, the property's value needs to be wrapped inside double quotes :
# Spring Boot Actuator
management:
endpoints:
web:
exposure:
include: "*"
Note : Ensure you use the right endpoints keyword (with 's') for this property as long as it exists for another property without 's' : "management.endpoint.health.... " .
Note: - It's a POST request (not GET)
I've posted the solution here
[https://stackoverflow.com/a/74465108/2171938][1]
If you have issues with accepting formurlencoded in SPRING 2.0>, use :
curl -H "Content-Type: application/json" -d {} http://localhost:port/actuator/refresh
instead of:
curl -d {} http://localhost:port/refresh
which was accepted in SPRING 1.*

Spring cloud gateway hystrix not working

I am having issues getting hystrix to work with my route. things like re-write paths and load balancing are working but for some reason hystrix never trips. I am setting my timeouts very low and have a delay in a downstream service. Is there anything special you need to do to get hystrix working?
I am using spring-cloud-gateway with eureka and spring-cloud-config. Also, is there a way to debug when a route is not working? Like a log setting to see what is happening?
Here is my route:
spring:
cloud:
gateway:
routes:
# =====================================
- id: main-service
uri: lbl://main-service
predicates:
- Path=/main-service**
filters:
- Hystrix=mainservice
Here is my pom
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.0.0.M7</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-
8</project.reporting.outputEncoding>
<java.version>1.8</java.version>
<spring-cloud.version>Finchley.M5</spring-cloud.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-config</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-eureka</artifactId>
<version>1.4.0.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-hystrix</artifactId>
<version>2.0.0.M2</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</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>
Here is my Application class:
#EnableDiscoveryClient
#EnableHystrix
#SpringBootApplication
public class GatewayApplication {
public static void main(String[] args) {
SpringApplication.run(GatewayApplication.class, args);
}
}
The only other class in the jar is this:
#Configuration
public class GatewayConfiguration {
#Bean
public DiscoveryClientRouteDefinitionLocator
discoveryClientRouteLocator(DiscoveryClient discoveryClient) {
return new DiscoveryClientRouteDefinitionLocator(discoveryClient);
}
}
I figured out the issue. It seems that if you add eureka discovery then it automatically add routes that match all the spring.application.names returned by your eureka server and these have the same order as the ones I defined using application name as the predicate. I was able to fix this by setting the order for my route to -1.
Not sure if there is a better way to do this but at least I know hystrix is working.
Thanks
Maybe you should use this dependency:
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
</dependency>

SpringCloud Eureka - simple client doesnt register

I have an Eureka Server where I want to register a very basic SpringBoot service. Unfortunately the service doesnt register although I tried to follow all the articles I could find.
Moreover when I check description of the DiscoveryClient (that gets autowired), I see "Spring Cloud No-op DiscoveryClient" which suggests (as per NoopDiscoveryClient.java source) that Eureka client library isnt found.
In pom I have
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-netflix-eureka-client</artifactId>
</dependency>
which if I am right should make sure that proper netflix libraries are in place. #EnableEurekaClient annotation is present. No errors on the console when starting the client, nothing interesting in the Eureka Server console logs.
This is the configuration from the application.yml:
eureka:
client:
serviceUrl:
defaultZone: ${vcap.services.eureka-service.credentials.uri:http://127.0.0.1:8761}/eureka/
Any suggestions are really welcomed as I am running out of ideas :)
http://start.spring.io is your friend. You need to use the starters.
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>Brixton.M5</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
and
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-eureka</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
</dependencies>
Except #spencergibb's answer, in my case it also require <spring-cloud.version> inside the <properties>:
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version>
<spring-cloud.version>Greenwich.M3</spring-cloud.version>
</properties>

How can I specify the spring-data-mongodb version using spring-boot?

I want to use the latest version of spring-data-mongodb, in order to use the full text search feature, but I don't know how I can specify this using the spring-boot-starter-data-mongodb dependence.
You can read here: maven repository that the spring-data-mongodb version is not specify.
This is my pom file:
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.1.6.RELEASE</version>
<relativePath /> <!-- lookup parent from repository -->
</parent>
<dependencies>
<dependency>
<groupId>org.apache.tomcat.embed</groupId>
<artifactId>tomcat-embed-jasper</artifactId>
<scope>provided</scope>
</dependency>
<!-- Spring Boot -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- Spring Boot Rest -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-rest</artifactId>
</dependency>
<!-- Spring Boot Test -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<!-- Spring MongoDB integration -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-mongodb</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-freemarker</artifactId>
</dependency>
Spring Boot defines all its dependencies and dependency versions in the spring-boot-dependencies project. This project only contains a pom with only dependencies and versions as properties.
Spring Data releases all of its compatible releases in a so called release train and this makes sure that all dependencies of that version will work together.
When you take a closer look a the pom you will see a maven property named spring-data-releasetrain.version and for the upcoming Spring Boot 1.2 it points to the latest release train version Evans-RELEASE. The 1.1.7 version points to the previous version Dijkstra-SR4. I would suggest an upgrade from 1.1.6 to 1.1.7 just in case.
You're project already has the spring-boot-starter-parent project as its parent so in theory upgrading the Spring Data versions should be as easy as overriding the specified property.
<properties>
<spring-data-releasetrain.version>Evans-RELEASE</spring-data-releasetrain.version>
</properties>
As mentioned earlier the use of the release train is preferred as this will make sure you get all the compatible versions.
You can find that mongodb dependency in the parent project pom file
/../.m2/repository/org/springframework/boot/spring-boot-dependencies/2.3.0.RELEASE/spring-boot-dependencies-2.3.0.RELEASE.pom
That file defines all the dependency version for other libs SpringBoot use
<properties>
<activemq.version>5.15.12</activemq.version>
<antlr2.version>2.7.7</antlr2.version>
...
<mongodb.version>4.0.3</mongodb.version>
...
</properties>
So if you want to use different version for mongodb, define a properties in your pom file to override the default one like (I think this will only work if you use spring-boot-starter-parent as parent )
<properties>
<mongodb.version>3.11.2</mongodb.version>
</properties>
Answer by #sendon1982 worked for me. Here is an example of my POM.XML. I am adding it as an answer here because I could not paste in my pom file as a comment to sendon1982 answer...
<?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.3.3.RELEASE</version>
<relativePath/>
</parent>
<groupId>test.barry</groupId>
<artifactId>test</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>test</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>1.8</java.version>
<start-class>test.barry.Main</start-class>
<mongodb.version>4.1.0</mongodb.version>
</properties>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-mongodb</artifactId>
<version>2.3.3.RELEASE</version>
</dependency>
<dependency>
<groupId>org.mongodb</groupId>
<artifactId>mongodb-driver-sync</artifactId>
<version>4.1.0</version>
</dependency>
</dependencies>
</project>