How to use multiple configuration files for Log4j2? - java

I am writing Java code that tests a Java library. The library includes its own Log4j2 configuration as part of the distribution.
I would like to use Log4j2 in my test code without modifying the library's configuration.
Is there a way to have a separate Log4j2 configuration for my test code?
This is all running as command-line Java, no servers or web involvement at all.
EDIT
What I want is to be able to configure loggers, appenders, etc for the test code to use, and at the same time have the library code use its own separate configuration file for its logging.
The idea is to use Log4j2 in my test code, but without having to change the library's configuration file. Since the library configuration file is part of the library's distribution, I don't want to change it for testing.

This may be helpful:
Log4j2 will first look for log4j2-test.xml in the classpath
if that file is not found, it will look for log4j2.xml in the classpath
So one option is to copy the library's configuration (log4j2.xml) to log4j2-test.xml and add your own configuration to log4j2-test.xml.
Furthermore, Log4j2 supports XInclude in XML configuration, so you could use that feature to avoid duplicating the library's configuration in your log4j2-test.xml.

Log4j2 supports "Composite Configuration" which exactly matches your requirement. All you need to do is provide path to multiple files in log4j.configurationFile property. This can be passed from command line or added to log4j2.component.properties file in your application.
References
https://logging.apache.org/log4j/2.x/manual/configuration.html#CompositeConfiguration
https://logging.apache.org/log4j/2.x/manual/configuration.html#SystemProperties

There are two step you can try to solve for your issue
Create your own configuration file with your custom name(eg: xyz.properties/.xml)
You must add the following line to your java runtime command
cmd> java -Dlog4j.configuration=location/xyz.properties
If you use diffent name for configuration rather log4j.properties/.xml file you need to configure that file at runtime by above command for more info have a look here..

Correct format for using an alternate XML file to log4j2.xml:
java -Dlog4j.configurationFile=./location/log4j2-custom.xml
Assuming ./location/log4j2-custom.xml exists and is the new XML to replace log4j2.xml in this run
See:
https://github.com/kamalcph/Log4j2Examples/blob/master/src/main/java/in/co/nmsworks/log4j2/examples/CompositeConfigurationExample.java

Referencing https://logging.apache.org/log4j/2.x/manual/configuration.html states that you can add multiple comma separated files under log4j2.configurationFile property.

To use multiple configuration files, depending on the environment you must set the.
for example:
if (env.equals("DEV")) {
setConfigFile("log4j2-dev.xml");
}
public static void setConfigFile(String logConfigFile) {
File file = new File(logConfigFile);
LoggerContext context = (org.apache.logging.log4j.core.LoggerContext) LogManager.getContext(false);
context.setConfigLocation(file.toURI());
}

first configure application.yaml file
spring:
profiles:
active: dev
---
spring:
message: running in the dev profile //just to output the message in the log
profiles: dev
logging.config: classpath:log4j2-dev.xml
---
spring:
profiles: prod
logging.config: classpath:log4j2-prod.xml
and create these similar files in your classpath
* log4j2-dev.xml
* log4j2-prod.xml

Related

Disable spring-context-indexer by profile

