How to log MDC with Spring Sleuth 2.0? - spring-boot

referring to quesition/answer in How to log MDC with Spring Sleuth?
I think this has/will change(d) with spring-cloud 2.0 as there is no SpanLogger or Slf4jSpanLogger anymore (or I don't find it)
Wouldn't it be nice if application properties spring.sleuth.baggage-keys and spring.sleuth.propagation-keys if set would also be put in MDC I think inside Slf4jCurrentTraceContext (as this class is currently final I cannot subclass it)
If not, how could I achieve this with spring-cloud 2.0 accordingly?

We don't want to put all entries in MDC (that really doesn't make a lot of sense). You can however either copy the Slf4jCurrentTraceContext and extend it in the way you want to (and register it as a bean) or maybe create your own implementation of CurrentTraceContext that would wrap the existing CurrentTraceContext via a Bean Post Processor and perform additional logic. I guess the first option is more preferable.

In version 2.1.0, Slf4jScopeDecorator was introduced and it will automatically add baggage values to MDC as long as they are whitelisted in the spring.sleuth.log.slf4j.whitelisted-mdc-keys configuration.
For example, if you have the following configuration:
spring.sleuth.baggage-keys=key1,key2
spring.sleuth.log.slf4j.whitelisted-mdc-keys=key2
Only the value of key2 will be automatically added MDC, but not the value of key1.
For more info, see: https://cloud.spring.io/spring-cloud-sleuth/reference/html/#prefixed-fields

Related

#ConstructorBinding with immutable properties don't work with #Value in Spring Boot Kotlin #ConfigurationProperties

Spring Boot supports Kotlin data classes for #ConfigurationProperties.
#ConstructorBinding
#ConfigurationProperties(prefix = "prefix")
data class AppProperties (
val something: String
)
But val and #ConstructorBinding has some limitations. You cannot alias one variable to another. Let's say you're running in Kubernetes and want to capture the hostname, which is given by the env var HOSTNAME. The easiest way to do this is to apply #Value("\${HOSTNAME}:)" to a property, but it only works for a mutable property and without constructor binding.
The Spring Boot GitHub issue tracker says:
STOP!! Please ask questions about how to use something, or to understand why something isn't
working as you expect it to, on Stack Overflow using the spring-boot tag.
So, is this a known limitation or should I create a ticket for them to fix it?
Edit:
Opened https://github.com/spring-projects/spring-boot/issues/25552
#ConfigurationProperties is an alternative to #Value and the two are not designed to be used together. It may work with JavaBean-style binding but that would be by accident rather than by design and it shouldn't be relied upon.
Instead of using #Value to alias something bound via #ConfigurationProperties, it's recommended that you do so via some other means. For example you could use one of the approaches suggested in this answer that Marcos Barbero linked to in the comments on your question. Alternatively, you could take some inspiration from this example in the documentation and use a placeholder in application.properties:
prefix.something=${hostname}
Another option would be to register via META-INF/spring.factories an implementation of EnvironmentPostProcessor that adds a PropertySource to the environment to set up the desired aliasing. For the time being, this is probably the best approach if you want to do something in a reusable library. There's an open issue to remove some of the ceremony that's currently involved.

In Spring Boot how do you register custom converters that are available when parsing application configuration?

In a Spring Boot application how do you register custom converts to be used when processing application configuration?
I have made a custom convert (org.springframework.core.convert.converter.Converter) so it can be used by the ApplicationConversionService/Binder to parse #ConfiguraitonProperties defined in application.properties and application.yaml configuration files but do not know how to register it.
I have tried the solution here https://stackoverflow.com/a/41205653/45708 but it creates an instance of my converter after the application configuration parameters have been processed.
I ran into this issue myself recently. From what I can tell, the key issue is that binding to configuration properties occurs very early in the Spring startup process, before the Application Context is fully initialized. Therefore the usual methods for registering a converter are not reliable. In fact the ConversionService used for configuration binding appear to be a one-off and not really connected to the ConversionService that is stored in the Application Context.
I was able to get something working but it feels like a hack, as it relies on internal implementation details that may work today but not tomorrow. In any case, this is the code I used:
((ApplicationConversionService) ApplicationConversionService.getSharedInstance()).addConverter(myCustomConverter);
The trick I found was to make sure this gets called as soon as possible at application startup so that it gets called before the configuration binding where it's needed. I put it in a #PostConstruct block inside my main #SpringBootApplication class as this seemed to get invoked early on, at least in my case.

