Spring Cloud Sleuth bug on RefreshScope - gradle

we are currently having an issue with spring-cloud-sleuth and logback.
We are using sleuth to add trace information to our logback-logs which is working fine but when we hit the /actuator/refresh endpoint certain springProperty's that we define in the logback-spring.xml just disappear in all subsequent logs. These properties are defined in the gradle.properties file and injected into the application.yml on buid-time. We pinpointed the problem to be in the org.springframework.cloud:spring-cloud-starter-sleuth dependency. as soon as we remove it the refresh and logs work fine.
Here are some codesnippets that might help:
SpringProperty in logback-spring.xml:
<springProperty scope="context" name="version" source="spring.build.version"/>
application.yml definition of the variable:
spring:
build:
version: ${version}
Version definition in gradle.properties:
version=1.23
gradle sleuth dependency:
implementation("org.springframework.cloud:spring-cloud-starter-sleuth")
An example of a log message before refresh:
{
"level":"INFO",
"logger_name":"xx",
"message":"this is a message",
"thread_name":"boundedElastic-1",
"sequence":13,
"environment":"dev",
"version":"1.23",
"service":"my-service",
"traceId":"aa2d403b1d9a76a6",
"spanId":"aa2d403b1d9a76a6"
}
And after refresh:
{
"level":"INFO",
"logger_name":"xx",
"message":"this is another message",
"thread_name":"boundedElastic-1",
"sequence":2,
"environment":"development",
"traceId":"aa2d403b1d9a76a6",
"spanId":"aa2d403b1d9a76a6"
}
Thank you for your help!

Related

Spring Cloud Config: client doesn't attempt to connect to the config server