I want to enable Spring Context Indexer on a project but I am having issues with Swagger3 (check here and here).
I understand the limitations and would like to enable it, at least, at the DEV profile where we do not need Swagger running.
My goal is to disable indexing on PROD environment. From docs:
you can fallback to a regular classpath arrangement (as though no index was present at all) by setting spring.index.ignore to true, either as a system property or in a spring.properties file at the root of the classpath.
My first approach (without success) was setting an env var (Windows 10) with the following:
SPRING_APPLICATION_JSON={"spring":{"index":{"ignore":true}}}
If I create a spring.properties file and set the value accordingly it works. But I can't figure how to use different properties for each profile, I imagined it was something like the application.properties file but I was wrong.
How can I achieve that?
EDIT:
Just to be clear, this config (spring.index.ignore) will just work if inside a spring.properties file, not an application.properties one. (Just double-checked before this edit)
Actually I have one application-prod.properties and one application-dev.properties.
I don't know the difference between spring.properties and application.properties but the first one doesn't seem to work with multiple profiles as the later.
Edit 2:
Just went through org.springframework.context.index.CandidateComponentsIndexLoader and it uses SpringProperties.getFlag(IGNORE_INDEX) to read the value.
SpringProperties class is clear about the file it uses:
Reads a spring.properties file from the root of the Spring library classpath, and also allows for programmatically setting properties through setProperty. When checking a property, local entries are being checked first, then falling back to JVM-level system properties through a System.getProperty check.
I think I will need to pass a property to Java runner during initialization. Will research a little bit more about it.
you can use different application.properties file as follow:
add the following files to the resource folder:
application.properties
spring.profiles.active=dev #place profile name you want to use
application-dev.properties
#dev properties
...
You can create many application-env.properties you may wish
application-env.properties
#env properties
...
Spring Boot supports profile-specific properties files. You have to name these files with the following format: application-{profile}.properties. You can activate a profile via JVM system parameter: -Dspring.profiles.active=dev. You can read more about this subject here: https://www.baeldung.com/spring-profiles

Spring Boot refuses to pick up application test properties [duplicate]