Using RequestScope without ServletModule

I was exploring #RequestScoped and was wondering if there's way to use it without installing ServletModule. I am using Guice 3.0 + Jersey 1.17 and probably don't want to use GuiceContainer & GuiceServletContextListener.
I want object creation(injections) per request depending on some user input in the Jersey request. Is it possible? What can be performance & security considerations of using GuiceContainer if I had to replace my existing ServletContextListener with that of Guice?
If there's a way of using RequestScope as per my needs, can you give me some references for the same?
It is possible to bind a custom Scope implementation to a predefined scoping annotation like #RequestScoped. It does mean that then you cannot use ServletModule, since you can't bind two different implementations to the same scoping annotation.
See the documentation on Custom Scopes for details. You will need to write code to determine what constitutes a "request" for purposes of scoping, and trigger entering and exiting the scope as necessary.
For example, in the normal Guice implementation, ServletScopes.RequestScope uses a ThreadLocal initialized in GuiceFilter to keep track of what the current request is.

Spring environment validation

We're building a Spring-based application which will be delivered to end users as a distribution package. Users are responsible for properly configuring whatever needs to be configured (it's mostly about various filesystem locations, folder access permissions, etc). There's a good idea to make the app help users understand what is not configured or which parts of configuration are invalid.
Our current approach is a custom ApplicationContextInitializer which does all the environment validation "manually" and then registers few "low level" beans in the application context explicitly. If something is wrong, initializer throws, exception is caught somewhere in main(), interpreted (converted into plain English) and then displayed.
While this approach works fine, I'm wondering if there are any best practices to minimize hand-written code and use Spring whenever possible.
Here's an illustrative example. The application requires a folder for file uploads. This means:
There should be a configuration file
This file should be accessible by the app
This file should have no syntax errors
This file should explicitly define some specific property (let it be app.uploads.folder)
This property should describe the existing filesystem entity
This entity should be a folder
The app should have read/write access to this folder
Does Spring provide any tools to implement this sort of validation easily?
Spring Boot has a nice feature for context and external configuration validation. If you define a POJO class and declare it as #ConfigurationProperties then Spring will bind the Environment (external properties and System/OS typically) to its properties using a DataBinder. E.g.
#ConfigurationProperties(name="app.uploads")
public class FileUploadProperties {
private File folder;
// getters and setters ommitted
}
will bind to app.uploads.folder and ensure that it is a File. For extra validation you can do it manually in the setter, or you can implement Validator in your FileUploadProperties or you can use JSR-303 annotations on the fields. By default an external property in app.uploads.* that doesn't bind will throw an exception (e.g. a mis-spelled property name, or a conversion/format error).
If you use Spring Boot Autoconfigure #EnableAutoConfigure you don't have to do anything else, but if it's just vanilla Spring (Boot) you need to say #EnableConfigurationProperties in your #Configuration somewhere as well.
A bonus feature: if you also use the Spring Boot Actuator you will also get JMX and HTTP support (in a webapp) for inspecting the bindable and bound properties of #ConfigurationProperties beans. The HTTP endpoint is "/configprops".

Extended Properties for Spring Framework

Looking for a solution that will provide us more functionality within Spring properties such as:
nested structures
maps/lists
properties referencing other properties. Example:
city.name=Toronto
city.address=#{city.name}, 123 Ave SW
I tried EProperties (Google) and Commons Configurations (Apache) but doesn't seem to integrate very well with the Spring Framework.
Also, we're using Velocity to access properties using #springMessage("city.address"), so it needs to work for that.
Does anyone know how I can achieve the above by extending the default Properties capability?
With newest versions of Spring you can use the PropertySource mechanism. You register all your PropertySource and the order in which they are searched and then you don't have to do anything, except perhaps add this to your XML:
<context:property-placeholder />
As long as you declare only one of these without specifying local property files (the "old way"), you will be able to reference property A as the value of property B, even if they are not in the same property source.
For nested structures this may help if you don't like the properties readability:
https://stackoverflow.com/a/13470704/82609
For parsing problems you can easily handle lists and other stuff like that manually very easily:
Reading a List from properties file and load with spring annotation #Value

Resources