Exclude specific controllers from sleuth / brave to trace - spring-boot

we are using brave api in our spring boot application. We are able to trace all controllers and services. But issue is we are getting traces in some controllers which we do not want to trace like health check controller. Is there any way to specify this in controller as by default it is tracing all controllers.
I have tried using
spring:
application:
name: abc
sleuth:
enabled: "true"
reporter:
enabled: "true"
sampler:
probability: "1.0"
instrument:
web:
skipPattern: (^status* | ^Status* | *status*)
and
spring:
application:
name: abc
sleuth:
enabled: "true"
reporter:
enabled: "true"
sampler:
probability: "1.0"
web:
skipPattern: (^status* | ^Status* | *status*)
But it did not work. Status controller
#RestController
public class StatusController {
#Autowired
public StatusController() {
}
#RequestMapping(value = "/status", method = RequestMethod.GET)
public Boolean status() {
return true;
}
}
Please help.
Thanks

*status* is not a valid regex. Try just /status. You can check the https://github.com/spring-cloud/spring-cloud-sleuth/blob/v2.1.4.RELEASE/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/web/SleuthWebProperties.java#L34 for the default. Also, maybe it makes more sense to use the additionalSkipPattern property to append your custom values to existing ones.

Related

Spring - Thymeleaf - Hot reload of message files (localisation)

I'm a using spring boot (2.5.7) with the devtools dependency for hot reload. It works pretty well (including changes in fragments) but not for the localisation files (message_XX.properties under resources/lang). Every time I make a change there, I need to restart the server. Here is my application.yaml:
spring:
thymeleaf:
cache: false
mode: HTML
encoding: UTF-8
prefix: file:src/main/resources/templates/
web:
resources:
static-locations:
- file:src/main/resources/static/
cache:
period: 0
Some edits:
I use vscode and gradle 7
I redefined a MessageSource.
Any idea?
Thanks!
Forgot to reply earlier, in the end, I simply came back to:
spring:
thymeleaf:
cache: false
mode: HTML
encoding: UTF-8
cache:
period: 0
My LocaleConfig class:
#Configuration
public class LocaleConfig {
#Bean
public AcceptHeaderLocaleResolver localeResolver() {
final AcceptHeaderLocaleResolver resolver = new AcceptHeaderLocaleResolver();
resolver.setDefaultLocale(Locale.ENGLISH);
return resolver;
}
#Bean
public ResourceBundleMessageSource messageSource() {
final ResourceBundleMessageSource source = new ResourceBundleMessageSource();
source.setBasename("lang/message");
return source;
}
}
And then, I need two terminals, one with a continuous build from gradle and one with the spring boot bootRun task:
./gradlew compileJava --continuous
and
./gradlew bootRun
DISCLAIMER: it may happen that I need to stop and restart both as the new messages are sometimes not picked up.

Set Prefix to Spring Micrometer Merics using Statsd and Datadog

