How to set contextName of log4j2 Mbean - java

While accessing log4j2 Mbeans using jvisualvm, I see that the type (contextName) inside log4j2 package is a number (for me it is 1482868390). Since this goes in as 'type' while specifying Object in query, I would like to specify it to a more recognizable name that I prefer. Is there a way to set the contextName in xml configuration.
I think there is a way to do it for web applications, but I would like to set this for a standalone java application.

Yes this is possible but not in configuration. You can achieve this by subclassing one of Log4j's ContextSelectors and overriding its defaultContextName() method.
You then tell Log4j to use your ContextSelector by starting your application with system property -DLog4jContextSelector=com.yourpackage.YourContextSelector.
If you're making all loggers async, you want to subclass AsyncLoggerContextSelector, otherwise ClassLoaderContextSelector.

Related

java.util.logging stops working when I incorporate a library that uses Log4j 2

I have an existing application that logs messages using the java.util.logging API. As far as I can see, there are no configuration files for it in the framework, though there is some code to create a file appender. When I run the application, I get log messages to the console and to a file.
Now, I need to incorporate a library that uses Log4j 2. When I do so, I lose the console logging from the main application (though log messages still get written to the file appender that is created programmatically).
I imagine that, since the file appender is working in the original application, that I can solve my problem by also programmatically creating a console appender in the main application. However, I don't know if that's right or a kludge.
So, my question: is there anything general that I need to know about making java.util.logging and Log4j 2 interoperate? If the original application is not coded properly or according to best practices, I can change it.
Now, I need to incorporate a library that uses Log4j 2. When I do so, I lose the console logging from the main application (though log messages still get written to the file appender that is created programmatically).
The
Log4jBridgeHandler will remove handlers if the install method is called from code. You can always print the log tree to see what handlers are attached or attach a tool like JConsole to inspect the logger tree with and without the 3rd party lib.
I imagine that, since the file appender is working in the original application, that I can solve my problem by also programmatically creating a console appender in the main application. However, I don't know if that's right or a kludge.
Programmatic configuration of the logger tree should be done with the LogManager config option:
A property "config". This property is intended to allow arbitrary configuration code to be run. The property defines a whitespace or comma separated list of class names. A new instance will be created for each named class. The default constructor of each class may execute arbitrary code to update the logging configuration, such as setting logger levels, adding handlers, adding filters, etc.
Create a stand alone named class that just installs the handlers in the constructor.
Set the java.util.logging.config.class system parameter to the name of your class.
Otherwise if you have a logging.properties you set config to your class name.
So, my question: is there anything general that I need to know about making java.util.logging and Log4j 2 interoperate? If the original application is not coded properly or according to best practices, I can change it.
The java.util.logging.LogManager can only see classes on the system class loader. In that case log configuration in code is required to gain access to the correct classloader.
It might be easier to remove all JUL configuration and bridge to Log4j2. You can then leverage the configuration needed through that framework.

Get list of Spring property placeholder and their resolved values

