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.
Related
I am able to write console logs to rotating log files using this method here:
https://www.codejava.net/frameworks/spring-boot/logback-rolling-files-example
But my requirement is to write only specific logs to the log files instead of whole console log. For example, i need to write only the json messages(i can print them on console using log.info(message) which is supported by slf4j) being received by Kafka listener to the log files and nothing more. How can i achieve this in my spring-boot app? Is this not possible with slf4j logback?
Specify the appender-ref in your logger element.
So something like this in your logger XML configuration file:
<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{1} - %m%n"/>
</layout>
</appender>
<appender name="bdfile" class="org.apache.log4j.RollingFileAppender">
<param name="append" value="false"/>
<param name="maxFileSize" value="1GB"/>
<param name="maxBackupIndex" value="2"/>
<param name="file" value="/tmp/bd.log"/>
<layout class="org.apache.log4j.PatternLayout">
<param name="ConversionPattern" value="%-5p %c{1} - %m%n"/>
</layout>
</appender>
Then in the same config file, add a appender reference to the log file that you are interested in
<logger name="com.example.ClassWithJsonMessage" additivity="false">
<level value="debug"/>
<appender-ref ref="bdfile"/>
</logger>
I have my webapp some-app.war running under Tomcat 8.5. I use Slf4j and Logback for logging within the webapp. When I log using log.info() or similar, the output gets written to catalina.out, the same log file as Tomcat uses for its internal logging. I want the logs from my application to be written to a separate log file. But I do NOT want to use logback's FileAppender to do it. I'd prefer to leave Logback using ConsoleAppender as I may deliver the WAR to others who won't have the same logging needs. I see the location of the log file as an aspect of the deployment environment, not the code.
Is there a way that I can manage per-application log files from the configuration of the Tomcat server itself -- while still using Slf4j and Logback in my code?
You can't know about others' logging needs, so there's not a silver bullet solution for this. However I'm sure the best option is not "I'm gonna leave it configured really badly because someone might log differently".
You can configure it how you wish for yourself, using FileAppenders and document the necessary steps to reconfigure it (e.g. edit the war).
You can also use more advanced configurations such as making use of syslog. Now other users have a standardized configuration option, just as long as they use syslog.
There are other options as well, but the common thread here is that you can't know what others may want, so don't waste time trying to guess it. Just do what works well for you at least.
If you placed logging.properties at [CATALINA_HOME/conf/logging.properties] then it should use it as your root logging properties file. Put you logging.properties or log.xml file in your application at [MyApp/WEB_INF/classes/logging.properties] and configure it like blow.
<?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="stderr" class="org.apache.log4j.ConsoleAppender">
<layout class="org.apache.log4j.PatternLayout">
<param name="Target" value="System.err"/>
<param name="ConversionPattern"
value="%d{yyyy-MM-dd HH:mm:ss} %-5p %c{1}:%L - %m%n" />
</layout>
</appender>
<appender name="stdout" class="org.apache.log4j.ConsoleAppender">
<layout class="org.apache.log4j.PatternLayout">
<param name="Target" value="System.out"/>
<param name="ConversionPattern"
value="%d{yyyy-MM-dd HH:mm:ss} %-5p %c{1}:%L - %m%n" />
</layout>
</appender>
<appender name="file" class="org.apache.log4j.RollingFileAppender">
<param name="append" value="true" />
<param name="maxFileSize" value="2MB" />
<param name="maxBackupIndex" value="100" />
<param name="file" value="${catalina.base}/logs/MyApp/MyApp.log" />
<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>
<level value="DEBUG" />
<appender-ref ref="stdout" />
<appender-ref ref="stderr" />
<appender-ref ref="file" />
</root>
</log4j:configuration>
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.
This question already has answers here:
Where does java.util.logging.Logger store their log
(3 answers)
Closed 9 years ago.
Netbeans thoughtfully sprinkles Logger.getLogger(this.getClass().getName()).log(Level. [...]
statements into catch blocks. Now I would like to point them all to a file (and to console).
Every logging tutorial and such only me tells how to get a specific logger to output into a file, but I assume there is a better way than fixing every automatically generated logging statement? Setting a handler for some sort of root logger or something?
I just add the following at startup
Handler handler = new FileHandler("test.log", LOG_SIZE, LOG_ROTATION_COUNT);
Logger.getLogger("").addHandler(handler);
You can specify your own values for LOG_SIZE and LOG_ROTATION_COUNT
You may need adjust the logging level to suit.
You have to define where the log is writting in the logger configuration file.
For example, if you use log4j, a log4j.xml (or log4j.properties) file will contain such information.
For example, here is a simple log4j.xml file that logs directly into a file (my-app.log) and in the console:
<?xml version="1.0" encoding="UTF-8"?>
<log4j:configuration xmlns:log4j="http://jakarta.apache.org/log4j/">
<appender name="rolling" class="org.apache.log4j.DailyRollingFileAppender">
<param name="File" value="my-app.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] [IP=%X{ipAddress}] [user=%X{user}] %m%n" />
</layout>
</appender>
<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} %-5p [%C] [user=%X{user}] %m%n" />
</layout>
</appender>
<root>
<priority value="info" />
<appender-ref ref="console" />
<appender-ref ref="rolling" />
</root>
</log4j:configuration>
I am having problem that even though I specify the level to ERROR in the root tag, the specified appender logs all levels (debug, info, warn) to the file regardless the settings. I am not a Log4j expert so any help is appreciated.
I have checked the classpath for log4j.properties (there is none) except the log4j.xml.
Here is the log4j.xml file:
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE log4j:configuration SYSTEM "log4j.dtd">
<log4j:configuration xmlns:log4j='http://jakarta.apache.org/log4j/'>
<!-- ============================== -->
<!-- Append messages to the console -->
<!-- ============================== -->
<appender name="console" class="org.apache.log4j.ConsoleAppender">
<param name="Target" value="System.out" />
<layout class="org.apache.log4j.PatternLayout">
<!-- The default pattern: Date Priority [Category] Message\n -->
<param name="ConversionPattern" value="[AC - %5p] [%d{ISO8601}] [%t] [%c{1} - %L] %m%n" />
</layout>
</appender>
<appender name="logfile" class="org.apache.log4j.RollingFileAppender">
<param name="File" value="./logs/server.log" />
<param name="MaxFileSize" value="1000KB" />
<param name="MaxBackupIndex" value="2" />
<layout class="org.apache.log4j.PatternLayout">
<param name="ConversionPattern" value="[AC - %-5p] {%d{dd.MM.yyyy - HH.mm.ss}} %m%n" />
</layout>
</appender>
<appender name="payloadAppender" class="org.apache.log4j.RollingFileAppender">
<param name="File" value="./logs/payload.log" />
<param name="MaxFileSize" value="1000KB" />
<param name="MaxBackupIndex" value="10" />
<layout class="org.apache.log4j.PatternLayout">
<param name="ConversionPattern" value="[AC - %-5p] {%d{dd.MM.yyyy - HH.mm.ss}} %m%n" />
</layout>
</appender>
<appender name="errorLog" class="org.apache.log4j.RollingFileAppender">
<param name="File" value="./logs/error.log" />
<param name="MaxFileSize" value="1000KB" />
<param name="MaxBackupIndex" value="10" />
<layout class="org.apache.log4j.PatternLayout">
<param name="ConversionPattern" value="[AC - %-5p] {%d{dd.MM.yyyy - HH.mm.ss}} %m%n" />
</layout>
</appender>
<appender name="traceLog"
class="org.apache.log4j.RollingFileAppender">
<param name="File" value="./logs/trace.log" />
<param name="MaxFileSize" value="1000KB" />
<param name="MaxBackupIndex" value="20" />
<layout class="org.apache.log4j.PatternLayout">
<param name="ConversionPattern"
value="[AccessControl - %-5p] {%t: %d{dd.MM.yyyy - HH.mm.ss,SSS}} %m%n" />
</layout>
</appender>
<appender name="traceSocketAppender" class="org.apache.log4j.net.SocketAppender">
<param name="remoteHost" value="localhost" />
<param name="port" value="4445" />
<param name="locationInfo" value="true" />
</appender>
<logger name="TraceLogger">
<level value="trace" /> <!-- Set level to trace to activate tracing -->
<appender-ref ref="traceLog" />
</logger>
<logger name="org.springframework.ws.server.endpoint.interceptor">
<level value="DEBUG" />
<appender-ref ref="payloadAppender" />
</logger>
<root>
<level value="error" />
<appender-ref ref="errorLog" />
</root>
</log4j:configuration>
If I replace the root with another logger, then nothing gets logged at all to the specified appender.
<logger name="com.mydomain.logic">
<level value="error" />
<appender-ref ref="errorLog" />
</logger>
The root logger resides at the top of the logger hierarchy. It is exceptional in three ways:
it always exists,
its level cannot be set to null
it cannot be retrieved by name.
The rootLogger is the father of all appenders. Each enabled logging request for a given logger will be forwarded to all the appenders in that logger as well as the appenders higher in the hierarchy (including rootLogger)
For example, if the console appender is added to the root logger, then all enabled logging requests will at least print on the console. If in addition a file appender is added to a logger, say L, then enabled logging requests for L and L's children will print on a file and on the console. It is possible to override this default behavior so that appender accumulation is no longer additive by setting the additivity flag to false.
From the log4j manual
To sum up:
If you want not to propagate a logging event to the parents loggers (say rootLogger) then add the additivity flag to false in those loggers. In your case:
<logger name="org.springframework.ws.server.endpoint.interceptor"
additivity="false">
<level value="DEBUG" />
<appender-ref ref="payloadAppender" />
</logger>
In standard log4j config style (which I prefer to XML):
log4j.logger.org.springframework.ws.server.endpoint.interceptor = INFO, payloadAppender
log4j.additivity.org.springframework.ws.server.endpoint.interceptor = false
Hope this helps.
Run your program with -Dlog4j.debug so that standard out gets info about how log4j is configured -- I suspected that it isn't configured the way that you think it is.
To add on to what James A. N. Stauffer and cynicalman said - I would bet that there is another log4j.xml / log4j.properties on your classpath other than the one you wish to be used that is causing log4j to configure itself the way it is.
-Dlog4j.debug is an absolute killer way to troubleshoot any log4j issues.
Two things: Check additivity and decide whether you want log events captured by more detailed levels of logging to propagate to the root logger.
Secondly, check the level for the root logger. In addition you can also add filtering on the appender itself, but this should normally not be necessary.
If you are using a log4j.properties file, this file is typically expected to be in the root of your classpath, so make sure it's there.
This is correct behavior. The root logger is like the default behavior. So if you don't specify any logger it will take root logger level as the default level but this does not mean that root logger level is the level for all your logs.
Any of your code which logs using 'TraceLogger'logger or 'org.springframework.ws.server.endpoint.interceptor' logger will log messages using TRACE and DEBUG level respectively any other code will use root logger to log message using level, which is in your case ERROR.
So if you use logger other than root, root log level will be overridden by that logger's log level. To get the desired output change the other two log level to ERROR.
I hope this is helpful.