I'm trying to Implement Custom Metrics Integration for my App. Using the following setup
// DogStatsd Metrics Integration with MicroMeter
implementation group: 'io.micrometer', name: 'micrometer-registry-statsd', version: '1.7.2'
Custom Spring Configuration Added for the application
#Configuration
public class MetricConfiguration {
private final MeterRegistry meterRegistry;
#Value("${management.metrics.export.statsd.prefix}")
private String prefix;
#Autowired
public MetricConfiguration(MeterRegistry meterRegistry) {
this.meterRegistry = meterRegistry;
}
#Bean
public MeterRegistryCustomizer<MeterRegistry> metricsCommonTags() {
return registry -> registry.config().meterFilter(new MeterFilter() {
#Override
public Meter.Id map(Meter.Id id) {
if (!id.getName().startsWith(prefix)) {
return id.withName(prefix + "." + id.getName());
} else {
return id;
}
}
});
}
#Bean
public TimedAspect timedAspect() {
return new TimedAspect(meterRegistry);
}
}
YAML Configuration for Metrics
management:
metrics:
enable:
jvm: false
process: false
tomcat: false
system: false
logback: false
distribution:
slo:
http.server.requests: 50ms
percentiles-histogram:
http.server.requests: true
percentiles:
http.server.requests: 0.99
export:
statsd:
enabled: false
flavor: datadog
host: ${DD_AGENT_HOST}
port: 8125
prefix: ${spring.application.name}
endpoints:
enabled-by-default: true
web:
exposure:
include: "*"
endpoint:
metrics:
enabled: true
health:
enabled: true
show-components: "always"
show-details: "always"
Trying to set the prefix to all the custom metrics, but after setting the prefix the excluded metrics are breaking are started showing in the /actuator/metrics response.
The response looks like below:
{
names: [
"my-service.http.server.requests",
"my-service.jvm.buffer.count",
"my-service.jvm.buffer.memory.used",
"my-service.jvm.buffer.total.capacity",
"my-service.jvm.classes.loaded",
"my-service.jvm.classes.unloaded",
"my-service.jvm.gc.live.data.size",
"my-service.jvm.gc.max.data.size",
"my-service.jvm.gc.memory.allocated",
"my-service.logback.events",
"my-service.process.cpu.usage",
"my-service.process.files.max",
"my-service.process.files.open",
"my-service.process.start.time",
"my-service.process.uptime",
"my-service.system.cpu.count",
"my-service.system.cpu.usage",
"my-service.system.load.average.1m",
"my-service.tomcat.sessions.active.current",
"my-service.tomcat.sessions.active.max",
"my-service.tomcat.sessions.alive.max",
"my-service.tomcat.sessions.created",
"my-service.tomcat.sessions.expired",
"my-service.tomcat.sessions.rejected"
]
}

Properties with auto configure not working on spring cloud stream and rabbitmq

I have a config server with the properties and a microservice as consumer.
I've tried to configure maxAttempts to avoid retries on the consumer microservices, but it seems not to work.
I also define the bindings properties on config servers and them works fine. My consumer is listening and receive messages, but it tries 3 times and then crash.
This is my application.yml in my config server
server:
servlet:
contextPath: /cmsrsssitemap/v1
spring:
cloud:
stream:
bindings:
sitemap-main-output:
destination: sitemap-main
group: cms-microservices-v1
content-type: application/json
#consumer.concurrency: 2
test-job-output:
destination: test-job
group: cms-microservices-v1
content-type: application/json
rabbit:
bindings:
test-job-output:
consumer:
maxAttempts: 1
requeueRejected: false
autoBindDlq: true
#dlqTtl: 5000
#requeueRejected: false
#dlqDeadLetterExchange: dltexchange1
#republishToDlq: true
This is the application.yml in the producer side
server.servlet.contextPath: /cmsjmshandler/v1
spring:
cloud:
stream:
bindings:
sitemap-main-input:
destination: sitemap-main
content-type: application/json
test-job-input:
destination: test-job
group: cms-microservices-v1
content-type: application/json
And this is the lisener. It's throwing a NullPointer for testing purpose
#Component
public class TestJobListener {
#StreamListener(StreamProcessor.TEST_JOB)
public void testJobInput(#Payload String input) throws InterruptedException {
// Thread.sleep(3000);
System.out.println("########################### "+new Date() + " Mensaje Recibido");
throw new NullPointerException();
}
}
StreamProcesor.java
public interface StreamProcessor {
public static final String TEST_JOB = "test-job";
public static final String SITEMAP_MAIN = "sitemap-main";
#Input(StreamProcessor.TEST_JOB)
SubscribableChannel testJobOutputInput();
#Input(StreamProcessor.SITEMAP_MAIN)
SubscribableChannel processSitemapMain();
}
The goal of this it's making to move failed messages to DLQ, but it isn't work either
EDIT 1: Can't make it work. I've made changes according to Artem Bilan but it doesn't work either.
server:
servlet:
contextPath: /cmsrsssitemap/v1
spring:
cloud:
stream:
bindings:
test-job-output:
destination: test-job
group: cms-microservices-v1
content-type: application/json
consumer:
maxAttempts: 1
rabbit:
bindings:
test-job-output:
consumer:
requeueRejected: false
The maxAttempts is not a rabbit property. It is a core one.
There is a sample in the Docs on the matter: https://docs.spring.io/spring-cloud-stream/docs/Elmhurst.RELEASE/reference/htmlsingle/#spring-cloud-stream-overview-error-handling
spring.cloud.stream.bindings.input.consumer.max-attempts=1
spring.cloud.stream.rabbit.bindings.input.consumer.requeue-rejected=true
The problem was I put the wrong name on the StreamProcesor
#StreamListener(StreamProcessor.TEST_JOB)
StreamProcesor.TEST_JOB should be the channel name, nor destination. Updating my question.
Corrected SteamProcesor.java
StreamProcesor.java
public interface StreamProcessor {
public static final String TEST_JOB = "test-job-output";
public static final String SITEMAP_MAIN = "sitemap-main";
#Input(StreamProcessor.TEST_JOB)
SubscribableChannel testJobOutputInput();
#Input(StreamProcessor.SITEMAP_MAIN)
SubscribableChannel processSitemapMain();
}
I just tested it and it works fine with this (corrected) config for me. If you enable the actuator/env endpoint on the client and you can see the properties:
(I used input and a local file-based config server).

