Single Log4j between Tomcat6 webapps - log4j

Is there a correct way to use Log4j logger with Common ClassLoader, not with Web-App based ClassLoader, i.e. use only one log4j.jar for all deployed web-apps?
When i'm drop a log4j.jar in commons lib directory, log4j get a first loj4j.properties for any application and use only it. All other loj4j.properties (of other applications) are ignored. Is there way to say log4j to return separate log factory for every application with their properties?

Not in the way I think you mean, because each webapp's loggers should be completely independent of loggers in other webapps. Because logging repositories are singletons, this can only be done if they are handled by separate Classloaders, i.e. the webapp class loaders.
Also note that in general (though it may not be the case for you), different webapps have different lifecycles, which means that Tomcat may have to support webapp A using one version of log4j at the same time as webapp B, which uses a different version of log4j.

Related

alternative to PoolingOptions, any suggestions?

Migrating from cassandra-driver-core(3.4.0) to java-driver-core (4.14.1) don't find an alternative to PoolingOptions class in new version, does anybody has implemented the same earlier or any suggestions?
Java driver is now driven by the configuration file - you can override default configurations with your own stuff either with additional config file, or programmatically (see manual). For pools there is a separate section called pool under datastax-java-driver.advanced.connection (source) where you can customize size of the pool, number of inflight requests, etc.

How to set system properties dynamically via java code in tomcat 8 (not through the tomcat configuration files)

