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).
Related
I have written a small java application. The application uses some external packages as cling, javax and weld.
In my code I used java.util.logging but the other packages uses other loggers as sl4j.
Question. Is there a way to take control over the logging environment so all packages logging in a simular way. I would like to have a simple way to change loglevel and log output.
//lg
slf4j is a logging facade behind which different logging frameworks can be used. For example log4j. You just have to throw it in the path. Log4j can then be configured as usual. There should also be a jul bridge if you want to stick with java.util.logging.
I'm new to logging and wanted to use slf4j with log4j2 in a project of mine.
The configuration is using a json file.
I know that you can create a configuration during runtime with a ConfigurationFactory or use a file that will be checked if it has changed every time a log statement is made and a given time (or none) has passed.
My question is regarding the json file. Will i have to write my own class to change that file using a json parser or will slf4j/log4j2 change the file for me somehow? If so how?
I was reading through the documentation and googled, but didn't find the answer.
I hope you can help me out. :)
First write you code against the slf4j API. It's mostly a bunch of interfaces, and you don't want to "pollute" your code with non-slf4j API if you're using the slf4j logging interface.
Then you want to package / run with log4j-slf4j-impl-2.0.jar which adapts the slf4j API to the log4j2 API. Then you can configure your log4j2 system like you would if you never used slf4j.
Do not use the log4j-to-slf4j-2.0.jar, as that is intended to make code written to log to log4j loggers put their logging on the slf4j API, and if slf4j then implements that with a slf4j logger, your logging events will be passed between slf4j and log4j in an endless loop.
---- Editing post to address question, as it would be too much to put in a comment ----
slf4j is a logging suite with three main kinds of components.
A set of "input adapters" that take one logging system and pipe it into the slf4j API.
An slf4j API that doesn't make any assumptions about how logging is implemented.
A set of "output adapters" that take the slf4j API calls and cram them into some "other" logging system.
The input adapters typically have names like "logsystem-to-slf4j-version.jar", and should be used when you want to migrate to slf4j but haven't rewritten your code to stop using the "old" logging interface.
The output adapters typically have names like "logsystem-slf4j-impl-version.jar" and only one should be provided to slf4j at runtime.
Because slf4j is unaware of which logging adapter it might use to actually process the log messages, it is unaware of the configuration capabilities of that logging system.
Even worse, while logging typically has a semi-similar interface for the submission of log messages, they have vastly different interfaces for configuring the handling of such messages.
In short, if slf4j only adapts the handling of log messages, not the handling of configuration (which is vastly different between say System.out.println(...) and log4j)
This means that at best, you can filter your log messages at the slf4j API layer; but, there is no guarantee that they will be presented; because the underlying logging implementation may be configured to filter even more messages, or may be replaced with a "no logging at all" implementation.
Within some bounds it is possible to have log4j2 react on runtime values: With properties (which can grab entries from System config or ThreadContext), it's simple enough to inject some dynamism.
I am reading about logging using java and came across this: enter link description here
It talks about an advantage of slf4j here that:
One can select his logging framework at deployment time ==> The desired logging framework can be plugged in at deployment time by inserting the appropriate jar file (binding) on your class path.
Can someone explain to me why and where we would need this?
You're writing a generic-pupose library, which generates logs using SLF4J.
Company A uses it, and has already configured all its IT infrastructure to use log4J. They're happy that your API can also use log4J to log.
Company B uses it as well, and has already configured all its IT infrastructure to use java util logging. They're happy that your API can also use java util logging to log.
Company C uses it as well, and has already configured all its IT infrastructure to use logback. They're happy that your API can also use logback to log.
I can think of the following scenario:
Websphere uses JCL logging, if also using JCL, then you can set/modify log levels and filters at runtime.
Appserver X is more geared towards Log4J, so might be better to use that...
With SLF4J you don't need to refactor the code for the underlying logging framework to use...
I've using SLF4j as my logging framework, backed by log4j. My problem is that I am looking for a way to change the logging level for my logger at runtime.
I understand that slf4j does not permit this directly through its own API, and hence, I have to access the logging provider directly. Personally, I find this to be a huge deficiency in slf4j. So now my question is how can I determine programatically through slf4j which provider I am using? The biggest purpose of using slf4j is that you become provider agnostic - you can easily switch between your favourite logging system without having to recode anything. But now, if I have to make direct calls to log4j, I am losing that ability.
At the very least, I would like to be able to determine if I am using log4j as the provider and if so, then allow the user to switch log levels.
If I do LoggerFactory.getLogger(Logger.ROOT_LOGGER_NAME), the result is an instance of org.slf4j.impl.Log4jLoggerAdapter and not even org.apache.log4j.Logger (as I would have hoped/expected).
Is there any way to find this out?
Thanks,
Eric
SLF4J is designed as an abstraction for libraries, not applications (of course, you can and should still use SLF4J in your own app's logging calls, for consistency). In your own app, you choose the underlying logger framework, so it's fine to access the log4j API in the logging-config-specific parts.
No way should a library be mucking about with changing the logging config, IMHO, so it's not appropriate for it to be on the SLF4J API.
I have some questions about logging, more specifically about setting it up and making sure it works.
The project I'm doing will use Wicket, Spring and Hibernate. I know that Wicket and Hibernate uses Simple Logging Facade for Java (SL4J) and that Spring is using the logging component from Apache Commons.
Will they co-exist happily?
I thought I would use log4j together with both SL4J and the logging component from Apache commons, do you think that's a good idea?
Can I set up them all to output logging data into a common file?
Or should I use separate files?
Or should I store the logging messages in the database? (I'd rather not, as I find grepping etc on text files quite convenient.)
For Spring I guess I need some kind of configuration file for the Apache Commons logging component as well where I direct it to use log4j?
When I've set these up I guess to see that everything works I set the logging level to INFO as it's fairly certain that all three of the frameworks output some information in that mode? Or is there an even better way to make sure?
And my last question. In the project I'm starting, do you recommend that I use SL4J for my own logging purposes? (I thought I would use log4j directly, but that was before I learned a little bit more about logging and a lot of respectable libraries seem to choose the path of a bridge/facade for their logging needs. And if it gets us flexibility without added cost there's no reason not to do it that way.)
I'm looking forward to hearing more from you about how you are doing your logging. It's a new area for me which I'm eager to improve myself in.
Well SLF4J is just a facade, like commons logging, which means they still need something else to work. They permit library authors to not force users into having multiple logging library and configuration. Log4j and logback are regular logging libs.
See here for more info.
SLF4J has a commons logging bridge that you can use to replace the commons logging library. I think the schema there explain the situation very well.
Now, you just need to use slf4j-logj12.jar to have commons logging and slf4j use log4j (or anything else you chose; btw, logback doesn't need an additional library to be used with slf4j) as a backing engine.
You application will thus have
jcl104-over-slf4j.jar (to bridge jakarta commons logging to slf4j)
slf4j.jar (for hibernate and others to use slf4j)
slf4j-logj12.jar (for slf4j to use log4j as a backend)
log4j.jar (for your application to use. all config will also be done here)
Here is how to redirect everything to SLF4J:
remove commons-logging.jar from your classpath. If you are using Maven and have trouble getting rid of commons-logging, see this.
put jcl-over-slf4j.jar in your classpath (it comes in the SLF4J distribution). This is a drop-in replacement that mimics JCL's classes, but calls SLF4J internally. This will take care of Spring, and any other framework that uses JCL.
Connect SLF4J to your favorite backend (Log4J, Logback...) by putting slf4j-xxx.jar in the classpath. Configure the backend to log all categories to one file, and you're done.
As for using SLF4J in your application, it is not strictly necessary. Libraries like JCL and SLF4J were originally designed for people who write libraries and do no want to lock their clients into a particular logging framework.
PS: by the way, JCL = Jakarta Commons Logging