I have a spring boot application that I can package in a war that I want to deploy to different environments. To automate this deployment it'd be easier to have the configuration file externalized.
Currently everything works fine with a application.properties file in src/main/resources. Then I use ´mvn install´ to build a war deployable to tomcat.
But I would like to use a .yml file that does not need to be present on mvn install but that would be read from during deployment of the war and is in the same or a directory relative to my war.
24. externalized configuration shows where spring boot will look for files and 72.3 Change the location of external properties of an application gives more detail on how to configure this but I just do not understand how to translate this to my code.
My application class looks like this:
package be.ugent.lca;
Updated below
Do I need to add a #PropertySource to this file? How would I refer to a certain relative path?
I feel like it's probably documented in there as most spring boot documentation but I just don't understand how they mean me to do this.
EDIT
Not sure if this should be a separate issue but I think it's still related.
Upon setting the os variable the error of yaml file not found went away. Yet I still get the same error again as when I had no application .properties or .yml file.
Application now looks like this:
#Configuration
**#PropertySource("file:${application_home}/application.yml")**
#ComponentScan({"be.ugent.lca","be.ugent.sherpa.configuration"})
#EnableAutoConfiguration
#EnableSpringDataWebSupport
public class Application extends SpringBootServletInitializer{
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
The application_home OS variable
$ echo $application_home
C:\Masterproef\clones\la15-lca-web\rest-service\target
My application.yml file(part it complains about):
sherpa:
package:
base: be.ugent.lca
Error upon java -jar *.war
All variations upon:
Caused by: java.lang.IllegalArgumentException: Could not resolve placeholder 'sherpa.package.base' in string value "${sherpa.package.base}"
at org.springframework.util.PropertyPlaceholderHelper.parseStringValue(PropertyPlaceholderHelper.java:174)
at org.springframework.util.PropertyPlaceholderHelper.replacePlaceholders(PropertyPlaceholderHelper.java:126)
at org.springframework.core.env.AbstractPropertyResolver.doResolvePlaceholders(AbstractPropertyResolver.java:204)
at org.springframework.core.env.AbstractPropertyResolver.resolveRequiredPlaceholders(AbstractPropertyResolver.java:178)
at org.springframework.context.support.PropertySourcesPlaceholderConfigurer$2.resolveStringValue(PropertySourcesPlaceholderConfigurer.java:172)
at org.springframework.beans.factory.support.AbstractBeanFactory.resolveEmbeddedValue(AbstractBeanFactory.java:808)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1027)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1014)
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:545)
... 142 more
Using external properties files
The answer lies in the Spring Boot Docs, I'll try to break it down for you.
First of all, no you should not use #PropertySource when working with Yaml configuration, as mentioned here under the Yaml shortcomings :
YAML files can’t be loaded via the #PropertySource annotation. So in the case that you need to load values that way, you need to use a properties file.
So, how to load propery files? That is explained here Application Property Files
One is loaded for you: application.yml , place it in one of the directories as mentioned in the link above. This is great for your general configuration.
Now for your environment specific configuration (and stuff like passwords) you want to use external property files, how to do that is also explained in that section :
If you don’t like application.properties as the configuration file name you can switch to another by specifying a spring.config.name environment property. You can also refer to an explicit location using the spring.config.location environment property (comma-separated list of directory locations, or file paths).
So you use the spring.config.location environment property.
Imagine you have an external config file: application-external.yml in the conf/ dir under your home directory, just add it like this:
-Dspring.config.location=file:${home}/conf/application-external.yml as a startup parameter of your JVM.
If you have multiple files, just seperate them with a comma. Note that you can easily use external properties like this to overwrite properties, not just add them.
I would advice to test this by getting your application to work with just your internal application.yml file , and then overwrite a (test) property in your external properties file and log the value of it somewhere.
Bind Yaml properties to objects
When working with Yaml properties I usually load them with #ConfigurationProperties, which is great when working with for example lists or a more complex property structure. (Which is why you should use Yaml properties, for straightforward properties you are maybe better of using regular property files). Read this for more information: Type-Safe Configuration properties
Extra: loading these properties in IntelliJ, Maven and JUnit tests
Sometimes you want to load these properties in your maven builds or when performing tests. Or just for local development with your IDE
If you use IntelliJ for development you can easily add this by adding it to your Tomcat Run Configuration : "Run" -> "Edit Configurations" , select your run configuration under "Tomcat Server" , check the Server tab and add it under "VM Options".
To use external configuration files in your Maven build : configure the maven surefire plugin like this in your pom.xml:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
<argLine>-Dspring.config.location=file:${home}/conf/application-external.yml</argLine>
</configuration>
</plugin>
When running JUnit tests in IntelliJ:
Run → Edit Configurations
Defaults → JUnit
add VM Options -> -ea -Dspring.config.location=file:${home}/conf/application-external.yml
Yes, you need to use #PropertySource as shown below.
The important point here is that you need to provide the application_home property (or choose any other name) as OS environment variable or System property or you can pass as a command line argument while launching Spring boot. This property tells where the configuration file (.properties or .yaml) is exactly located (example: /usr/local/my_project/ etc..)
#Configuration
#PropertySource("file:${application_home}config.properties")//or specify yaml file
#ComponentScan({"be.ugent.lca","be.ugent.sherpa.configuration"})
#EnableAutoConfiguration
#EnableSpringDataWebSupport
public class Application extends SpringBootServletInitializer{
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
There is a very simple way to achieve this.
Inside your original application.properties file you can just specify the following line:
spring.config.import=file:Directory_To_The_File/Property_Name.properties
It will automatically sync all the properties from the external property file.
Now lets say that you have a situation where you need to get properties from multiple property files. In that case, you can mention the same line in the external property file which in turn will take the remaining properties from the second property file and so on.
Consider the following example.
application.properties:
spring.config.import=file:Resources/Custom1.properties
Custom1.properties:
server.port=8090
.
.
.
spring.config.import=file:Resources/Custom2.properties
One of the easiest way to use externalized property file using system environment variable is, in application.properties file you can use following syntax:
spring.datasource.url = ${OPENSHIFT_MYSQL_DB_HOST}:${OPENSHIFT_MYSQL_DB_PORT}/"nameofDB"
spring.datasource.username = ${OPENSHIFT_MYSQL_DB_USERNAME}
spring.datasource.password = ${OPENSHIFT_MYSQL_DB_PORT}
Now, declare above used environment variables,
export OPENSHIFT_MYSQL_DB_HOST="jdbc:mysql://localhost"
export OPENSHIFT_MYSQL_DB_PORT="3306"
export OPENSHIFT_MYSQL_DB_USERNAME="root"
export OPENSHIFT_MYSQL_DB_PASSWORD="123asd"
This way you can use different value for same variable in different environments.
Use below code in your boot class:
#PropertySource({"classpath:omnicell-health.properties"})
use below code in your controller:
#Autowired
private Environment env;

How to set different log levels in Eclipse Scout framework?

I'm having some trouble configuring proper logging in Eclipse Scout framework. My claims aren't that high as I only want to be able to set different log levels for different parts of my program in a configuration/properties/XML file.
The logging configuration in the config.ini of my Scout server plugin currently looks like this:
eclipse.consoleLog=true
org.eclipse.scout.log=eclipse
org.eclipse.scout.log.level=INFO
So as you can see this is the default logging configuration using Eclipse logging. It works fine for logging at a global level. The only thing I would like to do is to write something like this to set the different log levels:
packagename.ClassName=LOGLEVEL
As this is a very basic logging use case I think there must be some easy way to do this in Scout. Otherwise I would appreciate some help how to configure log4j, JUL or others for the use with Scout. The Eclipse Scout Wiki hasn't helped me so far. I created the example logger fragment to the host plugin 'org.eclipse.scout.commons' and removed the logging configuration lines from my config.ini but nothing happens. I'm also not sure where to put the log4j.poperties or how this is done otherwise.
I'm a bit ashamed for being unable to figure out such a basic problem, but would be very happy about some quick help.
I can tell you how to configure the logging if you choose the java logger (config.ini: org.eclipse.scout.log=java).
For the eclipse logger, I barely found any information at all.
Now, to configure the java (JUL) logging: You can do this in a file called logging.properties.
You can configure the logging by specifying the configuration file in your product:
Create your configuration file - say logging.properties inside the folder where your product file (for server or client respectively) is located. Typically this is in a folder named 'products'.
Open your product file and go to the "Launching" tab and specify your logging configuration file in the "VM Arguments" tab. Use the "java.util.logging.config.file" system property to do so:
-Djava.util.logging.config.file="${resource_loc:/com.yourapp.server/products/logging.properties}"
Now, you should be able to specify the log levels in your new logging.properties file:
### Root level of your application, all below are ignored
.level=INFO
### Handlers
handlers=java.util.logging.ConsoleHandler
### Handler properties
java.util.logging.ConsoleHandler.level=FINEST
### Override the logging level for certain classes
com.yourapp.server.SomeService.level=FINE
Alternatively, you can also use a class to initialize the logging with the java.util.logging.config.class option. See this wiki page for a detailed example.
Also, when building a WAR file, you might be interested in this answer.

Set log4j log level

I'm currently working on a project that uses log4j.
I'm running a testcase (junit) and would like to set the log level to trace so that I can see if all the values are correct. Classes that use logging in the project contain a line like the following:
private static final Log LOG = LogFactory.getLog(MatchTaskTest.class);
and use a like like this to do the actual debugging
LOG.trace("value");
I have never used log4j before, does anybody know how I can change the log level just for the testcase, preferably simply by defining a parameter in eclipse's run configuration dialog.
Using another configuration file
Perhaps you could point to another configuration file.
java -Dlog4j.configuration=config file yourApp
Where:
config, you file of configuration, e.g. log4j.properties or log4j.xml.
file, the log file, e.g. myApp.log
yourApp, you app, e.g. MyAppGUI
Or you can use a class
java -Dlog4j.configurationClass=config class yourApp
Where:
config, you file of configuration, e.g. log4j.properties or log4j.xml.
class, any customized initialization class, like LogManager, should implement
the org.apache.log4j.spi.Configurator
yourApp, you app, e.g. MyAppGUI
You can see more in Apache log4j 1.2 - Short introduction to log4j on Default Initialization Procedure section.
Modifying the level programmatically
Moreover, you can also use the methods that offers the Logger class, like public void setLevel(Level level), e.g.:
Logger.getRootLogger().setLevel(Level.TRACE);
Since you want only for testing purposes, you could use them. But it is recommended not to use in client code because they overwrite the default configuration parameters in hard coded. The best way is to use an external configuration file.
In your junit class put:
Logger.getRootLogger().setLevel(Level.TRACE);
somewhere before the execution of the tested method. It will set the threshold level of the root logger to TRACE.
If you're using Maven, you can have two log4j configuration files:
one in src/main/resources, containing your production logging config
one in src/test/resources, containing your test-time logging config
Maven will automatically use the latter at test time, and bundle the former into your artifact (JAR, WAR, etc) so that it's used in production. You don't have to mess around with command line switches or anything.
I don't think this is possible.
The config file is going to let you configure what log messages actually surface in the log, not what level each message is going be logged at. This makes sense - the config should not affect the level of the message.
The javadoc has a method for each log level and a generic log method, which takes in a priority, so I'm not sure there's even a default to be set.
You can set a config file explictly on the command line via -Dlog4j.configuration=<FILE_PATH>, so you could set up a specific config for that test case.
I have no idea why some of the above didn't work for me. (I don't want to write config file). following works for me
Logger log1 = Deencapsulation.getField(Some.class,"logger");
log1.setLevel(Level.DEBUG);
NB that the log4j2.properties file may include the line
filter.threshold.level = debug
You can waste an entire afternoon trying to figure out why your LOG.trace() statements aren't outputting anything!
I actually put it in the #Before method. But I believe it could (and should) be placed in the #BeforeClass.
If you set it in the class body you'll get compiler errors.

