My simple question is : If I have two statements like logger.info() and logger.error() in Java (using log4j), I want the results of these two lines to be printed in two separate files. That is, logger.info(...) should print to a file say myLog.info and logger.error(...) should print to myLog.error file. I am using rolling file appender for this task. Also I want just one logger object to do the task. Someone might suggest two or more different loggers one for each file, but that's not the case.
I tried searching a solution for the problem. One of the links Creating multiple log files of different content with log4j says about "threshold" and I even tried to add threshold in my xml configuration file. But what it actually is doing that : info log is being printed in myLog.info file but error log gets printed in both the files. Can it be done through xml configuration file alone or a separate properties file is needed? If xml file is sufficient, then what needs to be done?
I am preferring xml file over properties file. If there is a working solution using only xml configuration file, that would be sufficient. Thanks in advance.
You could use filters to deny any messages except those of the level you want. Here is an example of how to do this:
First a class to test our efforts:
package test;
import org.apache.log4j.Logger;
public class Main {
private static final Logger logger = Logger.getLogger(Main.class);
public static void main(String[] args) {
logger.debug("here's some debug");
logger.info("here's some info");
logger.warn("here's some warn");
logger.error("here's some error");
logger.fatal("here's some fatal");
}
}
Next a log4j.xml config file to set up the appenders and loggers:
<?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">
<layout class="org.apache.log4j.PatternLayout">
<param name="ConversionPattern" value="%d %-5p [%c{1}] %m %n" />
</layout>
</appender>
<appender name="debugLog" class="org.apache.log4j.RollingFileAppender">
<param name="File" value="logs/debug.log" />
<param name="Append" value="true" />
<param name="MaxFileSize" value="5000KB" />
<param name="maxBackupIndex" value="5" />
<layout class="org.apache.log4j.PatternLayout">
<param name="ConversionPattern" value="%d{yyyy-MM-dd HH:mm:ss} [%t] %-5p - %m%n" />
</layout>
<filter class="org.apache.log4j.varia.LevelMatchFilter">
<param name="LevelToMatch" value="DEBUG" />
<param name="AcceptOnMatch" value="true" />
</filter>
<filter class="org.apache.log4j.varia.DenyAllFilter" />
</appender>
<appender name="infoLog" class="org.apache.log4j.RollingFileAppender">
<param name="File" value="logs/info.log" />
<param name="Append" value="true" />
<param name="MaxFileSize" value="5000KB" />
<param name="maxBackupIndex" value="5" />
<layout class="org.apache.log4j.PatternLayout">
<param name="ConversionPattern" value="%d{yyyy-MM-dd HH:mm:ss} [%t] %-5p - %m%n" />
</layout>
<filter class="org.apache.log4j.varia.LevelMatchFilter">
<param name="LevelToMatch" value="INFO" />
<param name="AcceptOnMatch" value="true" />
</filter>
<filter class="org.apache.log4j.varia.DenyAllFilter" />
</appender>
<logger name="test" additivity="false">
<level value="DEBUG" />
<appender-ref ref="consoleAppender" />
<appender-ref ref="debugLog" />
<appender-ref ref="infoLog" />
</logger>
</log4j:configuration>
This pattern will allow you to generate a separate log for each log level, just repeat the configuration that I have provided for either debug or info logging. Note that the console appender will accept all levels.
I was able to gain some insight from this post so I thought I should give credit.
Related
First, I have found a SO question that seems very relevant:
How can I set up separate streams of logging for log4j?
The first answer to the question discusses using Markers and this is what I'd like to try to use. However, I have not been able to get the logging to actually work as expected. I don't know if I'm missing a step or using the wrong syntax.
I wrote a really simple program in an attempt to test this out.
package my.package;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.slf4j.Marker;
import org.slf4j.MarkerFactory;
public class LoggingTest {
private static final Logger logger = LoggerFactory.getLogger(LoggingTest.class);
public static void main(String[] args) {
Marker marker = MarkerFactory.getMarker("MARKER");
logger.info(marker, "log info to marker log");
logger.info("log info to regular log");
}
}
log4j.xml:
<log4j:configuration debug="true" xmlns:log4j='http://jakarta.apache.org/log4j/'>
<!-- APPENDERS -->
<appender name="console" class="org.apache.log4j.ConsoleAppender">
<layout class="org.apache.log4j.PatternLayout">
<param name="ConversionPattern"
value="[%d{yyyy-MM-dd HH:mm:ss.SSS}] %-5p: %c{2}:%L - %m%n" />
</layout>
</appender>
<appender name="file" class="org.apache.log4j.FileAppender">
<param name="file" value="session.log" />
<param name="append" value="true" />
<layout class="org.apache.log4j.PatternLayout">
<param name="ConversionPattern"
value="[%d{yyyy-MM-dd HH:mm:ss.SSS}] %-5p: %c{2}:%L - %m%n" />
</layout>
</appender>
<appender name="marker-file" class="org.apache.log4j.FileAppender">
<param name="file" value="marker.log" />
<param name="append" value="true" />
<MarkerFilter marker="MARKER" onMatch="ACCEPT" onMismatch="DENY" />
<layout class="org.apache.log4j.PatternLayout">
<param name="ConversionPattern"
value="[%d{yyyy-MM-dd HH:mm:ss.SSS}] %-5p: %c{2}:%L - %m%n" />
</layout>
</appender>
<!-- LOGGERS -->
<root>
<level value="INFO" />
<appender-ref ref="marker-file" />
</root>
</log4j:configuration>
The logging right now is just set to log to the marker appender. I would need to figure out how to set up the logger(s) to send "marker" output to the marker appender and the rest to the "regular" appender.
I don't know if the syntax of the usage of the MarkerFilter element is correct or not.
When I execute the program, I am specifying the VM argument -Dlog4j.configuration=file://<path to log4j.xml>.
I'm running this from within eclipse and I'm having a separate problem where it doesn't seem to be recognizing the log4j.xml file I'm giving it. I assume this is something I'm doing wrong (and is probably the reason why what I'm trying to do does not appear to work).
Any ideas as to what I might be doing incorrectly as far as getting the log4j.xml to be recognized, and then if that all checks out, whether I'm using the filter/marker mechanism correctly or not, would be greatly appreciated.
UPDATE:
I am doing this on a Windows box, so I suspect something is amiss with how I'm specifying the file URI to the log4j.xml file.
In my Tomcat application, I want to use two loggers to log general event informations and errors to two different files.
Logger eventLogger = Logger.getLogger("event");
Logger errorLogger = Logger.getLogger("error");
Now I want to do the following: the logs of the eventLogger should be written to a "events.log" file, and the errorLogger logs should be written in a "errors.log" file. All logs from any other logger (e.g. Tomcat logs) should be written to catalina.out (or any other default file).
How can I achive this with JULI? Or do I need a third party lib?
This can't be achieved with Juli. You might use log4j.
Basically you need appenders. They will manage the logs to go to separate files. Example configuration in xml:
<?xml version="1.0"?>
<!DOCTYPE log4j:configuration SYSTEM "log4j.dtd">
<log4j:configuration xmlns:log4j="http://jakarta.apache.org/log4j/">
<appender name="CONSOLE" class="org.apache.log4j.ConsoleAppender">
<layout class="org.apache.log4j.EnhancedPatternLayout">
<param name="ConversionPattern" value="%d{ABSOLUTE} %-5p [%t][%c{1}:%L] %m%n" />
</layout>
</appender>
<appender name="eventFILE" class="org.apache.log4j.DailyRollingFileAppender">
<param name="File" value="#tomcat.home#/logs/event.log" />
<param name="DatePattern" value="'.'yyyy-MM-dd" />
<layout class="org.apache.log4j.PatternLayout">
<param name="ConversionPattern" value="%d{yyyy-MM-dd HH:mm:ss} %-5p %c{1}:%L - %m%n"/>
</layout>
</appender>
<appender name="errorFILE" class="org.apache.log4j.DailyRollingFileAppender">
<param name="File" value="#tomcat.home#/logs/error.log" />
<param name="DatePattern" value="'.'yyyy-MM-dd" />
<layout class="org.apache.log4j.PatternLayout">
<param name="ConversionPattern" value="%d{yyyy-MM-dd HH:mm:ss} %-5p %c{1}:%L - %m%n"/>
</layout>
</appender>
<logger name="event" additivity="false">
<level value="INFO" />
<appender-ref ref="eventFILE" />
</logger>
<logger name="error" additivity="false">
<level value="INFO" />
<appender-ref ref="errorFILE" />
</logger>
<root>
<priority value="INFO" />
<appender-ref ref="FILE" />
</root>
</log4j:configuration>
you have to define an appender for each file in your log4j.xml and connect them to your loggers:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE log4j:configuration SYSTEM "log4j.dtd">
<log4j:configuration xmlns:log4j="http://jakarta.apache.org/log4j/">
<!-- 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="%d{ISO8601} %5p [%c.%M:%L] - %m%n" />
</layout>
</appender>
<appender name="FILE-error" class="org.apache.log4j.DailyRollingFileAppender">
<param name="File" value="${catalina.base}/logs/error.log" />
<param name="DatePattern" value="'.'yyyy-MM-dd" />
<param name="ImmediateFlush" value="true" />
<layout class="org.apache.log4j.PatternLayout">
<param name="ConversionPattern" value="%d{ISO8601} %5p [%c.%M:%L] - %m%n" />
</layout>
</appender>
<appender name="FILE-event" class="org.apache.log4j.DailyRollingFileAppender">
<param name="File" value="${catalina.base}/logs/event.log" />
<param name="DatePattern" value="'.'yyyy-MM-dd" />
<param name="ImmediateFlush" value="true" />
<layout class="org.apache.log4j.PatternLayout">
<param name="ConversionPattern" value="%d{yyyy-MM-dd HH:mm:ss};%m%n" />
</layout>
</appender>
<!-- Loggers -->
<logger name="error" additivity="false">
<level value="warn" />
<appender-ref ref="FILE-error" />
</logger>
<logger name="event" additivity="false">
<level value="info" />
<appender-ref ref="FILE-event" />
</logger>
<!-- Root Logger -->
<root>
<priority value="warn" />
<appender-ref ref="FILE-error" />
</root>
</log4j:configuration>
Tomcat documentation does not provide any way to define more than one file per application when using JULI. Actually it provides the steps to use log4j instead of it because JULI configuration can be too basic.
But again this configuration is at container level:
Note: The steps described in this section are needed when you want to
reconfigure Tomcat to use Apache log4j for its own logging. These
steps are not needed if you just want to use log4j in your own web
application. — In that case, just put log4j.jar and log4j.properties
into WEB-INF/lib and WEB-INF/classes of your web application.
So using a third party library is the logical choice and you can find how to configure it in this SO post
Tomcat JULI logging supports this only via the logging.properties located in the ${catalina.base}/config folder.
#Declares the handlers allowed for use.
handlers = 100catalina.org.apache.juli.FileHandler, 200catalina.org.apache.juli.FileHandler, 300catalina.org.apache.juli.FileHandler
#Install the 'all' hander on the root logger.
.handlers=300catalina.org.apache.juli.FileHandler
#Install the 'event' handler on the 'event' logger and don't report to root.
event.handlers=100catalina.org.apache.juli.FileHandler
event.useParentHandlers=false
#Install the 'error' handler on the 'error' logger and don't report to root.
error.handlers=200catalina.org.apache.juli.FileHandler
error.useParentHandlers=false
#Event handler settings.
100catalina.org.apache.juli.FileHandler.level = ALL
100catalina.org.apache.juli.FileHandler.directory = ${catalina.base}/logs
100catalina.org.apache.juli.FileHandler.prefix = event.
#Error handler settings.
200catalina.org.apache.juli.FileHandler.level = ALL
200catalina.org.apache.juli.FileHandler.directory = ${catalina.base}/logs
200catalina.org.apache.juli.FileHandler.prefix = error.
#Root handler settings.
300catalina.org.apache.juli.FileHandler.level = ALL
300catalina.org.apache.juli.FileHandler.directory = ${catalina.base}/logs
300catalina.org.apache.juli.FileHandler.prefix = all.
This config will not work if you try to install this file in the WEB-INF/classes/logging.properties. This is because the ClassLoaderLogManager doesn't allow you to install handlers on named loggers.
I am using log4j in my java application to log the messages.log4j-1.2.17.jar is the jar file used. Below is the log file.
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE log4j:configuration SYSTEM "log4j.dtd">
<log4j:configuration debug="true" xmlns:log4j='http://jakarta.apache.org/log4j/'>
<appender name="console" class="org.apache.log4j.ConsoleAppender">
<param name="Target" value="System.out" />
<param name="Threshold" value="debug" />
<layout class="org.apache.log4j.PatternLayout">
<param name="ConversionPattern" value="%d %-5p %c{1}:%L %m %n" />
</layout>
</appender>
<appender name="fileAppender" class="org.apache.log4j.RollingFileAppender">
<param name="Threshold" value="INFO" />
<param name="Threshold" value="debug" />
<param name="maxFileSize" value="10MB" />
<param name="maxBackupIndex" value="10" />
<param name="file" value="D/logs/projectLog.log"/>
<param name="append" value="true" />
<layout class="org.apache.log4j.PatternLayout">
<param name="ConversionPattern" value="%d{yyyy-MM-dd HH:mm:ss} %-5p %c{1}:%L %m %n" />
</layout>
</appender>
<root>
<priority value="info"></priority>
<appender-ref ref="fileAppender" />
</root>
</log4j:configuration>
I am using above log file in my application. Log file got generated successfuly but in the log file , debug messages are not getting printed.
In my java class,below are the statements i have included.
LOGGER.info("In TestMVCController, logger info");
System.out.println("is debug enabled" + LOGGER.isDebugEnabled());//always false even when server is started in debug mode
LOGGER.debug("In TestMVCController, logger debug");
LOGGER.error("In TestMVCController, logger errror");
In my log file, I can see only info and error messages being printed. In which scenario does the debug statements print and how can i make my log statements to print debug statements?Any advice would be helpful.
Change the root's priority value from "info" to "debug":
<root>
<priority value="debug"></priority>
<appender-ref ref="fileAppender" />
</root>
This will configure the root logger to send log messages at level "DEBUG" or higher to the appender "fileAppender". The "fileAppender" can then set the threshold it wants to log (DEBUG, INFO, WARNING etc).
Note: The appender's "threshold" parameter is optional. If you omit it, the appender will log at the level defined by the root logger. The "threshold" can be used if there are multiple appenders. For example: DEBUG for a console appender and INFO for a file appender.
I have overridden log4j smtp appender for some purpose. The problem is if i keep <param name="Threshold" value="INFO"/> Then it would send mails properly. But if i keep <param name="Threshold" value="ERROR"/> Then no mails are sent. What is the problem? Please find my code.
public class MyAppender extends SMTPAppender{
#Override
protected void sendBuffer() {
//Some code to format email body
}
}
log4j.xml
<!-- Appenders -->
<appender name="mail" class="com.service.MyAppender">
<param name="BufferSize" value="2"/>
<param name="BufferedIO" value="true"/>
<param name="Threshold" value="ERROR"/>
<param name="SMTPHost" value="myhost"/>
<param name="From" value="abc#co.com"/>
<param name="To" value="def#ld.com"/>
<param name="Subject" value="Testing Testing"/>
<layout class="org.apache.log4j.PatternLayout">
<param name="ConversionPattern"
value="%d{yyyy-MM-dd HH:mm:ss} %-5p %c{2}:%L - %m%n"/>
</layout>
</appender>
<appender name="ASYNC" class="org.apache.log4j.AsyncAppender">
<param name="BufferSize" value="500"/>
<appender-ref ref="mail"/>
</appender>
<root>
<level value="ERROR" />
<appender-ref ref="ASYNC" />
</root>
I looked into SMTPAppender source code and i believe below lines are the problem.
if(evaluator.isTriggeringEvent(event)) {
sendBuffer();
}
According to log4j documentation, all log events with value lower than Treshold will be filtered out (i.e. not sent).
It's possible that changing Treshold to more restrictive filters out all messages that are logged in your case.
Make sure that you actually have events with log level ERROR (or higher - FATAL).
Am using log4j for my error reporting. Ive set my log 4j to also append errors to emails. However i need it to send emails to separate groups depending on the level of the message. For example
info messages go to management- john#management.com, peter#management.com, simon#management.com
debug messages go to programmers - paul#programmer.com, matt#programmer.com
warn messages go to administrator - admin#admin.com
In such a fashion, is it possible? And has anyone implemented said procedure (a sample properties file would be appreciated)
Is should be easy to configure something like this using the SMTPAppender from log4j. But be aware, that emailing logs takes quite a bit of load, especially if you consider mailing DEBUG reports to developers.
You can use a log4j Filter to do this (http://logging.apache.org/log4j/1.2/apidocs/org/apache/log4j/spi/Filter.html)
The example below writes messages to different files according to the log level.
This can be easily adapted to an SMTPAppender instead of a FileAppender.
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE log4j:configuration SYSTEM "log4j.dtd">
<log4j:configuration xmlns:log4j='http://jakarta.apache.org/log4j/'>
<appender name="management" class="org.apache.log4j.FileAppender">
<param name="File" value="management.log" />
<layout class="org.apache.log4j.PatternLayout">
<param name="ConversionPattern" value="%m"/>
</layout>
<filter class="org.apache.log4j.varia.LevelRangeFilter">
<param name="LevelMin" value="INFO" />
<param name="LevelMax" value="INFO" />
<param name="AcceptOnMatch" value="true" />
</filter>
</appender>
<appender name="programmers" class="org.apache.log4j.FileAppender">
<param name="File" value="programmers.log" />
<layout class="org.apache.log4j.PatternLayout">
<param name="ConversionPattern" value="%m"/>
</layout>
<filter class="org.apache.log4j.varia.LevelRangeFilter">
<param name="LevelMin" value="DEBUG" />
<param name="LevelMax" value="DEBUG" />
<param name="AcceptOnMatch" value="true" />
</filter>
</appender>
<appender name="admin" class="org.apache.log4j.FileAppender">
<param name="File" value="admin.log" />
<layout class="org.apache.log4j.PatternLayout">
<param name="ConversionPattern" value="%m"/>
</layout>
<filter class="org.apache.log4j.varia.LevelRangeFilter">
<param name="LevelMin" value="WARN" />
<param name="LevelMax" value="WARN" />
<param name="AcceptOnMatch" value="true" />
</filter>
</appender>
<category name="a">
<level value="ALL" />
<appender-ref ref="management"/>
<appender-ref ref="programmers"/>
<appender-ref ref="admin"/>
</category>
</log4j:configuration>