How do I unify logging formats from the java stack - java

Using a Jetty web server, started from maven, which includes iBatis, Spring, Jersey, a little of this and a little of that, I get logging output with a host of formats.
Some are from maven:
[INFO] [war:war]
[INFO] Exploding webapp...
Some are from Jetty:
2009-03-25 21:01:27.781::INFO: jetty-6.1.15
2009-03-25 21:01:28.218:/example:INFO: Initializing Spring root WebApplicationContext
Some are from Spring:
INFO ContextLoader - Root WebApplicationContext: initialization started (189)
INFO XmlBeanDefinitionReader - Loading XML bean definitions from ServletContext resource [/WEB-INF/applicationContext.xml] (323)
Some are from Jersey:
Mar 25, 2009 9:01:29 PM com.sun.jersey.spi.spring.container.SpringComponentProviderFactory register
still others are from my code:
INFO ExampleApp - [User#14ef239 ...stuff] (69)
I expect they're all using standard logging packages (log4j, commons-logging, java-logging...)
Is it possible, and what is the easiest way to configure all of them to use the same format?
Is there any benefit to leaving them in varying formats?

This is possible using the logback library and its bridges. It basically consists to remove any log4j commons or alike jars from the classpath, stick logback jar file and bridges jars for log4j and alike. Spring, jersey and maven will use the bridge factories to instantiate loggers which in turn will use logbak producing unified logging.
Check http://logback.qos.ch/ and http://www.slf4j.org/legacy.html
The key are the bridges which link other log utilities with a single global logger.

The issue you have is that the applications are using different logging libraries. Jersey will use JUL, Spring will use commons-logging (which will in turn pick log4j if that's in your classpath), and Jetty uses its own logger. You can fix this by getting all your components to log through JUL.
First you need to get log4j off your classpath. Use exclusions or other mechanisms to ensure that log4j is not included. This will prevent commons-logging from picking log4j over JUL and get Spring to log in the same format as Jersey.
Next you'll need to configure Jetty to use commons-logging. You can find information about that on the Maven Jetty Plugin documentation page.
If your application code is using log4j directly, you'll need to switch to either commons-logging or JUL.
Maven I'm not so sure about, but it probably has a similar solution.

I don't know of any way to manage what you're describing in a useful manner. If you're desperate, the best suggestion I can make is to write something to unify the disparate formats under one umbrella and manage it there using your preferred logging format.

I don't think you can unify all of these easily, because you don't know what is being used by each framework.
If you identify which ones you are interested in then you can get each to output to log files in a central location /var/log/app (under linux for example). From here you could write a simple utility that parses each log file and massages the data into a single log file in the format that you want. The Awk utility is very good at doing this sort of thing.
Alternatively, you could leave them as they are - and use something like Splunk to index the files for future searching and analysis. It really depends on what you require from the log files at a later date. Hope that helps.

If and when they are using standard logging package, of course you can unify common parts ("INFO" prefix, timestamp, category name (usually class/package)). Just configure log4j / J.U.L / logback to your liking.
I don't know why you would get different formats -- log formats are NOT configured by frameworks, but apps -- so maybe they are using different frameworks. But that may be accidental.
As to whether it matters; well, only if you process it automatically (trigger regex-based alarms).

SLF4J allows you to consolidate logging by routing it into a single logging framework. You can redirect legacy logging calls made with commons-logging, java.util.logging and log4j as if they were made to SLF4J. See www.slf4j.org/legacy.html for details.
All logging will then be delegated to an underlying framework of your choice, for example logback, log4j, java.util.logging among others. If you run into trouble do contact the slf4j-user mailing list.

I think we will eventually need a "logging api" logging api that ties together all unified logging apis such as slf4j and whatever other ones they are. Who knows, you might need to change your logging framework that handles all types of logging one day...

Simply use http://logback.qos.ch/translator/ to convert the log4j.properties into xml format and paste that in logback.xml. This works as charm directing your log to appender configured.

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.

How do Log4j, commons-logging, JDK-Logging and SLF4J relate to each other?

Are they alternatives, dependencies, APIs or implementations of each other?
And why do they exist?
Ah, logging frameworks in Java. Your question mixes 2 different types of libraries:
log4j and JDK logging are libraries for handling logging
Commons Logging and SLF4J are logging facades: you still need a real logging implementation (like log4j)
If you are writing a library that will be used in someone else's system, then you should use a logging facade because you do not know which logging framework they will use. In this case use SLF4J (Commons Logging is older and has some classloader issues).
If you control the whole application and can dictate which logging framework to use, you are free to choose your own preference. My preferred solutions are (in order of preference):
Logback
log4j
JDK logging (in my opinion, a case of 'not invented here' by SUN)
I've been looking into this recently too. I've been using Log4J for years with Commons Logging and recently switched to SLF4J.
Log4j
Log4j is a framework for actually doing the log writing/distribution. It's extremely flexible: you can direct it to send log messages to files, syslog, remote monitoring, etc. You can also configure multiple loggers, logging categories, include context in entries, and so on. It's one of the most popular logging systems.
JDK Logging
The built-in JDK logging (which I've never used, to be honest) was added in JDK 1.4.2. From what I gather, it's not very popular because it's not as flexible as Log4j, but I'd welcome comments :).
Commons Logging and SLF4j
Both of these are façades on top of various logging frameworks that present a common interface for your application. For example, you can use CL/SLF4J in your application, and they will automatically detect an underlying logger implementation (Log4J, JDK logging, or a built-in logger that just delegates to System.err.println()). The benefit is that you or your end user can decide to switch out the underlying logging implementation at will, and they greatly simplify your implementation by removing many of the complexities of Log4J and JDK logging.
Most often you will see them layered.
SLF4J is purely an abstraction layer and is not, in itself, used for the actual outputting of logging but used by you in your code to log messages.
A typical setup is to use SLF4J to log in your code, then use log4j as the underlying "output" layer using an appropriate slf4j->log4j bridge (a jar you just include on your classpath). In order to merge logging from different sources, various bridges exist. For instance, many app servers (like tomcat) will use JDK-logging to avoid forcing a "non standard" logging framework on the deployed applications. For that purpose, slf4j has a bridge that will pick up all output from JDK-logging. So, this could be a stack
JDK-logging <- Your app-server or framworks might log using this
|
(JDK->Slf4j bridge)
|
Slf4j <- your application logs using Slf4j
|
(Slf4j->log4j bridge)
|
log4j <- log4j is just responsible for outputting to the appenders you configure (file, console etc)
SLF4J just is a generic API with different back-ends (any other logging system). Log4j and commons-logging (CL) different logging libraries, CL is a fossil. But they all have a fatal flaw, so sun have invented JDK logging.
As for me, I prefer SLF4J as most flexible and logback as a backend for it. Logback is most modern and have a lot nice features.

SLF4J, Common Logging, console output

I have this 3rd party library that has:
slf4j-api-1.5.5.jar
slf4j-jdk14-1.5.5.jar
jcl-over-slf4j-1.5.5.jar
I want to write some tests against this library and see its log output, and I don't want to add any more logging libraries (no log4j or anything else).
I understand that SLF4J and Common Logging are both logging abstractions so I probably need to write my own simple concrete logger (or maybe not, since jcl-over-slf4j includes org.apache.commons.logging.impl.SimpleLog?). If so, what interfaces should I implement, and more importantly, how do I set up SL4J/Common Logging to use my logger in my test? I read in the SLF4J docs that I have to modify the StaticLoggerBinder class... does that really mean that I actually have to download SLF4J sources, modify the class and recompile it?
We use SLF4J. It's very useful but several of the jars have confusing names and it's not real clear starting out to know which ones are incompatible.
SLF4J is the API you use for logging in your code (e.g. log.info("blah"). However, SLF4J has no configuration aspect to it. At runtime you add exactly one jar to the classpath that binds the API to the 'real' logging subsystem. If you want to use Log4J, add slf4j-log4j.jar or the StaticBinder jar for Simple or JDK, or Logback. You configure any of these logging implementations as you normally would without SLF4J.
There are several SLF4J modules available to redirect existing logging statements written using the APIs of Log4J, Apache Commons Logging, and java.util.logging to SLF4J. This allows you to setup a single logging configuration for all these disperate implementations. (This is very useful to avoid configuring both, say, Log4J and JUL if you have libraries that bind directly to any legacy logging framework.)
The SLF4J legacy page explains these concepts in depth. Heck, there is even a module to redirect Sysout.out/err to SFL4J.
To more directly answer your question: sure you can write your own logging implementation to go under SLF4J; but the only reason to do so is because you are already locked into some homegrown craptastic logging framework.
If you want to keep it simple, use the built-in (as of jdk 1.4) logger
https://docs.oracle.com/en/java/javase/19/docs/api/java.logging/java/util/logging/Logger.html
the jdk binding jar comes with slf4j. you want to make sure the jar is deployed to your webapp WEB-INF/lib dir or just in your classpath otherwise. See (slf4j.org/faq.html#where_is_binding) and this (slf4j.org/faq.html) for more information.
the jar you want to add to your classpath is slf4j-jdk14.jar. Note that the jdk logger is already available, this jar is the link between the slf4j interfaces and the chosen logger implementation. the jdk logging binding jar comes with the slf4j distribution. this should do it for you.
Your question leds me to believe that you have not read the the SLF4J user manual. It's a very short document. If after reading the document you still have the same question, then the document fails its purpose and needs to be clarified.
Anyways, you don't need to implement your own Logger class. Just use slf4j-simple which ships with SLF4J.

java logging vs Log4j in Spring framework. Which one is the most suitable

We are developing a web-based application in Java using the Spring framework. We are wondering which Logging system would be the most appropriate for it, whether Log4j or JUL (java.util.Logging), which is integrated with jdk. As far as I'm concerned, the former is more popular among developers and offers higher customization options, but I'm not sure which is simpler to adapt with spring.
any help will be appreciated.
thanks!
Before you start with log4j, look at logback. Log4j shouldn't be used for new projects anymore. If you have legacy code that needs any logging framework, use slf4j to make the old code talk to logback (or log4j if you must).
The main reasons you should not use JUL is that it implements the bare minimum that you need for logging, the configuration is hard at best and, if you use any component that doesn't use it, you'll have to deal with two logging frameworks.
Regardless of which logging framework you use in your own code, as far as I can remember, Spring has a hard dependency on commons-logging. You can still use whatever you like for your own logging (I'd recommend SLF4J as your facade, with logback as your implementation), but Spring internally needs commons-logging. Whether you want to depend on multiple frameworks is your choice; it shouldn't prove problematic.
Spring uses commons logging, which is a log abstraction facility but has issues that sl4j doesn't have. Hibernate moved to slf4j - I would like to see spring do the same, but I don't think they have any plans in this regard.
So as long as your log abstraction facility (use slf4j) logs to the same logging framework as you've configured commons logging in spring, then you're good. One log configuration for both. You might find an adapter for logback for commons and slf4j.
Since the other responses didn't actually answer your question, I thought I'd have a stab at it.
Firstly, java.util.logging is horrible. It's a pain to use, and a pain to configure. Log4J is nicer on both counts. However, you should pick whichever one you're most comfortable with. Spring uses commons-logging, which in turn will use either log4j (if found on the classpath) or java.util.logging otherwise. In otherwords, if your application already has log4j present, then Spring will effectively use that, and so should you. If log4j is not already present, then either use java.util.logging (if you choose to), or add log4j to your classpath and use that.

log4j.xml in client jars

I have some jar files that will be distributed to clients that are using log4j for logging. My question is should I include a log4j.xml configuration in the jar file or have the client provide one if they want logging?
My feeling is to leave the log4j.xml configuration file out of the client jars, since the apache jar files all come with log4j logging, but sans log4j.xml.
Yes, leave it out. It's an utter nuisance when your log4j configuration file is ignored because one of the 60 third-party libraries of your app contains its own.
The good thing about log4j in your case is that your jar really shouldn't have to worry about it. The basic use case of log4j is:
Obtain a logger object for the current class
Call one of the methods on that logger, such as debug("some message");
If the jars you are shipping are to be used by a larger application, then ideally your code will only do the two steps listed above. In this way, your code will simply obtain logger objects from the already-configured log4j instance in the client's application. Your production code is then decoupled from having to know how to configure log4j.
Any logging you need to see for your development of the jars can be accomplished by configuring a log4j instance in unit test setUp() methods or something similar that won't get bundled with the production code going to the client.
I would put a default log4j configuration that you expect will be useful to your clients in the documentation. This way interested people can see what logging options you have (usually certain classes have more interesting log messages, from the user's perspective). I find it annoying when I have a third-party lib using log4j and it has no documentation, and there are log messages filling my screen and I have to try to figure out how to enable or suppress certain log messages.
If you are using log4j in your application then you include it in your project. If you are not, then why would you put it in there? What if client A wants log4j version 1.2 and client B wants log4j version 1.3.
Let them decide what they need for their projects and worry about what you need for yours.
I would add the configuration xml and load it up with instruction for the user showing different configuration and options. This will make it easier for either them or support to enable addition logging.

Categories

Resources