How to have separate log4j config for library jar - java

We are developing client library which will be distributed as jar to other user application who will in turn create runnable application.
The problem is we want to setup log4j separately for this jar so that issues can be logged correctly. As this is library we can not assume user will always use log4j they might use some other logging framework or may not initialize log4j as we want. In short we want to configure log4j separately for our library jar. Please suggest way to do this.

Related

Detect logging framework when writing Java Library

I'm writing a java library which will be used by some external web applications. Let's assume that each application can use different logging system, say App A uses slf4j over log4j and App B: uses log4j2 over logback (Log4j2 -> slf4j -> logback) or just plain logback.
Now I would like to use current logging framework to log some messages from the library.
Which way I can detect logging system which is currently used by the client?
How to dynamically log to detected logging system?
I did something like that before by detecting if particular classes (typical to slf4j) are on classpath and than used some "loggingService" which was logging directly to slf4j. I'm wondering if this is correct approach or how else this can be tackled?
The normal way is to pick your logging API and have the application that uses your library provide an implementation for it (which can be just a bridge to whatever backend will actually be used).
For example, your library would build against slf4j-api. If the app wants to use Log4J, it would provide a) Log4J and b) a bridge from SLF4J to Log4J (so that you can log via SLF4J and it still ends up in Log4J).
Do not try to detect anything.
say App A uses slf4j over log4j and App B: uses log4j2 over logback
In the above example, App A is already set up to consume your library (because it provides slf4j-api), and App B is also ready (because it provides logback, which happens to also bring in slf4j-api). If App B used log4j2 over j.u.l, it would need to also pull in a bridge from sfl4j to j.u.l).
In general, there will be only one logging backend (decided and configured by the application), but there can be many logging API (so that all libraries that you need can have the one they like) that pipe into it.
The only reason code would ever want to detect and talk directly to the logging backend is if you need to programmatically configure it. Usually only application bootstrap code needs to do that (if at all). For the actual logging, you just talk to the API (of your choice).

Getting the Log4j settings from a custom properties file

I am working on a huge application which uses its on property file to set the global variables. I want to use the same one for setting the properties of Log4j log file instead of log4j.properties file due to some problems. How do I do this? Is there any way to set the properties of Log4j at run time?
If you just want to rename your log4j.properties file you can do this using a System Variable in your JVM startup (refer link)
-Dlog4j.configuration=test.properties
The Log4j API also allows configuration changes to the Loggers from within an application. Theoretically you could read your own property file and call the appropriate API calls. I'm not sure this approach is recommended - you might end up spending a lot of time getting it working that you could better use developing your application functionality.
Note: I dont know the nature of the huge application, but it if its running in an application server such as JBoss they often have their own dynamic logging configuration

Log4j Properties in a Custom Place

I'm using Apache Commons Logging and SLF4J with log4j, but I also want to use the log4j.properties in a custom place like conf/log4.properties. Here is the problem:
If i use
PropertyConfigurator.configure("conf/log4j.properties");
then my app is tied to log4j and defeats the purpose of having ACL and SLF4J.
What is the best way to configure it without the app ever knowing what the logging implementation is?
I think the easiest thing to do is specify the location of the file using the log4j.configuration system property. Adopting the example in the Log4J manual:
java -Dlog4j.configuration=conf/log4j.properties -classpath ...
I believe that Log4J will find a file named "log4j.properties" anywhere on the classpath, but may be hallucinating. Worth trying, however.
As you state, by invoking PropertiesConfigurator, you are tying your application to log4j. However, the extend of this tie is quite limited. You could very easily remove the line invoking PropertiesConfigurator and recompile your code. After that is done, assuming you are using the SLF4J API for logging, you could repalce log4j with another logging framework, say logback-classic or j.u.l. just by replacing jar files. Thus, SLF4J still serves its purpose to a large extend. I would not throw the baby out with the bath water.
You can specify config file location with VM argument
-Dlog4j.configuration="file:/C:/workspace3/local/log4j.properties"

3rd party jars creating log files

So we ran into an interesting issue today. We have a Java EE web app that uses a bunch of 3rd party jars. This includes Hibernate.
We use the Java logging api that comes with the SDK for logging purposes. Typically we are pretty thin on logging but we ran into this issue with one of our 3rd party jars using log4j to create it's own log file. Not only was it logging statements from it's own code, it even started writing out debugs for the hibernate code which resulted in a batch job logging 3 GB worth of logs in no time.
I have 2 issues with this:
I need to fix this logging issue (If possible I do not wish to yank out or modify the log4j config in the 3rd party jar). Is there a good way to do this besides modifying or yanking out the log4j config in the 3rd party jar OR by having my own log4j config that overrides the config in the 3rd party jar? I do not like either of the 2 options but I want to do what's best.
I want to ask if it is kosher to expect 3rd party libraries to be logging away merrily? I think this is bad design. I want to get the community's opinion on this.
I want the 3rd party libraries logging ERROR's. That being said I think it is slightly awkward that this 3rd party jar to log DEBUG's from packages other than the ones it is responsible for. e.g. in my case, this 3rd party jar is logging Hibernate debugs even though it does not even call any hibernate methods. The batch job that we ran did not even call the API in this jar. It looks like having my own log4j config override what's in there seems to be the best way to go.
From what I remember you just need to provide your own log4j properties file on the classpath before your JARs that are doing the logging, and this one will be picked up. Digging back to the depths of memory, Hibernate at least picks this up from the root of its JAR, so you don't need to package your properties.
As a wider issue, yes I definitely want my libraries logging - otherwise how do you know if something has gone wrong if there's no log?
If they are using log4j or another commonly used logging framework, you can override its configuration by providing another lo4j.properties earlier on the classpath. 3rd party logging is in my opinion a good thing as long as you can easily configure the logging level that you want, which is the case if they use log4j. It's always easier to configure a logging system to output less information than to instrument 3rd party code to add logging to it !

Strategies for logging to application logs from library code?

Where I work we use Log4j for web application logging. The log4j.jar is at the application level, not the container level. We're using a daily rolling file appender. Our log4j.properties files define appenders based on the app package name, so only classes in our application's package and below get logged to our app's log file.
In my application, I'm extending our framework with some supporting classes. These classes are not in the application's package, as they are not exclusive to my application and will eventually be made into a jar library for use with other applications. Because of this, my logging statements are not picked up by my application's appender, and are thus not logged to my application's log files.
I want to allow the classes in my jar to log to the log file of the application using the classes. However, if I create an appender in my application's log4j properties file based on my classnames, I suspect that when multiple applications are using my jar, because of the identical class names in the log4j.properties files, only one application log file will receive my jar's logging statements, and that it will receive ALL the logging statements from EVERY application using that jar. I think this is the case, since we're using a static Logger.getLogger() call to retrieve the logger.
I first want to know if my fears are valid, if this is really what would happen when multiple web applications in the same or different containers are using my jar simultaneously.
I'd also like to know if there are "boundaries" on which this behavior changes. For example, does this problem exist regardless of whether log4j.jar is a container-level jar or an app-level jar, or if each container is running in a separate JVM?
Lastly, if this IS the case, I'd like to know what strategies I should use to overcome the problem.
Thanks in advance!
If log4j.jar is only in the web-app then the logs will stay separate so each web-app should have its own log4j.jar and log4j.properties so that all logs stay separate.
The problem is that the preffered pattern for log4j is to use static *Configurator methods, which don't go very well with application containers.
This article solved this problem for me when i came across it ...

Categories