Log4j configuration via JVM argument(s)?

What variables do I have to set/pass as arguments to the JVM to get Log4j to run properly? And by properly I mean not complain and print to the console. Can I see a typical example?
Note: I need to avoid creating a log4j.properties file in the application.
Do you have a log4j configuration file ? Just reference it using
-Dlog4j.configuration={path to file}
where {path to file} should be prefixed with file:
Edit: If you are working with log4j2, you need to use
-Dlog4j.configurationFile={path to file}
Taken from answer https://stackoverflow.com/a/34001970/552525
The solution is using of the following JVM argument:
-Dlog4j.configuration={path to file}
If the file is NOT in the classpath (in WEB-INF/classes in case of Tomcat) but somewhere on you disk, use file:, like
-Dlog4j.configuration=file:C:\Users\me\log4j.xml
More information and examples here: http://logging.apache.org/log4j/1.2/manual.html
This configuration seems to have changed in Log4j 2:
-Dlog4j.configurationFile=file:C:\Users\me\log4j.xml
See: https://logging.apache.org/log4j/2.x/manual/configuration.html
I know this is already answered, but because you said, this isn't exactly what you are looking for, I would like to point out the following alternative:
You can also use a configuration class instead of the properties or xml file.
-Dlog4j.configuratorClass=com.foo.BarConfigurator
See http://logging.apache.org/log4j/1.2/manual.html for details.
Late to the party as since 2015, Log4J 1.x has reached EOL.
Log4J 2.x onwards the JVM option should be -Dlog4j.configurationFile=<filename>
P.S. <filename> could be a file relative to the class path without the file: as suggested in the other answers.
Generally, as long as your log4j.properties file is on the classpath, Log4j should just automatically pick it up at JVM startup.
Relative Path is also ok:
java -Dlog4j.configuration=file:".\log4j.properties" -jar com.your-1.0-SNAPSHOT.jar
or
java -Dlog4j.configuration=file:".\log4j.xml" -jar com.your-1.0-SNAPSHOT.jar
If you are using gradle. You can apply 'aplication' plugin and use the following command
applicationDefaultJvmArgs = [
"-Dlog4j.configurationFile=your.xml",
]
According to the page (Log4j2 - Automatic Configuration) Log4j2 needs:
-Dlog4j2.configurationFile=<path to file>
Log4j will inspect the "log4j2.configurationFile" system property and, if set, will attempt to load the configuration using the ConfigurationFactory that matches the file extension. Note that this is not restricted to a location on the local file system and may contain a URL.
Taken from: Log4j2 - Automatic Configuration
I used this two commands below with weblogic 12 and it works for log4j2.xml
-Dlog4j.configurationFile=<path to file>
-Dlog4j2.configurationFile=<path to file>

Categories