I'm trying to create a simple Spring Cloud Config server/client setup and am loosely following the documentation:
https://cloud.spring.io/spring-cloud-config/reference/html/
I've so far implemented a server that seems to work correctly, i.e. return the correct property values when I call the corresponding endpoint:
GET http://localhost:8888/config-client/development
{
"name": "config-client",
"profiles": [
"development"
],
"label": null,
"version": null,
"state": null,
"propertySources": [
{
"name": "classpath:/config/config-client-development.properties",
"source": {
"user.role": "Developer"
}
}
]
}
I'm, however, not having any luck with getting the client to connect to the server. I have done the following:
Added the spring-cloud-starter-config dependency:
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-config</artifactId>
</dependency>
Added a bootstrap.properties file:
spring.application.name=config-client
spring.profiles.active=development
spring.cloud.config.uri=http://localhost:8888
But I'm still getting a
java.lang.IllegalArgumentException: Could not resolve placeholder 'user.role' in value "${user.role}"
when trying to run the client application.
There is nothing in the application log that even looks like the client is attempting to communicate with the configuration server.
Link to a minimal GitHub repository that reproduces the issue:
https://github.com/Bragolgirith/spring-cloud-minimal
Steps to reproduce:
Build and run the config-service application
Build and run the config-client application
Any idea what I'm doing wrong?
OK, mistery solved.
It seems a new Spring Cloud version was released a week ago (https://spring.io/blog/2020/10/07/spring-cloud-2020-0-0-m4-aka-ilford-is-available) that has a new way to activate the bootstrap process - now it doesn't happen by default, but requires adding an additional dependency:
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-bootstrap</artifactId>
</dependency>
Although this new version is now the default you get when using the
Spring Initializr, the documentation is still not updated to reflect the changes - they are only briefly mentioned in the release notes.
As an alternative to using the abovementioned spring-cloud-starter-bootstrap dependency and a bootstrap.properties file, it seems the following is now also possible (and even preferred):
application.properties
spring.application.name=config-client
spring.profiles.active=development
spring.config.import=configserver:http://localhost:8888

Springdoc: got 404 when open swagger-ui.html

I got latest Spring Boot app and springdoc.swagger-ui on board.
<dependency>
<groupId>io.swagger</groupId>
<artifactId>swagger-annotations</artifactId>
<version>1.6.1</version>
</dependency>
<dependency>
<groupId>org.springdoc</groupId>
<artifactId>springdoc-openapi-ui</artifactId>
<version>1.2.32</version>
</dependency>
My application.properties contains springdoc.swagger-ui.path=/swagger-ui-openapi.html
When I run application via Intellij IDEA http://localhost:8080/swagger-ui-openapi.html brings me to http://localhost:8080/swagger-ui/index.html?configUrl=/v3/api-docs/swagger-config
and Swagger UI page loads successfully.
But if I start the app via command line: "java -jar my-app.jar", I got 404 in browser and Error in logs 'Circular view path [error]' when trying to reach http://localhost:8080/swagger-ui-openapi.html
and it redirrects me to http://localhost:8080/swagger-ui/index.html?configUrl=/v3/api-docs/swagger-config
javax.servlet.ServletException: Circular view path [error]: would dispatch back to the current handler URL [/error] again. Check your ViewResolver setup! (Hint: This may be the result of an unspecified view, due to default view name generation.)
However http://localhost:8080/v3/api-docs is reachable and schema is available at this address.
How can I fix this?
What worked in my case when your application is running behind a proxy, a load-balancer or in the cloud.
In your Spring Boot application make sure your application handles this header: X-Forwarded-For.
There are two ways to achieve this:
In your properties file add:
server.use-forward-headers=true
If this is not enough, Spring Framework provides a ForwardedHeaderFilter. You can register it as a Servlet Filter in your application by setting server.forward-headers-strategy is set to FRAMEWORK.
Since Spring Boot 2.2, this is the new property to handle reverse proxy headers:
In your properties file add
server.forward-headers-strategy=framework
And you can add the following bean to your application:
#Bean
ForwardedHeaderFilter forwardedHeaderFilter() {
return new ForwardedHeaderFilter();
}
If you already have static content on your root, and you don’t want it to be overridden by springdoc-openapi-ui configuration, you can just define a custom configuration of the swagger-ui, in order not to override the configuration of your files from in your context-root:
For example use in your properties file:
springdoc.swagger-ui.path= /swagger-ui/api-docs.html
ref:
https://springdoc.org/
For this problem, my conclusion is:
(1) Starting it in IDEA is fine
(2) Repackaging the jar with spring-boot-maven-plugin and starting it with 'java -jar' is fine as well.
(3) if I tried to starting with such as 'java -classpath ".:.conf" DemoApplication', it does not work.
So, for packaging, i use the spring-boot-maven-plugin.
You don't need swagger-annotations v1.6.1 dependency for springdoc-openapi;
By default, with springdoc you need no additonal settings of any ViewResolver.
You can have a look at some sample code:
https://github.com/springdoc/springdoc-openapi-demos

Can spring-boot application.properties file woking with log4j2.xml configuration?

I want to define high-level file logging in application.properties as a convenience to leverage my log4j2.xml file configuration. By itself my log4j2 config is working fine, however I was hoping to control logging levels and log file and path info from the application.properties file. I have the spring-boot-starter-log4j2 dependency in the application's pom file.
In log4j2.xml I have as one of the properties
<Property name="LOG_FILE">${LOG-DIR}/test.log</Property>
, where LOG-DIR is defined in another (previous) property in the same file. In my application.properties file, I have
logging.file=LOG_FILE
as a property, plus several level properties such as
logging.level.org.springframework.web=DEBUG
none of these log-related properties as defined in my application.properties file are working to build the corresponding log file. Again, when I simply use log4j2.xml by itself it works fine, but wanted to take advantage of the convenience of application.properties for logging configuration.
Any insights into what I am doing wrong are greatly appreciated. thank you
If I understood your question right, you are looking at Property Substitution feature of log4j2.
You can define logging property in application.properties file like below:
log.file.path=/myDir/logpath
And then the property(s) lookup defined as Property in log4j2.xml:
<Configuration>
<Properties>
<property name="LOG_FILE">${bundle:application:log.file.path}</property>
</Properties>
Now all the property can be referred in same log4j2.xml with ${propertyName} notation, which eventually points to values from application.properties file.

Spring flyway configuration: cannot find placeholders when running sql

I am trying to run gradlew flywayMigrate, and the application chrashes when running a recurring migration with the error
Caused by: org.flywaydb.core.api.FlywayException: No value provided for placeholder expressions: ${dbLinkHost}, ${dbLinkPassword}, ${dbLinkSid}, ${dbLinkUser}. Check your configuration!
The variables are configured like this in application.yml:
flyway:
placeholders:
dbLinkHost: ...
dbLinkSid: ...
dbLinkUser: ...
dbLinkPassword: ...
And I try to access them like this in the sql file:
'${dbLinkHost}'
Does anyone know why the declarations in application.yml don`t seem to be accessible here?
As a result of Spring Boot Issue #9896 - Move Flyway configuration properties to spring.flyway and commit f9e3163, starting with v2.0.0.M4, Flyway configuration properties in your application properties start with spring.flyway. To configure Flyway placeholders, for example:
spring:
flyway:
placeholders:
dbLinkHost: ...
dbLinkSid: ...
dbLinkUser: ...
dbLinkPassword: ...
In Spring Boot versions before v2.0.0.M4 such as the recently-released v1.5.14.RELEASE, Flyway configuration properties start with flyway.

Spring Boot - Log4j2 - 2 files are generated

I am using Log4j2 and Spring Boot (1.2.4). Following the documentation (and the log4j2-file.xml as example in spring-boot.jar), here is my configuration
<?xml version="1.0" encoding="UTF-8"?>
<Configuration>
<Appenders>
<File name="Logs" fileName="${sys:LOG_FILE}" append="false">
...
<Logger level="warn">
<AppenderRef ref="Logs"/>
</Logger>
In application.properties file :
logging.file: /var/tmp/logs/mylog.log
As a result, 2 files are generated :
One file named ${sys:LOG_FILE} which remains empty
One file /var/tmp/logs/mylog.log properly filled
I do not understand why the file ${sys:LOG_FILE} is generated.
Any idea ?
Thanks a lot.
I'm using version 1.2.5.RELEASE of Spring Boot (including the starter parent) and I'm seeing the same issue.
My assumption is that Log4j2 tries to initalize the file before Spring Boot loaded the configuration, resulting in an empty file called ${sys:LOG_FILE} or ${sys (on Windows).
One way of avoiding this is to just set the system property (-DLOG_FILE=/var/tmp/logs/mylog.log) and remove logger.file from your configuration.
It seem log4j2.xml is loaded and log file is created before application.properties being loaded. One way to fix this is to change the name of log4j2.xml to something else, for example log4j2-example.xml to present auto loading and then add the following line into application.properties:
logging.config=classpath:log4j2-example.xml
This will ensure the LOG_PATH are loaded before creating logger.
logging.file is just used for default logger configured by spring only.
In this case, your LOG_FILE must be passed into system variable before execute the jar by -DLOG_FILE=/location/of/log.file

Resources