How to add infos to library's log message? - java

I have a Servlet that uses a Library. Both servlet and library log things via log4j.
The servlet is multithreaded and each request has a unique "request ID" like 123456.
When the servlet is logging stuff, it always appends the request ID at the beginning of the log message, but the library does not.
Like this:
Servlet - [123456] I'm going to do stuff now and call the library
LibraryX - I do library stuff here
How can I also append this request ID to every library message log, without modifying the library ?
What I want is :
Servlet - [123456] I'm going to do stuff now and call the library
LibraryX - [123456] I do library stuff here

You can use a Mapped Diagnostic Context
Just put your requestId into the context:
MDC.put("requestId", requestId);
And configure your jog4j.xml
<appender name="console" class="org.apache.log4j.ConsoleAppender">
<param name="Target" value="System.out" />
<layout class="org.apache.log4j.PatternLayout">
<param name="ConversionPattern" value="%d - [%X{requestId}] - %m%n" />
</layout>
</appender>

Related

Log4j issue logging in same file from different application

I have 4 applications which configured to log in same file opus-event.log and all have following configuration.
I am facing issue is each application logging in original(opus-event.log) as well as backup file like opus-event.log2015-10-16 and event.log2015-10-17 on date 19 oct.
<appender name="event" class="org.apache.log4j.DailyRollingFileAppender">
<param name="Threshold" value="DEBUG"/>
<param name="file" value="${jboss.server.log.dir}/opus-event.log"/>
<param name="DatePattern" value="yyyy-MM-dd"/>
<layout class="org.apache.log4j.PatternLayout">
<param name="ConversionPattern" value="%m%n"/>
</layout>
</appender>
Please some one help me to know what issue it is ? is it possible to resolve using log4j configuration without changing log file name?
You can't simply log into one file from 4 separate applications - there needs to be someone who manages and synchronizes the writes to the file.
Possible solutions:
You can use multiple files (one for each application)
If all applications are running in one JVM (e.g. application server), you might be able to configure them to use some shared logging service
Send the log entries to a logging service - all 4 programs would send their logs to a logger application that would write them to file - see Syslog for inspiration

JASIG CAS: How do I change where log files are written to?

I know very little about Java, let alone JASIG CAS.
We are trying to implement CAS on our CentOS 6 server. We are getting the following errors:
java.io.FileNotFoundException: cas.log (Permission denied)
[...snip...]
java.io.FileNotFoundException: perfStats.log (Permission denied)
After some investigation, it seems like tomcat6 is trying to write the log files in its home directory (/usr/share/tomcat6/). I was able to determine this by chown tomcat: /usr/share/tomcat6 and then, after a restart, the log files were created in that directory.
All the other logs though are written to /usr/share/tomcat6/logs which is a symlink to /var/log/tomcat6.
I want to know how do I reconfigure CAS to write these 2 log files to a different directory /usr/share/tomcat6/logs)?
Assuming you have a recent version of CAS, it uses log4j for logging, and you can find the log4j configuration in
$CATALINA_BASE/webapps/cas-server-webapp-VERSION/WEB-INF/classes/log4j.xml
For a standard Tomcat install under CentOS, $CATALINA_BASE would be /usr/share/tomcat.
If your log4j configuration has not been changed, you'll find an appender named "cas" near the top of the file which is responsible for creating cas.log. It looks like this:
<appender name="cas" class="org.apache.log4j.RollingFileAppender">
<param name="File" value="cas.log" />
<param name="MaxFileSize" value="512KB" />
<param name="MaxBackupIndex" value="3" />
<layout class="org.apache.log4j.PatternLayout">
<param name="ConversionPattern" value="%d %p [%c] - %m%n"/>
</layout>
</appender>
Further down you'll find another appender named "fileAppender", which creates the perfStats.log file.
<appender name="fileAppender" class="org.apache.log4j.FileAppender">
<param name="File" value="perfStats.log"/>
<layout class="org.apache.log4j.PatternLayout">
<param name="ConversionPattern" value="%m%n"/>
</layout>
</appender>
See how the value for the File parameters is just a file name with no directory specified? The log files therefore get created in the $CATALINA_BASE directory. To get them into the Tomcat logs directory where you want them, just change the values to logs/cas.log and logs/perfStats.log.
Note that CAS only reads the log4j config at startup, so once you've made the change you'll have to either undeploy and redeploy CAS or bounce Tomcat for it to take effect.

What is the best way to use log4j in the web application?

