Dynamic setting of Log4j level across multiple JVMs - java

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);

Related

What's the best approach in jar/library creation?

I need to create jar/library that does some stuff and writes some logs. For logs I was thinking about java.util.logging.Logger vs Logback. So the question is:
Should I prefer using java out-of-the-box logging or it's totally fine to include some third-party tools?
Or it should be purely the matter of my needs and which one to use doesn't really matter?
Use a facade, like slf4j. Think of it from the point of view of the person using your jar in their application. They will want all the logging going to one place, whether it is logging for your jar or for the rest of the application, they will not want to configure your library's logging separately.
Using a logging facade means your library writes to whatever log the rest of the application uses. The application should be in charge of logging, not your jar.
For which facade to use, slf4j seems like a better choice, commons logging can get in trouble where multiple classloaders are involved. See Difference between Simple Logging Facade for Java and Apache Commons Logging
One can use System.Logger
System.Logger instances log messages that will be routed to the underlying logging framework the LoggerFinder uses. System.Logger instances are typically obtained from the System class, by calling System.getLogger(loggerName) or System.getLogger(loggerName, bundle).
Loggers across libraries always were a pain. Java.util.logging incorporated Logging into the Standard Edition. Since Java 9 there is a Standard Edition way to integrate loggers.
This leaves the choice to the library user. No longer a mix, version blues, etcetera. The exact logger in a straight application could be java util Logger.

Creating Custom LoggingContext (Logging Separation)

I've been experimenting with different logging frameworks for use in a Java library I've been developing. I'd like to separate the logging configuration of the library from logging done by users implementing the library. I want users of my library to be able to specify their own LOG2J2 configuration and log their own information without it having ANY effect on the logging configuration of the library. The best way I can see to accomplish this is to have the library create and use it's own LoggerContext. I have two questions: Is it possible to create and use a special LoggerContext specifically for my library or is there perhaps an easier way to accomplish what I'm trying to do? Once I've created a LoggerContext and applied its configuration is it possible to somehow tie it back to the LogManager so that when I call LogManager.getLogger() from my library it will use my custom LoggerContext?
To try and put it simply, I want to separate the framework logging from the implementation logging. Similar to what is being described here. Unfortunately, that link seems to focus more on Web logging separation rather than application/framework logging separation.

Isn't it possible to configure logging INSIDE the application when using jboss AS 7.1.1.Final?

I read a lot but I couldn't figure out how I could specify for example the log level for specific classes.
Only way I could figure out was in the standalone.xml but why should I configure some application specific setting very general in the server? This complicates the deployment process unnecessary.
Isn't it somehow possible to define the specific log level and the output files somewhere inside the war without touching the server?
Btw. it doesn't matter if log4j or commons-logging or slf4j or whatever is used.
Using a logging.properties file or a log4j configuration file in your deployment will work in JBoss EAP 6.x and WildFly (formerly JBoss AS). Note though that a log4j configuration would only work if you use log4j for your logging facade.
That said I agree with Marko that this should probably be done in the server configuration. I would also encourage you to use the CLI or web interface rather than editing the raw XML as well. You can get some more information on the documentation.
I am sorry for not providing a direct answer, but consider this: the application being in charge of logging levels is a bad idea most of the time as this is something an AS admin should be able to change at any time. For example, the point of the DEBUG or TRACE log levels is to be able to place a lot of such statements in the code without hurting the production server's performance. However, once a bug is detected, you want to be able to lower the logging level without rebuilding the application. This should be a purely administrative task.
On the other hand, I do recognize the need to at least have a decent starting point for the logging configuration and I don't know of any architecture which would allow the application to provide defaults which are overridable by the server configuration.

Pros & cons of configuring logging at server-level vs application-level

