Intercepting or wrapping log4j root logger or appender - java

I would like to inject a piece of information into all messages logged by anything, including third-party code. The reason is that, in our web-services-oriented application, requests come in with unique IDs and I want those unique IDs to be attached to all log messages that occur while processing a request, to assist in later analysis. I am already tracking the "current request" using ThreadLocal<> techniques, so I have the ability to fetch the "current request" from anywhere.
To that end, I would like to configure log4j such that I can inject the requestID into messages before they reach the root logger (or appender?). I know that I can just make a whole new Appender that implements append() and does whatever it wants with the output, but that's not what I'm asking for. I want output to ultimately go to whatever appender is configured at startup, but with the additional information attached.
I am using log4j 1.x, but if a move to log4j 2.x or using slf4j makes this significantly easier, I would consider it.

Related

Accessing Historical Log Messages with slf4j/logback

I have a Swing-based application that logs all messages to text files through slf4j with logback underneath.
I'd like to add a feature to show all messages at a certain level(e.g. fatal) logged in the current session on demand, say in a JTable.
Does slf4j provide API that lets you access historical log messages, preferably filtered by level or time?
Try to use Logback, there is a ch.qos.logback.classic.db.DBAppender class that you can use as an Appender to your fatal errors. You can define your own data structure, just provide the SQL Insert statement. Also, other variants of this DBAppender are provided, so you can choose when do you want to customize the behavior.
The next thing is that you tie your appender to those loggers that you want to log.
Finally you can manage your logged data within your application (filter, purge/archive) just like your application business data.

Component-based logging with logback (or: intercept foreign log messages)

I'm looking for a way to define transitive log message routing. Let's say we have an application called poly with these packages:
com.mycompany.server-common
com.mycompany.communication
com.mycompany.webservice
server-common is used by both of the 2 others. All 3 use org.hibernate as well.
Now, I like to have 1 logfile for the webservice component with all messages from com.mycompany.webservice and with those messages from com.mycompany.server-common and org.hibernate that were initiated by the webservice. And then, another coresponding file for the communication package.
My application is a war file running in tomcat, where all components run in 1 context (it comes in 1 war file). I already defined the multiple log files, but they naturally only log that what i defined statically, there is no transitive inclusion.
I would be very interested in ideas how I could achieve the desired behaviour. I already thought about using the MDC for that, but I'm not sure if that's a good idea.
Another idea was to separate the contexts, but I think in the current project state this will be hard and it does not offer the flexibility I hope for.
Any hints or discussions are appreciated.
If you set an MDC key when webservice starts serving a request and clear the MDC key at the end of the request, SiftingAppender will do what you are asking. Shout on the logback-user mailing list if you run into difficulties.

What is the right logging approach when using Spring Batch?

What is the right logging approach when using Spring Batch? Should I use log4j (or something similar) or Spring Batch provides some instruments that help me to instantiate a logger and use it? Maybe some sort of dependency injection of the logger?
I'd used log4j. and its the simple and nice approach.
I'm not sure the original poster's question was answered, so I'll try restating this a bit. In Spring Batch you may have multiple threads going, and you may want to have job-specific logging, so that all events for a particular job are logged into a single log file. You want a Logger whose scope is tied directly to the job you are processing. When the job finishes, the logger (and all references to the logger) go away.
So when you submit Job#1, all events are logged to "job_1.log"; when you submit Job#2, its events are logged to "job_2.log", etc.
In log4j, when you do "Logger.getLogger('mylogger')" you are telling the LogManager to get 'mylogger' out of the cache and give it to you. What you really want is a new instance of the logger, configured using the configuration of mylogger. In Spring this might be typically done with a prototype bean. Every time you ask the context for 'mylogger' you would get a new instance.
You should think about Slf4J (logging API) + Logback (logging implementation) as Log4j is intented to be succeeded by this duet.
More:
http://www.slf4j.org/
http://logback.qos.ch/

How do you differentiate log4j sessions in a log file from copies of the same web-app?