We are starting a Spring MVC based web application. We will be using tomcat as the web server.
I need to configure log4j in the application and log to the application specific file and not to the tomcat log files.
e.g. tomcat has its own log files like localhost.log etc. I want something like myAppName.log in the tomcats log folder.
The logging configuration will go in lo4j.xml or log4j.properties in the application war file.
Plus I dont want to hard code the output log file in the web application.
But I am not sure how to do this.
Please help me. As well correct me if I am wrong somewhere.
Do like this, initialize the logger with following code,
Logger log = Logger.getLogger(this.getClass());
log the information like follows,
log.debug("My message");
and place the log4j.xml in your class path. content like follows,
<log4j:configuration xmlns:log4j="http://jakarta.apache.org/log4j/">
<appender name="infoLogsFile" class="org.apache.log4j.RollingFileAppender">
<param name="File" value="MyApplication.log"/>
<param name="Threshold" value="DEBUG"/>
<param name="MaxFileSize" value="100MB"/>
<param name="ImmediateFlush" value="TRUE"/>
<layout class="org.apache.log4j.PatternLayout">
<param name="ConversionPattern" value="%d %-5p [%c] %m%n"/>
</layout>
</appender>
<root>
<priority value ="DEBUG" />
<appender-ref ref="infoLogsFile"/>
</root>
</log4j:configuration>
Do not forget to add the required jars like log4jXXX.jars and apache common logging jars. with this you will be able to see all log messages in MyApplication.log file creates in bin folder of your tomcat.
Try this:
Put the log4j jar as part of the web application
Do not put a configuration as part of your web application
Create your log4j.xml wherever you like
When you start tomcat provide this argument
-Dlog4j.configuration=file:///.../log4j.xml

Best way to modify log4j appended for logging