Configuring logging in java can sometimes be tricky (due to the multiple existing logging APIs) and can be done at different levels (server, application, both?). So what are the pros and cons to configure logging at those levels?
I came with this list but I would like others to share their experience:
Server-level
Pros
Centralized configuration
Application must not be modified prior to deployment
Can log to resources managed by the server (files relative to server path, DB...)
Cons
Must be sure each application uses the same logging api
Configuration can grow big as more applications are deployed
Server knows maybe too much about categories=>logging-level mapping for each application
Application-level
Pros
Application may use the logging api of its choice
Application can configure its own logging-levels
Cons
Configuration must be edited prior to deployment in order to specify path to logfiles (if relative to server) or JNDI name of the logdatabase
Is there a way to combine the two to keep only pros? Like configuring loggers at the server-level and then categories=>logging-level mapping at the application-level?
Is there a way to combine the two to keep only pros? Like configuring loggers at the server-level and then categories=>logging-level mapping at the application-level?
To answer this question I would say, Yes, we can do. But in this case your server and applications have to follow a proper design and in the negative side all the application might become tightly coupled.
If your apps are java based then, you can actually make a single logger file for all applications and there you have to set the application logger level, provided your applications follow different package structures.
Suppose app1 follows package structure com.app1.. and app2 follow com.app2.., then you can modify logger level like below,
*.*.com.app1 = logger_level1
*.*.com.app2 = logger_level2
But if your app2 is dependent on app1, or it has package like this com.app1.app2.* or some common package names, then you might have define more on the logger properties, so the package structure and design is very much important to follow single logging mechanism.

LOG4J as a singleton, anyway to avoid log4j logging conflicts in web environment

We have a j2ee web environment. The server is configured to share session and possibly classloaders across multiple webapps. Basically, one classloader could server multiple web apps.
This seems to cause issues with log4j. Different webapps could have different log4j configurations but the logging will move to the same file.
Reading online, it looks like log4j uses singletons a lot, in terms of the appenders and other functionality.
Is there a way to completely separate the log4j configurations from one webapp from the other.
Server: websphere6+
Log4j: 1.4.2
Java: 1.5
Example log4j.properties (webapp1):
log4j.appender.R=org.apache.log4j.RollingFileAppender
log4j.appender.R.File=/usr/local/file1.log
log4j.additivity.com.app=false
Example log4j.properties (webapp2):
log4j.appender.Z=org.apache.log4j.RollingFileAppender
log4j.appender.Z.File=/usr/local/file2.log
log4j.additivity.com.app=false
Right now, logging from webapp2 may appear in the webapp1 logs and vice verse. We don't want that.
Possible Solution:
It might be possible to add a custom file appender? Would that fix the issue and what code would I add to the custom appender?
Is it possible to change the log4j initialization. E.g., could I use some startup servlet to load logj4 for each webapp.
You have two ways to solve your problem:
Configure your app. server so it doesn't share classloaders across multiple webapps. When it does do that, because of log4j's nature, only one log4j.properties file will be loaded.
If you leave the app. server so it shares classloaders, then use one "master" log4j.properties file. In it, define appenders for root of every one of your applications (example com.mycompany.webapp1, com.mycompany.webapp2)
No solution is perfect. Particularly, the second one will be problematic if your web apps share some classes that use log4j. In that case, logs from both apps will end up in the same file.
Your problem is a common one. To understand more about this topic, google for "log4j and j2ee".
Edit: since solutions 1 and 2 aren't feasible, you could try something else:
Use log4j.properties file per application. In every one of them, define an appender for their root (as explained in solution 2), and set additivity to false. This also won't be perfect if there is any class sharing between them.
Configure log4j programatically for every application. Since they're legacy applications, this could be tough. One way to do it is to use ServletContextListener for every application and configure log4j on application startup. I haven't personally tried this, so I'm not 100% sure if there will be clashes due to shared classloaders.
Log4j won't be really updated anymore. Ceki Gülcü, who created log4j, stated that he will focus his efforts on slf4j and logback, to correct some mistakes he did during development of log4j.

Categories

Resources