I have gone through the solution provided by peter for setting system properties dynamically in multithreading with the below link
System.setProperty used by a thread impacts other thread in communication to external network elements. How to resolve it?
But the problem is, tomcat is not considering the system properties that i am setting. So how to achieve this ?
I have mutiple threads in a management station connecting to different servers through RMI APIs and download the stub accordingly.
I am referring to the same name jar file as a stub at different locations for each server.
note: jar versions may differ at each location.
Eg: MS --> serv1 --> stublocation (http://15.xx.xx.xx:port/myfolder/myapp.jar)
MS --> serv2 --> stublocation (http://15.yy.yy.yy:port/myfolder/myapp.jar)
I want to set java.rmi.server.codebase system property for each of these locations dynamically and make it threadLocal so that it will not override each other settings.
With the example provided in the above link, I hope to achieve the solution for above problem.
But to test the resolution, i am unable to set these properties in tomcat.
Tomcat is ignoring the system properties that i am setting. Tomcat is considering the JVM arguments that are set through catalina.bat or service.bat but not through the system.properties as i need it to be dynamically set.
Any help here will be great! Thanks.
The java.rmi.server.codebase property is set at the JVM which exports remote objects. Setting it in a client JVM accomplishes exactly nothing, unless that JVM exports remote objects too, i.e. callbacks. It doesn't seem likely that you will be dealing with multiple versions of your own application within the same JVM.
In short, your question doesn't make sense.
As EJP points out, (successfully) setting that property is unlikely to achieve what you want.
But there are a couple of other important misconceptions in your question.
Tomcat doesn't implement RMI. RMI is actually implemented by the Java SE itself. Therefore, it is not up to Tomcat to pay attention to those property settings.
Typical Java services that use system properties for configuration purposes do it once during the lifetime of the JVM. Typically this happens when the relevant subsystem (e.g. RMI) initializes. The problem with setting system properties programmatically ("dynamically") is ensuring that they are set before the relevant initialization code uses them.
Going back to what you are trying to achieve, it seems that it is the same as or similar to this:
Java custom classloading and RMI
Nobody was able to help that person, and he ended up solving his problem another way. (I think he is saying that he handled serialVerionId mismatches with customized readObject / writeObject methods ...)
But his Q&A offers one possible way to solve the problem. It is a bit complicated.
The RMI system allows you to provide your own classloader for RMI to use. You do this by implementing the RMIClassLoaderSpi API and then registering your providers as described in the RMIClassLoader javadoc. That's one part of the equation.
The problem is that the RMI classloader is global, but you want RMI on different threads to use different class loaders.
Solution: delegate!
You implement your custom RMI classloader to delegate to one of a number of different classloaders, depending on which versions of the remote APIs that the context requires.
Since you have proposed using thread locals, you can declare a thread local variable for use by the custom RMI classloader, and have it use that variable's value to decide which classloader to delegate to.
CAVEAT ... I have not tried this!

How to obtain all log4net loggers currently running in all processes

Each process in our system uses log4net. Many of those processes are stared up as services. Some of those running applications are very verbose spewing debug entries and we'd like the ability to limit their output. All loggers use the same .config file to set their current logging level. I'm working on an app that will gain access to all loggers that set the source using
log4net.GlobalContext.Properties["source"] = source;
What I'd like to do is get a list of all loggers currently registered, obtain their source name and then change the .config file for each of those sources to individually configure the output level for each of them.
The problem I'm having is finding the list of all those loggers so I may add an entry in the .config file. Is there a way to do obtain that list of loggers across all processes from a single application?
I've tried using GetRepository().GetCurrentLoggers(), but that only returns the logger for the currently calling application.
There is no standard way of getting loggers which are in an other process. You have to make something your self.
Try this
using log4net.Repository.Hierarchy;
var appenders = ((Hierarchy)LogManager.GetRepository())
.Root.Appenders;

How to configure log4net for fallback

This is my situation. I have successfully implemented logging to remote syslog using log4net. However, as far as I could test, if syslog IP is not valid, all messages will not log anywhere and no exception is raised. It just does nothing.
Hence, it would be nice to have some sort of fallback. Let's say if writing to syslog fails, write to file or to database.
Is that even possible with log4net? Or would I have to configure it to log to two locations at the same time?
I don't think you can do this by configuration. This issue is open in the log4net feature backlog.
If your application can eat the logging overhead, the easiest solution would be to log to an alternative appender by default.
Alternatively you could try to wrap the appender you're using in a custom appender, and implement the fallback scenario if the syslog appender throws an exception. If it doesn't swallow them silently.
From log4net FAQ:
You can implement the log4net.Appender.IAppender interface to create you own customized appender. We recommend that you extend the log4net.Appender.AppenderSkeleton class rather than starting from scratch. You should implement your custom code in a assembly separate from the log4net assembly.
To get started it is worth looking at the source of the log4net.Appender.TraceAppender as an example of the minimum amount of code required to get an appender working.
Third option would be to look into the source code of your appender and see if you can fork it and do the necessary customizations there.

Log4Net GetLogger creates rolling files even for the unreferenced files

I have a C# solution that contains three executables. I have each of these three executables sharing the same log4net configuration file. At startup of each of the executable, they retrieve a logger (one logger per executable, as per configuration file further below). When one of the executable performs Log.GetLogger(), it creates all the rolling files instead of only the one rolling file that is referred to as appender-ref in the executable's logger configuration.
For instance, when I startup my sending daemon executable, it performs Log.GetLogger("SendingDaemonLogger") which creates 3 files Log/RuleScheduler.txt, Log/NotificationGenerator.txt and Log/NotificationSender.txt instead of only the desired Log/NotificationSender.txt.
Then when I startup another of the executables, for instance the rule scheduler daemon, this other process cannot write in Log/RuleScheduler.txt because it has been created and locked by the sending daemon process.
I am guessing that there may be three different solutions to my problem:
The GetLogger should only create the rolling file appenders that are referenced in the config
I should have one config file per executable, this way each config file could list only one rolling file appender and starting each of the executable would not create the rolling files of the other daemons. I am however reluctant to do this because some of the configuration (SMTP appender, console appender) is shared between the daemons and I don't want to have duplicate copies to maintain. Unless there is a way to have a config file including another one?
Maybe there is a way to configure the rolling file so that concurrent access across processes is allowed? This solution still isn't perfect in my opinion because any of the daemons should not be creating the rolling files of some other daemons.
Thanks in advance for your help!
I have difficulties for posting the config file properly here (this website interprets as HTML). Please go to the following link for seeing my log4net configuration file:
log4Net configuration file
Better late than never...
Use the following filename definition for an file appender.
The %appdomain will be replaced on startup with the appdomains friendly name.
Now you can use the exact same configuration file for multiple apps and still have separate logfiles. No need to configure multiple appenders...
<file type="log4net.Util.PatternString" value="C:\logs\%appdomain.log" />
see PatternString documentation for available patterns.
I think that all 3 files are created for the reason given in this answer. Though you could write your own appender that does not show this behavior it is not advisable. This leaves you with either having 3 separate config files or configuring minimal locking:
<lockingModel type="log4net.Appender.FileAppender+MinimalLock" />
I have no experience with the latter so I cannot tell you how good this works. I would probably go for the three separate config files.

Resources