I'm currently developing soon to be big(functional wise) rest web service and I want to capture logs really good, so I can have a good insight of what is going on where. For now I use log4j for logging, using this appended setting :
<!-- Appenders -->
<appender name="console" class="org.apache.log4j.ConsoleAppender">
<param name="Target" value="System.out" />
<layout class="org.apache.log4j.PatternLayout">
<param name="ConversionPattern" value="%-5p: %c - %m%n" />
</layout>
</appender>
which produces these kind of logs :
10:44:55,893 INFO [STDOUT] INFO : my.package.MyClass - I'm class message
How can I make this message look like i.e.
10:44:55,893 INFO : my.package.MyClass - I'm class message
Can I make a special appender or whatever it is, and use it in some classes not in all, i.e. I want to have in few of my logs this :
Payload: some request parameters
Response: some response that my service returns
extra data : some extra data
Without having these INFO [STDOUT] INFO my.package.MyClass in front of it
UPDATE
I forgot to mention in the question that I'm using Jboss 5. I think the jboss might be adding the 10:44:55,893 INFO [STDOUT] to any format that I put in my log4j config.
BOUNTY UPDATE
I changed this :
<!-- ============================== -->
<!-- Append messages to the console -->
<!-- ============================== -->
<appender name="CONSOLE" class="org.apache.log4j.ConsoleAppender">
<errorHandler class="org.jboss.logging.util.OnlyOnceErrorHandler"/>
<param name="Target" value="System.out"/>
<param name="Threshold" value="INFO"/>
<layout class="org.apache.log4j.PatternLayout">
<!-- The default pattern: Date Priority [Category] Message\n -->
<param name="ConversionPattern" value="%d{ABSOLUTE} %-5p [%c{1}] %m%n"/>
</layout>
</appender>
to this:
<!-- ============================== -->
<!-- Append messages to the console -->
<!-- ============================== -->
<appender name="CONSOLE" class="org.apache.log4j.ConsoleAppender">
<errorHandler class="org.jboss.logging.util.OnlyOnceErrorHandler"/>
<param name="Target" value="System.out"/>
<param name="Threshold" value="INFO"/>
<layout class="org.apache.log4j.PatternLayout">
<!-- The default pattern: Date Priority [Category] Message\n -->
<param name="ConversionPattern" value="%m%n"/>
</layout>
</appender>
And it worked, but it seems kind of ugly to do it like this. Is there any other way? I'm using spring MVC/JBoss combination.
I'm now getting nice clean messages :
10:44:55,893 INFO : my.package.MyClass - I'm class message
without annoying
10:44:55,893 INFO [STDOUT]
prefix
Question 1:
Use the following pattern layout for your appender:
<param name="ConversionPattern" value="%d{ABSOLUTE} %-5p: %c - %m%n" />
The conversion pattern in the configuration file you stated does not result in the kind of log you stated. For example the date/time is not included in your conversion pattern.
Question 2:
You can use a special logger which uses another appender that is only logging the pure message.
Your configuration would for example look like the following:
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE log4j:configuration SYSTEM "log4j.dtd">
<log4j:configuration xmlns:log4j="http://jakarta.apache.org/log4j/">
<appender name="consoleAppender" class="org.apache.log4j.ConsoleAppender">
<param name="Target" value="System.out" />
<layout class="org.apache.log4j.PatternLayout">
<param name="ConversionPattern" value="%m%n" />
</layout>
</appender>
<appender name="consoleAppender2" class="org.apache.log4j.ConsoleAppender">
<param name="Target" value="System.out" />
<layout class="org.apache.log4j.PatternLayout">
<param name="ConversionPattern" value="%d{ABSOLUTE} %-5p: %c - %m%n" />
</layout>
</appender>
<logger name="specialLogger" additivity="false">
<level value="INFO" />
<appender-ref ref="consoleAppender" />
</logger>
<root>
<priority value="INFO" />
<appender-ref ref="consoleAppender2" />
</root>
</log4j:configuration>
You use the specialLogger for the pure messages without the additional information. It can be used in multiple classes.
In the configuration of the specialLogger, additivity = "false" is needed, because otherwise also the appender consoleAppender2 of the root logger would log the same message. (The message would be logged two times in this case.)
Your code could for example look like this:
public class TestClassA
{
private static Logger specialLogger = Logger.getLogger("specialLogger");
private static Logger logger = Logger.getLogger(TestClassA.class);
public TestClassA() {
}
public void doSomething() {
logger.info("Some message from TestClassA");
specialLogger.info("Some message via the specialLogger from TestClassA");
}
}
Calling doSomething results in:
17:17:18,125 INFO : com.foo.TestClassA - Some message from TestClassA
Some message via the specialLogger from TestClassA
Somewhere in your main class you need to configure log4j as usual, e.g.:
DOMConfigurator.configureAndWatch("log4j.xml", 60 * 1000);
The INFO [STDOUT] normally comes from log4j listening for System.out as well. We had a similiar case where the application itself had its own log4j configuration and thus got its own root appender. This would log to the console which is listened to by the JBoss log4j. This in turn adds the INFO [STDOUT] as if you were writing directly to System.out (or ERROR [STDERR] when writing to System.err).
The solution in our case was to remove the application specific log4j config and just use the one that JBoss writes to.
Another way might be to directly write to an application specific log file rather than writing to the console. In a server environment you'd most probably refer to log files anyway.
As for the second part, i.e. automatically extending logs with response, request etc. data:
In one case we had a super class for stateless session beans that provided logging functionality and had a (overwritable) logger per instance. The base methods like info would then call the logger and add the required data automatically.
A second approach could be MCD, i.e. you put some data (like the request) into the thread local MDC (basically a map) and then access them in your pattern definition.
For example, we have several similar applications each of which has some classes the others have too. So we'd need which application the message originated from and thus added the application name to the MDC:
In the code:
MDC.put("app.name", "myapplication");
In the log4j pattern config:
<param name="ConversionPattern" value="%d %-5p [%c (%X{app.name})] %m%n"/> (note the %X{app.name})
I didn't test whether you could do something like putting the request into the MDC and then use : %X{request.getAttribute('xyz')} but if it just gets the value in the MDC and calls toString() on it, you might create a request wrapper like this:
class RequestLogWrapper {
private HttpServletRequest request; //initialize through constructor etc.
public String toString() {
return request.getAttribute("xyz") + ";" + request.getAttribute("abc") + ... //handle null etc. as well
}
}
Then call MDC.put("request", new RequestLogWrapper(request)); and in the config use %X{request}.
Try to use this pattern as it will give you clean message:
<param name="ConversionPattern" value="%d{HH:mm:ss.SSS} %-5p %c %X %m/>
It is a good idea to add some unique value to MDC when request comes in, then add %X{uniqueValueKey} to your pattern. It will allow you to track logs for this unique request.
If you do not like the log4j xml configuration file you could switch to a property file instead. You cannot configure filters using the simple property file but since it seems you don't need them this shouldn't be an issue.
Given that you're
...currently developing soon to be big(functional wise) rest web service and I want to capture logs really good, so I can have a good insight of what is going on where.
then I'm afraid that your desired output won't give you many insights at all, it won't scale well, and it will make you loose your mind once the application gets big as expected...
Please refer to Log4j Best Practices for a good reference of logs design. Please take a look at ALL its paragraphs including the cosmetic consideration at the very end. Hope this helps.
to print only messages , the following conversion pattern will do.
<param name="ConversionPattern" value="%m%n"/>
Depending on your requirement, you can set the conversion pattern to whatever you want to
%-5p refers to the type of log entry. This would appear in the
log file as INFO, DEBUG, ERROR, etc. Technically, %p would be enough
to include this description; the -5 is there to include the word in
a 5-character width column.
%d refers to the date.
%t to the name of the thread that raised this log entry.
%c lists the category that generated this log which usually is the
class name.
%m displays the message
%n adds a carriage return.
Are you going to put all relevant information in messages only? I am not sure but its not a good idea.