Spring Cloud Gateway API - Context-path on routes not working

I have setup context-path in application.yml
server:
port: 4177
max-http-header-size: 65536
tomcat.accesslog:
enabled: true
servlet:
context-path: /gb-integration
And I have configured some routes
#Bean
public RouteLocator routeLocator(RouteLocatorBuilder builder) {
final String sbl = "http://localhost:4178";
return builder.routes()
//gb-sbl-rest
.route("sbl", r -> r
.path("/sbl/**")
.filters(f -> f.rewritePath("/sbl/(?<segment>.*)", "/gb-sbl/${segment}"))
.uri(sbl)).build();
}
I want the API gateway to be reached using localhost:4177/gb-integration/sbl/**
However it is only working on localhost:4177/sbl/**
It seems my context-path is ignored.
Any ideas how I can get my context-path to work on all my routes?
You probably already figuered it out by your self, but here is what is working for me:
After reading the Spring Cloud documentation and having tryied many things on my own, I have eventually opted for a route by route configuration. In your case, it would look something like this:
.path("/gb-integration/sbl/**")
and repeat the same pattern for every route.
.path("/gb-integration/abc/**")
...
.path("/gb-integration/def/**")
You can actually see this in spring cloud documentation.
The spring clould documentation seems to be in progress. Hopefully, we shall find a better solution.
Detailing on #sendon1982 answer
If your service is exposed at localhost:8080/color/red and you want it to be accessible from gateway as localhost:9090/gateway/color/red, In the Path param of predicates, prepend the /gateway, and add StripPrefix as 1 in filters, which basically translates to
take the requested path which matches Path, strip/remove out the prefix paths till the number mentioned and route using given uri and the stripped path
my-app-gateway: /gateway
spring:
cloud:
gateway:
routes:
- id: color-service
uri: http://localhost:8080
predicates:
- Path=${my-app-gateway}/color/**
filters:
- StripPrefix=1
Using yaml file like this
spring:
cloud:
gateway:
routes:
- id: property-search-service-route
uri: http://localhost:4178
predicates:
- Path=/gb-integration/sbl/**
fixed :
application.yaml:
gateway:
discovery:
locator:
enabled: true
lower-case-service-id: true
filters:
# 去掉 /ierp/[serviceId] 进行转发
- StripPath=2
predicates:
- name: Path
# 路由匹配 /ierp/[serviceId]
# org.springframework.cloud.gateway.discovery.DiscoveryClientRouteDefinitionLocator#getRouteDefinitions
args[pattern]: "'/ierp/'+serviceId+'/**'"
filter:
#Component
public class StripPathGatewayFilterFactory extends
AbstractGatewayFilterFactory<StripPathGatewayFilterFactory.Config> {
/**
* Parts key.
*/
public static final String PARTS_KEY = "parts";
public StripPathGatewayFilterFactory() {
super(StripPathGatewayFilterFactory.Config.class);
}
#Override
public List<String> shortcutFieldOrder() {
return Arrays.asList(PARTS_KEY);
}
#Override
public GatewayFilter apply(Config config) {
return (exchange, chain) -> {
ServerHttpRequest request = exchange.getRequest();
ServerWebExchangeUtils.addOriginalRequestUrl(exchange, request.getURI());
String path = request.getURI().getRawPath();
String[] originalParts = StringUtils.tokenizeToStringArray(path, "/");
// all new paths start with /
StringBuilder newPath = new StringBuilder("/");
for (int i = 0; i < originalParts.length; i++) {
if (i >= config.getParts()) {
// only append slash if this is the second part or greater
if (newPath.length() > 1) {
newPath.append('/');
}
newPath.append(originalParts[i]);
}
}
if (newPath.length() > 1 && path.endsWith("/")) {
newPath.append('/');
}
ServerHttpRequest newRequest = request.mutate().path(newPath.toString()).contextPath(null).build();
exchange.getAttributes().put(ServerWebExchangeUtils.GATEWAY_REQUEST_URL_ATTR, newRequest.getURI());
return chain.filter(exchange.mutate().request(newRequest).build());
};
}
public static class Config {
private int parts;
public int getParts() {
return parts;
}
public void setParts(int parts) {
this.parts = parts;
}
}
}