I would like to make all property placeholder and their resolved values of a running Spring (Boot) application available for process monitoring. In the first step this could be just by writing them to the logs or by creating a 'resolved.properties' file similar to the application.pid file.
All properties where property placeholder are used (implicit/explicit) should be considered.
Motivation: It is usually hard during operation to know the values of resolved properties. System properties or command line arguments are "visible" but e.g. hidden default values in the code (like #Value("${timeout:30000}")) are hard to find out. I would like to be able to answer the question "How does the configuration of the running application looks like?" in a generic way that I can use in all of my spring applications.
I know about the Spring Boot Actuator /configprops endpoint, but this only includes #ConfigurationProperties. I would like to get a list of all properties where placeholder are used.
The requirement does not seem to be new (see here or here) but I wonder if there is an appropriate (bootiful) way nowadays.
There is (currently) no way to obtain all the properties in the Environment abstraction. This is intentional as can be read here. This is also why it isn't possible to obtain all the values used for resolution.
The values and resolutions are logged at runtime telling which key was resolved from where at runtime. But that logging is quite verbose and logged each time a StringValueResolver is used.
You might get a partial result by providing your own customized PropertySourcesPlaceholderConfigurer which maintains a collection of resolved key/value pairs. But not every resolution uses the PropertySourcesPlaceholderConfigurer some directly use a StringValueResolver implementation bypassing the PropertySourcesPlaceholderConfigurer.
It doesn't cover all your needs (ie: properties from all files, default values, application arguments, etc.).
I'll still keep the answer for other readers/future reference.
Spring Boot's Actuator /env endpoint
You may use the /env endpoint. It lists a bunch of stuff but it also includes the content of application.properties (near the end):
applicationConfig: [classpath:/application.properties]={myproperty=blah, server.port=8080}

Can I configure Log4j using Tomcat Context Parameters?

I want to be able to log at different levels depending on what server I deploy my Java web application on. For example, on my test server I would like to log at the DEBUG level and on my production server I would like to log at the WARN level. Currently my log4.xml file is located inside of my WAR file. I want to be able to configure the logging level of my web app using Tomcat context parameters. Is this possible?
I have seen that environment variables and system properties can be used. For example, ${catalina.home} gets interpreted. Is this same functionality available for substituting in Tomcat context parameter values?
For example, this would be the log4j.xml snippet:
<level value="${log.level}"
Where log.level is defined in %TOMCAT_HOME%/conf/context.xml:
<Parameter name="log.level" value="DEBUG" />
I have tried the above and it does not seem to work. Google has not turned up anything for me related to using context parameters in log4j configuration files. I found this SO question doing something similar using system properties, but it does not use Tomcat context parameters so it is not quite what I want. Is a context parameter value substitution capability available in log4j configuration? Do I need to explore other options such using an external log4j.xml file?
I don't think that Log4J does this natively. I recall that the Spring Web Framework came with a listener configured via web.xml that might do something a little similar. If you really wanted to, I think you could could grab the code for that and use it to create something that does exactly want you want.
One method I've been using recently for extremely fine-grained control over logging is the log4 appender. It's a little more work than editing your config file, but gives you an incredible amount of flexibility. See my answer here for a quick example on how one of these would be configured.

Dynamic setting of Log4j level across multiple JVMs

I am working in an application has a number of plain vanilla Java components, each of which runs in a separate JVM. All these components use Log4j and there is no option to change to another logging library.
As the title implies, I am looking for an "easy" way to dynamically apply a Log4j logging level across all components/JVMs. By "easy", I mean without rewriting the source code (otherwise, one can use, for instance, an interface to get/set the logging level, and have all classes implement that interface).
There are articles on the web about using JMX (for instance, via the LoggerDynamicBean class (http://logging.apache.org/log4j/1.2/apidocs/org/apache/log4j/jmx/LoggerDynamicMBean.html) of the Log4j distribution.
An interesting such article describes how to implement this using an application server (Tomcat): http://www.devx.com/Java/Article/32359/1954. The application server seems necessary as an implementation of the MBeanServer class, to which all the loggers will be registered by Log4j as MBeans.
Is there any implementation that does this dynamic logging level setting, across multiple JVMs, either via JMX, or via any other means?
Keep it simple. Point all the JVMs to the same log4j configuration file use this to have them reload occasionally.
PropertyConfigurator.configureAndWatch( yourConfigFile, yourReloadInterval);

Pass properties to log4j before it loads

Is there a way to pass data or setting to log4j before it loads and then use that property within the config file.
I was assuming there is a system properties I could use:
log4j.appender.R.File=/usr/local/pfs/logs/${ws.host}/log4j.log
Where ws.host is the property I want to use.
But how can I set that value?
Also, I am in a web environment. How can I know at what point to set the property setting before log4j loads.
The default log4j PropertiesConfigurator supports variable substitution.
http://logging.apache.org/log4j/1.2/apidocs/org/apache/log4j/PropertyConfigurator.html
So, you could pass system properties like this "-DmyProject.logFile="/temp/test.log" to your Java startup, and then in the properties files have "log4j.appender.R.File=${myProject.logFile}".
If working from a web environment, you might want to check out Spring's Log4jConfigListener. It uses a listener (Servlet API 2.4+) to initialization log4j ahead of other components. Even if not using Spring, you should be able to use the source as an example to easily create your own listener.

Categories

Resources