In the Quarkus Application Configuration Guide it mentions how to configure an app with profiles (eg. %dev.quarkus.http.port=8181).
But is there a way to access a Profile (or Environment) API so I can log the active profiles ? For example something like Spring:
#ApplicationScoped
public class ApplicationLifeCycle {
private static final Logger LOGGER = LoggerFactory.getLogger("ApplicationLifeCycle");
#Inject Environment env;
void onStart(#Observes StartupEvent ev) {
LOGGER.info("The application is starting with profiles " + env.getActiveProfiles());
}
ProfileManager.getActiveProfile()?
Related
I'm writing unit tests and trying to use ExecutionCondition for enabling the test only when specific profile activated exclusively.
I created my ExecutionCondition.
class EnabledWithH2ExclusiveExecutionCondition implements ExecutionCondition {
#Override
public ConditionEvaluationResult evaluateExecutionCondition(
final ExtensionContext context) {
// check the environment
}
#Autowired
private Environment environment;
}
But the environment is not injected.
How can I do that?
Because your ExecutionCondition is created by JUnit5 itself using reflection .It is not managed by Spring and so the #Autowired will not work.
You can call SpringExtension.getApplicationContext() to get Spring Context and then get the Environment from it :
#Override
public ConditionEvaluationResult evaluateExecutionCondition(final ExtensionContext context){
Environment env = SpringExtension.getApplicationContext(context).getEnvironment();
// check the environment
}
I followed the exact steps in this documentation.
I have the following entries in my META-INF/spring.factories
org.springframework.boot.env.EnvironmentPostProcessor=com.mygroup.myapp.CustomEnvironmentPostProcessor
My post processor:
public class CustomEnvironmentPostProcessor
implements EnvironmentPostProcessor, Ordered {
..
}
I don't see anything in the logs as if it didn't get registered or not existing.
I unzipped the JAR and I can see META-INF/spring.factories. I can also see BOOT-INF/classes directly from the root.
What am I missing here?
There is no elegant way to solve this. You can make something like this :
#Component
public class CustomEnvironmentPostProcessor implements
EnvironmentPostProcessor, ApplicationListener<ApplicationEvent> {
private static final DeferredLog log = new DeferredLog();
#Override
public void postProcessEnvironment(
ConfigurableEnvironment env, SpringApplication app) {
log.error("This should be printed");
}
#Override
public void onApplicationEvent(ApplicationEvent event) {
log.replayTo(CustomEnvironmentPostProcessor.class);
}
}
define spring.factories file
Environment Post Processor
org.springframework.boot.env.EnvironmentPostProcessor=\
class name with package
As of Spring Boot 2.4, there are now optional constructor parameters that provide access to deferred logs:
public class CustomEnvironmentPostProcessor implements EnvironmentPostProcessor {
private final Log log;
public CustomEnvironmentPostProcessor(Log log) {
this.log = log;
}
#Override
public void postProcessEnvironment(ConfigurableEnvironment environment, SpringApplication application) {
log.info("CustomEnvironmentPostProcessor!!");
}
}
NOTE: The log messages are deferred so they will appear in the log output only after the logging system has been initialized.
See https://docs.spring.io/spring-boot/docs/current/api/org/springframework/boot/env/EnvironmentPostProcessor.html
Because #BeforeClass method in Junit should be static and static methods couldn't access instance objects, I couldn't use the following code to get spring properties.
#Autowired
private Environment env;
OR
#Value("${spring.path}")
private String path;
Are there other ways to access spring properties from application.yml in #BeforeClass method of Spring Junit Test?
#BeforeClass
public static void test() {
// I want to access path or env variable here.
// Generally, it's impossible to access instance variables in static method
// So my question is how to access spring properties from here.
// In the case, I'd like to copy a file to spring.path folder for testing.
}
Just use #Before (instead of #BeforeClass)
java test file:
#RunWith(SpringRunner.class)
#SpringBootTest
public class SofTests {
#Autowired
private Environment env;
#Value("${spring.path}")
private String path;
#Before
public void sof() {
System.out.println("sof) path: " + path);
}
}
src/test/resources/application.yml file:
spring.path: foo/file.ext
Console:
sof) path: foo/file.ext
I want to set active profile host dependent for any envrionment and cannot find an environment independent hook.
Following factory will set the active profile before application context will build.
/META-INF/spring.factories
org.springframework.context.ApplicationContextInitializer=MyApplicationContextInitializer
MyApplicationContextInitializer.java
public class MyApplicationContextInitializer implements ApplicationContextInitializer<ConfigurableApplicationContext> {
#Override
public void initialize(ConfigurableApplicationContext ca) {
ConfigurableEnvironment environment = ca.getEnvironment();
environment.addActiveProfile("myHost");
}
}
If this example is executed in a mock environment by JUnit ...
*Test.java
...
#RunWith(SpringRunner.class)
#SpringBootTest
#AutoConfigureMockMvc
...
... following will be logged.
...
... RestControllerTests : The following profiles are active: myHost
...
but profile myHost is not active and default profile will be used in context of JUnit!
A test as Java Application and JUnit with VM arguments works ...
-Dspring.profiles.active=myHost
I use a war packaged spring-boot-starter-web app and programmatically profile shall be set and used in any environment
Java Application
JUnit
Servlet Container
How do I set the profile programmatically for any environmnet?
I do not want to use VM arguments or environemt variables because the profile shall be set by the current host name.
Simplest answer after a lot of googling :)
#SpringBootApplication
public class ExampleMain2 {
public static void main(String[] args) {
ConfigurableEnvironment environment = new StandardEnvironment();
environment.setActiveProfiles("dev");
SpringApplication sa = new SpringApplication(ExampleMain2.class);
sa.setEnvironment(environment);
sa.setAdditionalProfiles("remote","live");
sa.run(args);
}
}
I had the same issue and I finally solved it implementing the ActiveProfilesResolver interface.
In your case you could do something like this:
public class MyActivateProfilesResolver implements ActiveProfilesResolver {
#Override
public String[] resolve(Class<?> testClass) {
// some code to find out your active profiles
return new String[] {"myHost"};
}
}
And then you need to link your test with your resolver like this:
#ActiveProfiles(resolver = MyActivateProfilesResolver.class)
I don't think there is such a thing as setting active profile dynamically (programmatically) at runtime once the application is running, any modification to the profile will not have any effect on the loaded beans and properties files.
However, before running the application you can configure the available profiles of the application. for example:
#SpringBootApplication
public class DemoApplicationWithSysProperty {
public static void main(String[] args) {
System.setProperty(AbstractEnvironment.ACTIVE_PROFILES_PROPERTY_NAME,
PROFILE_NAME);
SpringApplication.run(DemoApplicationWithSysProperty.class, args);
}
}
Don't you think that could be achieved with an EnvironmentPostProcessor ans still have an impact on the running environment? My attempts failed.
#Order(Ordered.LOWEST_PRECEDENCE)
public class EnvtPostProcessor implements EnvironmentPostProcessor {
#SuppressWarnings("deprecation")
#Override
public void postProcessEnvironment(ConfigurableEnvironment env, SpringApplication application) {
if ((env.acceptsProfiles("bar1") || env.acceptsProfiles("bar2"))
&& !(env.acceptsProfiles("foo1") || env.acceptsProfiles("foo2"))) {
env.addActiveProfile("foo1");
}
}
}
NB: don't forget to register the processor in src/main/resources/META-INF/spring.factories:
org.springframework.boot.env.EnvironmentPostProcessor=com.mygroup.myapp.EnvtPostProcessor
When I only apply the "bar2" active profile, the "foo1" profile is added to the environnement as an active profile, before application context initialization; but not all beans are found eventually (as they are in the originally complete active profiles list use case).
Maybe that's because of the dependencies (Azure for Spring Cloud connection, by the way) : I end up with no OAuth2UserService found for my ActiveDirectoryConfigurer.
I'm running Spring Boot and I want to add logging to my application. All examples have the following for the main Application entrypoint:
private static final Logger log = LoggerFactory.getLogger(Application.class);
However, I want the same log variable visible (as Singleton) across all my application components (services, controllers, etc.). How would I do that? Thanks!
You can use springs IoC container to achieve this.
just configure a bean like this in a #Configuration cass
#Bean
public Logger log() {
return LoggerFactory.getLogger(AnyClassYouWant.class);
}
and inject it with #Autowired in your class
class WhatEver {
#Autowired
Logger log;
//...
}
You can create a static class.. Which contain:
private static final Logger log = LoggerFactory.getLogger(StaticLog.class);
And will expose methods to write logs..
Hope that answer your needs