How to enable togglz-console in spring-boot application

My spring-boot+jersey application has integrated togglz. I added below dependencies as below.
// togglz
compile('org.togglz:togglz-servlet:'+togglzVersion)
compile('org.togglz:togglz-cdi:'+togglzVersion)
compile('javax.enterprise:cdi-api:2.0-EDR1')
compile('org.togglz:togglz-spring-web:'+togglzVersion)
compile("org.togglz:togglz-spring-boot-starter:"+togglzVersion)
compile("org.togglz:togglz-console:"+togglzVersion)
compile("org.togglz:togglz-spring-security:"+togglzVersion)
compile("com.github.heneke.thymeleaf:thymeleaf-extras-togglz:1.0.1.RELEASE")
In my boot class I added below code:
#Bean
public FeatureProvider featureProvider() {
return new EnumBasedFeatureProvider(AppFeatures.class);
}
after launch the app, I can see the json data from this link:http://localhost:8080/togglz.
But I can't access http://localhost:8080/togglz-console. I got "Failed to load resource: the server responded with a status of 403 (Forbidden" error.
I can see below log in my log file but I can't access togglz-console/*.
o.s.b.c.e.ServletRegistrationBean : Mapping servlet: 'togglzConsoleServlet' to [/togglz-console/*]
below is my togglz property file:
# togglz
togglz:
feature-enums: com.cooltoo.backend.features.AppFeatures # Comma-separated list of fully-qualified feature enum class names.
features:
SMS_CODE: false
console:
enabled: true # Enable admin console.
path: /togglz-console # The path of the admin console when enabled.
what did I miss here?
Step1 Add the below dependency :
<!-- Togglz Admin Console -->
<dependency>
<groupId>org.togglz</groupId>
<artifactId>togglz-console</artifactId>
<version>2.3.0.RC1</version>
</dependency>
Step2 Add the below in your application.yml or application.properties
togglz:
console:
enabled: true # Enable admin console.
or
togglz.console.enabled: true # Enable admin console.
Step3 Configure the console path by
togglz:
console:
path: /togglz-console # The path of the admin console when enabled.
For authentication : Add a dummy UserProvider which assigns admin privileges to every user:
public class MyTogglzConfiguration implements TogglzConfig {
#Override
public UserProvider getUserProvider() {
return new UserProvider() {
#Override
public FeatureUser getCurrentUser() {
return new SimpleFeatureUser("admin", true);
}
};
}
}
If you want to authenticate the user, instead of the above dummy one , implement your own UserProvider by following this documentation
Please add the below in your application.yml or application.properties:
togglz:
console:
enabled: true
path: /togglz-console
use-management-port: false
or
togglz.console.enabled: true
togglz.console.path: /togglz-console
togglz.console.use-management-port: false
Setting togglz.console.use-management-port to false will always run the Admin Console on the application port.

Resources