There is only one file. And it is written simultaneously as web app copies run.
How do you filter only one session log messages from other log lines?
Using a servlet filter with either NDC or MDC information is the best way I've seen. A quick comparison of the two is available at http://wiki.apache.org/logging-log4j/NDCvsMDC.
I've found MDC has worked better for me in the past. Remember that you'll need to update your log4j properties file to include whichever version you prefer (pattern definitions at http://logging.apache.org/log4j/1.2/apidocs/org/apache/log4j/PatternLayout.html).
A full example of configuring MDC with a servlet filter is available at http://veerasundar.com/blog/2009/11/log4j-mdc-mapped-diagnostic-context-example-code/.
A slightly easier to configure, but significantly inferior option: You could opt to just print out the thread ID (via the properties file) for each request and make sure that the first thing you log about each request is a session identifier. It isn't as proper (or useful), but it can work for low-volume applications.
You could set a context message including the identifier of the specific app instance using org.apache.log4j.NDC, like this:
String appInstanceId = "My App Instance 1";
org.apache.log4j.NDC.push(appInstanceId);
// handle request
org.apache.log4j.NDC.clear();
You can set up the context during the initialization of your web app instance, or inside the doPost() method of your servlets. As its name implies, you can also nest contexts within contexts with multiple push calls at different levels.
See the section "Nested Diagnostic Contexts" in the Log4J manual.
Here is a page that sets up an MDC filter for web-app -> http://rtner.de/software/MDCUserServletFilter.html
Being a servlet filter it will free you from managing MDC/NDC in each of your servlets.
Of course, you should modify it to save information more pertinent to your web-app.
If you want to differentiate sessions in the same application then the MDC is the way to go. But if you want to differentiate the web applications writing to the same file, then MDC won't help because it works on a thread basis. In such case I used to make my own appender which knows which application instance it serves. This can be done through appender configuration properties. Such appender would stick application name into each logging event as a property before writing it into the media, and then you can use a layout to show this property value in the text file it writes to. Using MDC in such case won't work because every thread will have to MDC.put(applicationName) and that is quite ugly. MDC is only good for single process, not for several processes. If someone knows the other way, I'd like to hear.

SLF4J Message Format In WebSphere App Server

So, I'm beating my head against the wall with logging again. I know, how complex can it be? Well, let's see...
I'm starting a new project to be run on WebSphere Application Server 6.1 (actually Portal Server 6.1, but it's WAS 6.1 under the hood - whatever). I usually use java.util.logging for my WAS projects and everything is fine. This customer is a SLF4J fan and wants to use that. Fair enough, sounds easy.
So, I deploy slf4j-api-1.5.8.jar and slf4j-jdk14-1.5.8.jar in my WEB-INF/lib directory. In my code I do a --
// These classes are coming from org.slf4j.*
private static Logger log = LoggerFactory.getLogger(MyClass.class);
...
log.debug("This is a log message");
As expected I get an entry in the SystemOut.log. However, it's the format of that message that I can't figure out. A sample would be --
[12/15/09 15:43:15:071 EST] 00000042 MyClass D com.example.MyClass This is a log message
Let me explain what's in that sample log entry. I assume everything to the left of com.example.MyClass is coming from the j.u.l formatter. Everything to the right of it is what I included in my log.debug(). So, who's adding the com.example.MyClass? Only thing I can think is that SLF4J is adding it before it passes the message through to the underlying j.u.l.
It's the com.example.MyClass part that's irritating me. I don't want that included in the SLF4J-generated log message. The class name is already included, so it's extra fluff that's not needed. Plus, the real package names are quite long and their inclusion just pushes the real meat of the log entry too far off to the right.
When I use just plain java.util.loggging, the log entry is exactly the same except that the "com.example.MyClass" piece is not included. Exactly as I want!
So, the question is - how can I get rid of this extra class name entry in the log messages generated via SLF4J under WAS?
Thanks!
You bind slf4j to java.util.logging which most likely is configured inside WebSphere as it doesn't look like the standard message format.
I do not know WebSphere, but you may get a better result by telling slf4j to bind to something else. Would the slf4j-simple backend do? It just prints out info-or-higher messages instead of invoking java.util.logging.
Basically you want to configure the layout of the logging messages produced by the underlying logging mechanism.
SLF4J does not actually perform the logging, but delegates to other logging systems (log4j, JUL, etc) based on how you set it up.
So if you are binding SLF4J with JUL, then I think the real question you are asking is either one of
Setting the Formatter of a Logger Handler
Creating a Custom Formatter for a Logger Handler

Categories