Creating multiple log files of different content with log4j

Is there a way to configure log4j so that it outputs different levels of logging to different appenders?
I'm trying to set up multiple log files. The main log file would catch all INFO and above messages for all classes. (In development, it would catch all DEBUG and above messages, and TRACE for specific classes.)
Then, I would like to have a separate log file. That log file would catch all DEBUG messages for a specific subset of classes, and ignore all messages for any other class.
Is there a way to get what I'm after?
This should get you started:
log4j.rootLogger=QuietAppender, LoudAppender, TRACE
# setup A1
log4j.appender.QuietAppender=org.apache.log4j.RollingFileAppender
log4j.appender.QuietAppender.Threshold=INFO
log4j.appender.QuietAppender.File=quiet.log
...
# setup A2
log4j.appender.LoudAppender=org.apache.log4j.RollingFileAppender
log4j.appender.LoudAppender.Threshold=DEBUG
log4j.appender.LoudAppender.File=loud.log
...
log4j.logger.com.yourpackage.yourclazz=TRACE
Perhaps something like this?
<!DOCTYPE log4j:configuration SYSTEM "log4j.dtd">
<log4j:configuration xmlns:log4j="http://jakarta.apache.org/log4j/">
<!-- general application log -->
<appender name="MainLogFile" class="org.apache.log4j.FileAppender">
<param name="File" value="server.log" />
<param name="Threshold" value="INFO" />
<layout class="org.apache.log4j.PatternLayout">
<param name="ConversionPattern" value="%-5p %t [%-40.40c] %x - %m%n"/>
</layout>
</appender>
<!-- additional fooSystem logging -->
<appender name="FooLogFile" class="org.apache.log4j.FileAppender">
<param name="File" value="foo.log" />
<layout class="org.apache.log4j.PatternLayout">
<param name="ConversionPattern" value="%-5p %t [%-40.40c] %x - %m%n"/>
</layout>
</appender>
<!-- foo logging -->
<logger name="com.example.foo">
<level value="DEBUG"/>
<appender-ref ref="FooLogFile"/>
</logger>
<!-- default logging -->
<root>
<level value="INFO"/>
<appender-ref ref="MainLogFile"/>
</root>
</log4j:configuration>
Thus, all info messages are written to server.log; by contrast, foo.log contains only com.example.foo messages, including debug-level messages.
I had this question, but with a twist - I was trying to log different content to different files. I had information for a LowLevel debug log, and a HighLevel user log. I wanted the LowLevel to go to only one file, and the HighLevel to go to both a file, and a syslogd.
My solution was to configure the 3 appenders, and then setup the logging like this:
log4j.threshold=ALL
log4j.rootLogger=,LowLogger
log4j.logger.HighLevel=ALL,Syslog,HighLogger
log4j.additivity.HighLevel=false
The part that was difficult for me to figure out was that the 'log4j.logger' could have multiple appenders listed. I was trying to do it one line at a time.
Hope this helps someone at some point!
For the main logfile/appender, set up a .Threshold = INFO to limit what is actually logged in the appender to INFO and above, regardless of whether or not the loggers have DEBUG, TRACE, etc, enabled.
As for catching DEBUG and nothing above that... you'd probably have to write a custom appender.
However I'd recommend not doing this, as it sounds like it would make troubleshooting and analysis pretty hard:
If your goal is to have a single file where you can look to troubleshoot something, then spanning your log data across different files will be annoying - unless you have a very regimented logging policy, you'll likely need content from both DEBUG and INFO to be able to trace execution of the problematic code effectively.
By still logging all of your debug messages, you are losing any performance gains you usually get in a production system by turning the logging (way) down.
Demo link: https://github.com/RazvanSebastian/spring_multiple_log_files_demo.git
My solution is based on XML configuration using spring-boot-starter-log4j. The example is a basic example using spring-boot-starter and the two Loggers writes into different log files.

Categories

Resources