I'm using slf4j and log4j2 combination as logging framework in my application. To redirect logs of java.util.logging into slf4j, I'm using jul-to-slf4j. I also have to execute :
static {
LogManager.getLogManager().reset();
SLF4JBridgeHandler.install();
}
the above to register the handler to make this work and it is working fine. But I would like to avoid this static block if it possible to do the same handler register by using log4j2.xml file configuration. I spent much time to find the xml configuration but could not found it.
If you are not running the code in a servlet container like Tomcat you can simply add the -Djava.util.logging.manager=org.apache.logging.log4j.jul.LogManager to the launch command.
Otherwise should be able to use a logging.properties file with contents:
handlers=org.slf4j.bridge.SLF4JBridgeHandler
org.apache.logging.log4j.jul.Log4jBridgeHandler.propagateLevels = true
Then launch the application with -Djava.util.logging.config.file=logging.properties. You'll have to adjust the path to the logging.properties
Related
the log file is generated when I run the code within IDE (Intellij IDEA).
as soon as I create runnable jar of the code and then try to run the jar then the logs are not generating.
I have made sure the log4j2.xml file is a part of classpath.
is there anything extra I have to do while creating jar in the Intellij IDEA?
Taken from the FAQ: How do I debug my configuration?
First, make sure you have the right jar files on your classpath. You need at least log4j-api and log4j-core.
Next, check the name of your configuration file. By default, log4j2 will look for a configuration file named log4j2.xml on the classpath. Note the “2” in the file name! (See the configuration manual page for more details.)
From log4j-2.9 onward
From log4j-2.9 onward, log4j2 will print all internal logging to the console if system property log4j2.debug is either defined empty or its value equals to true (ignoring case).
Prior to log4j-2.9
Prior to log4j-2.9, there are two places where internal logging can be controlled:
If the configuration file is found correctly, log4j2 internal status logging can be controlled by setting in the configuration file. This will display detailed log4j2-internal log statements on the console about what happens during the configuration process. This may be useful to trouble-shoot configuration issues. By default the status logger level is WARN, so you only see notifications when there is a problem.
If the configuration file is not found correctly, you can still enable log4j2 internal status logging by setting system property -Dorg.apache.logging.log4j.simplelog.StatusLogger.level=TRACE.
I placed a default log4j2 config file (log4j2.xml) in my application jar.
If the user doesn't define a own config file, I want to load my default config.
I could get a stream of the default config this way:
InputStream defaultConfigStream = MyApp.class.getClassLoader().getResourceAsStream("log4j2.xml");
But that won't help me, because following code takes a full path to the config file to check its existance and to load it.
System.setProperty("log4j.configurationFile", file.toUri().toURL().toString());
How can I accomplish that? I don't want to hardcode my default config settings, like here.
Use a DomConfigurator, see: https://logging.apache.org/log4j/1.2/apidocs/org/apache/log4j/xml/DOMConfigurator.html, you can parse the XML and feed it to the configurator and when initializing logger it will automatically consider the configuration
As I found out, it's pretty simple. Like described in the documentation (point 7), Log4j2 will automatically look for a log4j2.xml on the classpath.
So if the user doesn't define a own config file, I don't call any method to load my default config.
Is it possible to have conditions in log4j.properties. I have a situation where I want to have logging level set to Info on production environment and DEBUG on local. Is it possible to read environment variables in log4j.properties.
No, you have to have 2 different log4j.properties file
Configuring logging is something that should happen as part of the deployment, not as part of the build, i.e. you should NOT create multiple builds for different log configurations, the risk of introducing also other differences in artifacts is to big.
Create ONE build containing a default configuration, possibly the one you want to use in production.
Implement a way to find and use an alternative configuration without changing your artifact. Most of the time this is achieved by adding an additional directory to the classpath of your application and store a log4j configuration there. You can use the default initialization of log4j by using a configuration format that has higher precedence then the one contained in the artifact. This also allows you to reconfigure logging without new deployment, which can be very helpful when troubleshooting.
Alternatively you can provide the location of the configuration file to use via a environment variable at startup: -Dlog4j.configuration=log4j-prod.xml (borrowed from Keerthi Ramanathan's answer)
You can prepare different builds and decide which log4j.propeties you want to include on build time, for example using maven params, profiles or any other way.
There is no way to declare condition in log4j.properties
No.
But just to outline some other options
a) I would encourage you to have a look at logback which provides a simple facade over log4j and you can then change your config at runtime. The relevant documentation can be found here.
b) If you have a build process in place (ant/maven) you can do the replacement as part of the build process. If you use maven you can set up a profile to build and the in the build-cycle apply filtering
c) Load the log4j files from a conf directory for each environment. The idea for that is that the files once set for an environment are changed minimally over time. You maintain both in your repository and as part of your deployment process ensure that additional/deleted files/props get added/removed.
What i would suggest as said in comment, have a separate version of log4j properties file for every environment and follow the naming convention for easy maintainance. say, for dev environment, it would be log4j-dev.xml and for production, log4j-prod.xml. Now, you can configure the appropriate file to pick up during runtime using
-Dlog4j.configuration=log4j-prod.xml
during server startup. so, that appropriate conffiguration file will be taken by log4j.
You can use programmatic configuration when using log4j, which gives you more control over what options to use in what environment. You can have your own configuration files and use your own logic to convert them into a log4j configuration. The downside is that you need to do init() somewhere in your application. This answer provides good reference.
I used a this approach when I had similar question. A default log level if nothing is explicitly specified, and option to override.
So, I added a log4j.properties file in application resources.
log4j.rootLogger=ALL, stdout
...
log4j.appender.stdout.Threshold=INFO
...
And then added more log config properties (log4j-n.properties, for n in {d, i, w, e}) defining log levels at debug, info, warning and error. Now, during startup I would supply the config file explicitly if I wanted to override the default.
java ... -Dlog4j.configuration=file:///<path>/log4j-n.properties ...
This would override any config I had in the default log4j.properties.
Later I went with this approach. I removed all the extra config files. In the log4j.properties file in resources, I used a JVM arg placeholder:
log4j.appender.stdout.Threshold=${app.log.level}
And supplied that as JVM argument.
java ... -Dapp.log.level=<LOG-LEVEL> ...
Voila!
I created a dynamic web project using IBM Rational Application Developer (RAD). I used java.util.logging as the logging framework. I put the logging.properties in WEB-INF/classes directly.
The problem which I am facing is, the application could not load the logging.properties even I put it in the WEB-INF/classes. I add the following generic JVM arguments in the WebSphere Application Server Administrator's Console
-Djava.util.logging.config.file="logging.properties"
I add the following code snippet in the servlet init method.
Properties prop = System.getProperties();
prop.setProperty("java.util.logging.config.file", "logging.properties");
System.out.println("Is file exists " + file.exists());
try {
LogManager.getLogManager().readConfiguration();
} catch (IOException ex) {
ex.printStackTrace();
}
I off the console level debug in logging.properties, so I should not get the logging in console. But currently I am getting the logs in console not in log files which I mentioned in logging.properits.
logging.properties
#------------------------------------------
# Handlers
#-----------------------------------------
handlers=java.util.logging.ConsoleHandler,java.util.logging.FileHandler
# Default global logging level
.level=ALL
# ConsoleHandler
java.util.logging.ConsoleHandler.level=OFF
java.util.logging.ConsoleHandler.formatter=java.util.logging.SimpleFormatter
# FileHandler
java.util.logging.FileHandler.level=FINE
# Naming style for the output file:
java.util.logging.FileHandler.pattern=${SERVER_LOG_ROOT}/nyllogs/loadData.log
# Name of the character set encoding to use
java.util.logging.FileHandler.encoding=UTF8
# Limiting size of output file in bytes:
java.util.logging.FileHandler.limit=25000000
# Number of output files to cycle through
java.util.logging.FileHandler.count=2
# Style of output (Simple or XML):
java.util.logging.FileHandler.formatter=java.util.logging.SimpleFormatter
Please let me know why the application couldnt pick up the logging.properties file?
In a WebSphere server, the effect of what you are trying to do would be to change the logging configuration not only of the application, but the entire server. Since WebSphere itself uses java.util.logging, this would mean that everything that is logged internally by WebSphere goes to the same file as the application logs. That would be pointless because then you may as well use the standard WebSphere log files (SystemOut.log and trace.log).
In addition, since WebSphere installs its own LogHandler, it is likely that it will forbid usage of the readConfiguration() method.
Read the configuration from an inputstream using readConfiguration(is). Your code sets a property with relative path but the JVM cannot look into it.
Properties prop = System.getProperties();
prop.setProperty("java.util.logging.config.file", "logging.properties");
Calling the readConfiguration() method without arguments only reloads the properties, which may not be loaded since your path is relative.
public void readConfiguration()
throws IOException,SecurityException
Reinitialize the logging properties and reread the logging configuration.
Use an absolute path for the property or pass an Inputstream. Here's an example loading the properties from a file and using an InputStream.
I have a common jar that multiple web applications are using. All the web applications are using log4j. Each has their own log4j xml configuration file that are basically the same. I would like to put a common log4j configuration in the included jar file and in each individual web project, in that log4j configuration, I would like to be able to simply refer to the one in the jar file.
I'm not seeing anything in the documentation that explicitly says this is possible. I'm wondering if I might just remove the configuration file from the web projects and stick it in the common jar if it would get loaded automatically since it is on the class path?
In the end, I would like the ability to adjust logging on a particular application for debugging and troubleshooting without modifying the common configuration in the jar file.
I was on a project where I needed to manage dozens of web applications. Each of the apps were logging slightly differently and it was a pretty big pain to manage. I used a strategy similar to what you are describing to standardize on log4j and it has worked out pretty well.
Basically, I created a single common.jar which contains shared code. This jar contains a log4j.xml that sets log level to INFO and sets the default appender to stdout for common.jar. This log4j config is used as the baseline for all other apps.
For this example, pretend this class is inside common.jar:
public class ThirdPartyLib
{
protected static final Logger log = LogManager.getLogger("third-party-lib");
public void doSomething()
{
log.debug("Third Party App is about to Do something!");
log.info("Third Party App just did something");
}
}
Now, all other web applications can simply depend on common.jar. For example, pretend this class is inside myapp.war:
public class MyApp
{
public void CallThirdParty()
{
ThirdPartyLib lib = new ThirdPartyLib();
lib.doSomething();
}
}
Since log4j.xml is inside common.jar, this code will log something like this. In other words, there's no need to put log4j.xml inside myapp.war:
2011-01-03 15:49:22,451 [main] INFO third-party-lib - Third Party App just did something
Now, if you want/need to control logging in myapp.war, then simply place a log4j.xml inside myapp.war and override settings from common.jar. For example, you might set the level to DEBUG, and then you'll see:
2011-01-03 16:03:22,928 [main] DEBUG third-party-lib - Third Party App is about to Do something!
2011-01-03 16:03:22,928 [main] INFO third-party-lib - Third Party App just did something
UPDATE - Is it possible to configure each webapp to log to separate file?
Yes, definitely. For example, you can direct logs to a RollingFileAppender instead of stdout inside log4j.xml for myapp.war. This is handy because then you can have each individual webapp log to it's own separate file.
In addition, I wrote a servlet filter (similar to what gigadot suggested) which configures log4j to check for whether a log4j.xml exists at an external path (outside of each webapp's war). This way, the log4j.xml files are accessible outside the wars and we're able to set log levels without restarting the servlet container (tomcat, in this case). If the external log4j.xml doesn't exist, it defaults to use the log4j.xml on each apps classpath.
If you have multiple jar/war files, each file have its own log4j.xml and you don't want to worry about which log4j.xml get loaded, you can explicitly load the configuration yourself.
For a webapp project, put the following context listener as the first listener in your web.xml This will load log4j from your path of preferrence.
<listener>
<listener-class>mycompany.server.listener.Log4JInitServletContextListener</listener-class>
</listener>
Implementation of Log4JInitServletContextListener.
Note: if you have multiple log4j.xml in the same path (which is possible for multiple jar files), it will be confusing which one gets loaded. So try to have a unique package name for the configuration resource in your common jar.
As you can see, you can use this method to programatically load log4j.xml depending on condition too.
package mycompany.server.listener;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import org.apache.log4j.xml.DOMConfigurator;
public class Log4JInitServletContextListener implements ServletContextListener {
#Override
public void contextInitialized(ServletContextEvent sce) {
org.w3c.dom.Element log4jConfigElement = parseFromInputStream(getClass().getResourceAsStream("/unique/package/name/in/common/jar/log4j.xml"););
DOMConfigurator.configure(log4jConfigElement);
}
// omit the rest and implementation of parseFromInputStream method
}
i am not sure that can help but you can set property file location like this,
java -Dlog4j.configuration=jar:file:/full/path/to/app.jar!/log4j.properties -jar app.jar