I am working with Java Web App {Servlet + JSP + Tomcat} and having one log management for the info and error logs.
Now I want to add some actual data log functionality with different path name and property values. How can I achieve this in Java ?
Existing Log Property
<Configuration status="ALL" name="Logger" packages="">
<Properties>
<Property name="baseDir">D:\\Log\\</Property>
</Properties>
<Appenders>
<RollingFile name="RollingFile" append="true" fileName="${baseDir}/Log.log" filePattern="${baseDir}/$${date:yyyy-MM}/app-%d{yyyy-MM-dd-HH}-%i.log.gz">
<PatternLayout pattern="%d{dd/MM/YYYY HH:mm:ss.SSS} [%t] %-5level %logger{36} %msg %n"/>
<Policies>
<TimeBasedTriggeringPolicy />
<SizeBasedTriggeringPolicy size="30 MB" />
</Policies>
<!-- Create 5 archives for the same date if the log file size exceeds 30MB -->
<!-- Deletes the logs which are older than 60 days from the current date -->
<DefaultRolloverStrategy max="5">
<Delete basePath="${baseDir}" maxDepth="2">
<IfFileName glob="*/app-*.log.gz">
<IfLastModified age="60d" />
</IfFileName>
</Delete>
</DefaultRolloverStrategy>
</RollingFile>
</Appenders>
<Loggers>
<Root level="ALL">
<AppenderRef ref="RollingFile"/>
</Root>
</Loggers>
</Configuration>
Java
public class Logj {
static Logger objLogger = LogManager.getLogger(Logj.class);
public static void doLog(Exception objException){
objLogger.error("StackTrace - "+objException.fillInStackTrace());
}
public static void doActivityLog(String strActivityMessage){
objLogger.info(" Activity - "+strActivityMessage);
}
}
I need same functionality to be execute for the new requirement
Will it support to add multiple Properties to add different directory path and adding multiple Appenders with different names ?
Thank in advance!!
You need to add one more property with different path in properties tag,
along with add one more rolling file appender and refer that appender in the root level, that will create two logs.
Related
java 1.8
maven 3.5
In pom.xml
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-slf4j-impl</artifactId>
</dependency>
In my Maven java project I want to generate new log file every new day (midnight).
So I use RollingFile and cron 0 0 0 * * ?. Here my log4j2.xml
<Properties>
<Property name="baseDir">logs</Property>
<Property name="patterLayout">%d{[dd.MM.yyyy HH:mm:ss.SSS]} %l %p:%n %m%n</Property>
</Properties>
<Appenders>
<Console name="Console" target="SYSTEM_OUT">
<PatternLayout pattern="${patterLayout}"/>-
</Console>
<RollingFile name="RollingFile" fileName="${baseDir}/app.log"
filePattern="${baseDir}/$${date:yyyy-MM}/app-%d{yyyy-MM-dd}.log.gz">
<PatternLayout pattern="${patterLayout}"/>-
<CronTriggeringPolicy schedule="0 0 0 * * ?"/>
<DefaultRolloverStrategy>
<Delete basePath="${baseDir}" maxDepth="2">
<IfFileName glob="*/app-*.log.gz"/>
<IfLastModified age="60d"/>
</Delete>
</DefaultRolloverStrategy>
</RollingFile>
</Appenders>
<Loggers>
<Root level="trace">
<AppenderRef ref="Console"/>
<AppenderRef ref="RollingFile"/>
</Root>
</Loggers>
But all logs print in ONE file app.log.
Here result:
[27.11.2021 23:59:05.235] com.myproject.xls2metro2.App.main(App.java:18) TRACE:
JDK: 1.8.0_202
[27.11.2021 23:59:05.238] com.myproject.xls2metro2.App.main(App.java:33) WARN:
File path is mandatory
[28.11.2021 00:01:13.347] com.myproject.xls2metro2.App.main(App.java:18) TRACE:
JDK: 1.8.0_202
[28.11.2021 00:01:13.351] com.myproject.xls2metro2.App.main(App.java:33) WARN:
File path is mandatory
At first, verify that your original configuration doesn't have this hyphen character (probably you have added it accidentally while writing a question)
<PatternLayout pattern="${patterLayout}"/>-
Also, make sure that your code is wrapped inside the Configuration tag (I assume that you have omitted it for the sake of brevity):
<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="warn" name="MyApp" packages="">
... your code here
</Configuration>
At second, your config looks exactly the same as in the official documentation examples, so it should be fine.
But in the documentation stated that:
The CronTriggeringPolicy triggers rollover based on a cron expression.
This policy is controlled by a timer and is asynchronous to processing
log events, so it is possible that log events from the previous or
next time period may appear at the beginning or end of the log file.
The filePattern attribute of the Appender should contain a timestamp
otherwise the target file will be overwritten on each rollover.
So probably, this is your case. Just wait a little longer to verify, that the next logs will be written to a separate file.
This question already has an answer here:
ParserConfigurationException while using log4j2 with junit
(1 answer)
Closed 10 months ago.
Switched from log4j1 to log4j2 (1.2.17 to 2.12).
I have 5 projects that use the new log4j2. I removed the old jar for log4j1, and all the references and paths now refer to the new added jar for log4j2.
I am using log4j2.xml to set the configuration for log4j2.
4 out of 5 other projects are running perfectly with the new log4j2, logging to the right file, with the correct pattern described in the log4j2.xml file.
One project - let's call it "ProjectX" - is returning an error when trying to access the same logger:
ERROR StatusLogger Caught javax.xml.parsers.ParserConfigurationException
The following are used when running the project:
jdk1.7.0_79
oracle.jdbc_11.1.1\ojdbc6dms.jar;
oracle.nlsrtl_11.1.0\orai18n.jar;
oracle.odl_11.1.1\ojdl.jar;
oracle.dms_11.1.1\dms.jar;
oracle.xdk_11.1.0\xmlparserv2.jar;
oracle.xdk_11.1.0\xml.jar;
com.oracle.toplink_1.0.0.0_11-1-1-5-0.jar;
org.eclipse.persistence_1.1.0.0_2-1.jar;
com.bea.core.antlr.runtime_2.7.7.jar;
javax.persistence_1.0.0.0_2-0-0.jar;
wlserver_10.3\server\lib\weblogic.jar;
commons-io-2.4.jar;
log4j-api-2.12.0.jar;
log4j-core-2.12.0.jar;
wlserver_10.3\server\lib\weblogic.jar
The log4j2.xml I'm using:
<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="WARN">
<Properties>
<!-- Path to the log files -->
<Property name="log-path">C:/logs</Property>
</Properties>
<Appenders>
<!-- Logger that prints to the Console window -->
<Console name="Console" target="SYSTEM_OUT">
<PatternLayout>
<pattern>%-6p%d{DATE} - %C{1}.%M:%L - %m%n</pattern>
</PatternLayout>
</Console>
<!-- Logger that prints to the log file specified in the fileName -->
<RollingFile name="LoggerFile" fileName="${log-path}/App.log" filePattern="${log-path}/App-%d{yyyy-MM-dd}-%i.log" immediateFlush="true" append="true">
<PatternLayout>
<pattern>%-6p%d{DATE} - %C{1}.%M:%L - %m%n</pattern>
</PatternLayout>
<!-- The maximum size of a log file -->
<Policies>
<SizeBasedTriggeringPolicy size="1 MB" />
</Policies>
<!-- Number of log files before starting to roll over -->
<DefaultRolloverStrategy max="10"/>
</RollingFile>
</Appenders>
<Loggers>
<Logger name="RollingFileLogger" level="DEBUG">
<AppenderRef ref="LoggerFile"/>
</Logger>
<Root level="DEBUG">
<AppenderRef ref="LoggerFile"/>
</Root>
</Loggers>
</Configuration>
Any idea what causes the error ERROR StatusLogger Caught javax.xml.parsers.ParserConfigurationException?
Could it be oracle.xdk_11.1.0\xmlparserv2.jar or xml.jar?
I tried xmlparserv2.jar version 12.2, and it fixed the error.
To download version 12.2 of xmpparserv2.jar:
https://maven.oracle.com/com/oracle/jdbc/xmlparserv2/12.2.0.1/xmlparserv2-12.2.0.1.jar
I upgraded the xmlparser jar from version 11.1 to version 12.2: xmlparserv2-12.2.0.1.jar.
I added it to the project and it fixed the problem.
I have a Java application that runs for a few minutes each hour via a cron job (java -jar...). It runs in its own JVM, not in a continuously running environment like Tomcat. I am using Log4j 2.11 to do logging. Within the application, I have a particular logger with specific rollover requirements:
Log to "rolling.log"
At the end of each day (or on the first logging event of a new day), rolling.log should be rolled over to rolling-yyyy-MM-dd.log.gz and new logging events added to a fresh rolling.log.
I have not been able to get the rollover to work. All log messages are to "rolling.log" only and no rolling-yyyy-MM-dd.log.gz is ever created. To test this in the most simple way possible, I created a simple Java console application with the following two files. I would expect the log file to roll over on every execution as long as the system clock is showing a different minute, but this does not happen.
LoggingTest.java:
package log4jtest;
import java.time.Instant;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
public class LoggingTest {
private static final Logger logger = LogManager.getLogger();
public static void main(String[] args) {
System.out.println(Instant.now() + " - BEGIN: Logging to log4j");
logger.error("Test log message");
System.out.println(Instant.now() + " - DONE");
}
}
log4j2.xml:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE Configuration>
<Configuration status="WARN">
<Appenders>
<RollingFile name="RollingLogFile"
fileName="logs/rolling.log"
filePattern="logs/rolling-%d{yyyy-MM-dd-HH-mm}.log.gz"
createOnDemand="true">
<PatternLayout
pattern="%d{HH:mm:ss.SSS} %-5level - %msg%n" />
<Policies>
<TimeBasedTriggeringPolicy modulate="true"
interval="1" />
<OnStartupTriggeringPolicy />
</Policies>
<DefaultRolloverStrategy />
</RollingFile>
</Appenders>
<Loggers>
<Root level="error">
<AppenderRef ref="RollingLogFile" />
</Root>
</Loggers>
</Configuration>
My guess is that since the JVM hosting the application and the Log4j instance is not running at the time the rollover would happen, then the rollover does not get triggered.
Ultimately, I abandoned the use of the RollingFileAppender and went with a straight-up FileAppender:
<File name="RollingLogFile"
fileName=logs/rolling-${date:yyyy-MM-dd}.log"
createOnDemand="true">
<PatternLayout
pattern="%d{HH:mm:ss.SSS} %-5level - %msg%n" />
</File>
This works, but it has a few disadvantages:
I cannot monitor the simply named "rolling.log" (since it doesn't exist), but have to use the date-specific version of the filename.
I cannot make use of log4j's compression on rollover features.
I cannot make use of log4j's delete on rollover retention policies.
So, the question, restated, is: Using log4j, is it possible for an application executed in brief intervals to use a time-based log file rollover strategy in the same way that continuously running applications can?
Please, try the following configuration:
<RollingFile name="LogSpecial"
fileName="${sys:special.directory}/special.csv"
filePattern="${sys:special.directory}/special-%d{yyyy-MM-dd}.csv.gz"
createOnDemand="true">
<CsvParameterLayout />
<Policies>
<TimeBasedTriggeringPolicy modulate="true" interval="1" />
<OnStartupTriggeringPolicy />
</Policies>
<DefaultRolloverStrategy>
<Delete basePath="{sys:special.directory}">
<IfFileName glob="special-*.csv.gz" />
<IfLastModified age="60d" />
</Delete>
</DefaultRolloverStrategy>
</RollingFile>
You can also switch on log4j2.debug system property to debug this configuration and investigate what's wrong.
It turns out that log4j2 is capable of doing exactly what I was aiming for but part of my configuration, for unknown reasons, prevented it from working properly. The solution was to remove the createOnDemand="true" attribute from the RollingFile element.
After excluding that attribute, the following configuration works exactly as I would expect (rolling over at startup, at most every minute):
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE Configuration>
<Configuration status="WARN">
<Appenders>
<RollingFile name="RollingLogFile"
fileName="logs/rolling.log"
filePattern="logs/rolling-%d{yyyy-MM-dd-HH-mm}.log.gz">
<PatternLayout
pattern="%d{HH:mm:ss.SSS} %-5level - %msg%n" />
<TimeBasedTriggeringPolicy />
</RollingFile>
</Appenders>
<Loggers>
<Root level="error">
<AppenderRef ref="RollingLogFile" />
</Root>
</Loggers>
</Configuration>
We have WAR deployments running on Tomcat containers which are using log4j 2.5 for logging events. We have now amended the deployments' log4j2.xml configuration to have the log files roll over every 24 hours but, with this new configuration, the rollover of files are not taking place as we would expect.
Sample configuration:
<RollingFile name="file"
fileName="${sys:catalina.base}/logs/${web:contextPath}.log"
filePattern="${sys:catalina.base}/logs/${web:contextPath}-%d{dd-MMM-yyyy}.log"
append="true">
<PatternLayout pattern="%d{dd-MMM-yyyy HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n" >
<header>LOG START DATE=${date:dd-MMM-yyyy HH:mm:ss.SSS} APP=${web:contextPath} TOMCAT=${env:HOSTNAME}:${env:CONNECTOR_PORT}${sys:line.separator}</header>
<footer>LOG END DATE=${date:dd-MMM-yyyy HH:mm:ss.SSS} APP=${web:contextPath} TOMCAT=${env:HOSTNAME}:${env:CONNECTOR_PORT}${sys:line.separator}</footer>
</PatternLayout>
<Policies>
<TimeBasedTriggeringPolicy/>
</Policies>
</RollingFile>
Any ideas why the rollover is not taking place?
NOTE: The same configuration but with a <CronTriggeringPolicy schedule="0 0 0 * * ?" /> instead of TimeBasedTriggeringPolicy does rollover but, in this case, the rolled over files get created with today's date in the filename and NOT yesterday's date.
NOTE2: We have other deployments with similar configuration that do rollover every 24 hours but those configurations have the filename hardcoded instead of using ${web:contextPath}. Could this lookup have something to do with why RollingFile might not work?
--- EDIT ---
UPDATE: We are able to get TimeBasedTriggeringPolicy to rollover files using above configuration when the Tomcat instance is running on Windows but NOT when the Tomcat instance is running on Linux.
There is nothing wrong with your configuration snippet as I get the desired behaviour of time based rolling.
To test, I changed the dd-MMM-yyyy to dd-MMM-yyyy-HH-mm and my log file rolls every minute.
It must be something else that is preventing you from achieving the desired behaviour.
My setup #1:
Log4j2 v2.8.2
Apache Tomcat 8.5.13
Windows 7 Enterprise SP1
My setup #2:
Log4j2 v2.5
Apache Tomcat 7.0.77
CentOS 7 (1611)
I have the following 3 JARs in WEB-INF/lib:
log4j-api-2.5.jar
log4j-core-2.5.jar
log4j-web-2.5.jar
Here is my complete log4j2.xml for your reference:
<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="DEBUG">
<Appenders>
<RollingFile name="RollingFileAppender"
fileName="${sys:catalina.base}/logs/${web:contextPath}.log"
filePattern="${sys:catalina.base}/logs/${web:contextPath}-%d{dd-MMM-yyyy-HH-mm}.log"
append="true">
<PatternLayout pattern="%d{dd-MMM-yyyy HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n" >
<header>LOG START DATE=${date:dd-MMM-yyyy HH:mm:ss.SSS} APP=${web:contextPath} TOMCAT=${env:HOSTNAME}:${env:CONNECTOR_PORT}${sys:line.separator}</header>
<footer>LOG END DATE=${date:dd-MMM-yyyy HH:mm:ss.SSS} APP=${web:contextPath} TOMCAT=${env:HOSTNAME}:${env:CONNECTOR_PORT}${sys:line.separator}</footer>
</PatternLayout>
<Policies>
<TimeBasedTriggeringPolicy/>
</Policies>
</RollingFile>
</Appenders>
<Loggers>
<Logger name="root" level="debug" additivity="false">
<appender-ref ref="RollingFileAppender" level="debug"/>
</Logger>
<Root level="debug" additivity="false">
<AppenderRef ref="RollingFileAppender"/>
</Root>
</Loggers>
</Configuration>
I am trying to configure a log4j2 config to route messages to different logfiles for a multithreaded program via threadname.
Here is what I have, so far (relevant to log4j2 config):
|-/src/main/java/log4j2/plugins
|-- ThreadLookup.java
|-/src/main/resources
|-- log4j2.xml
ThreadLookup.java:
package log4j2.plugins;
import org.apache.logging.log4j.core.LogEvent;
import org.apache.logging.log4j.core.config.plugins.Plugin;
import org.apache.logging.log4j.core.lookup.StrLookup;
#Plugin(name="threadLookup", category=StrLookup.CATEGORY)
public class ThreadLookup implements StrLookup {
#Override
public String lookup(String key) {
return Thread.currentThread().getName();
}
#Override
public String lookup(LogEvent event, String key) {
// Check event first:
if (event.getThreadName() != null) {
return event.getThreadName();
}
// Fallback to key if event doesn't define a threadName:
return this.lookup(key);
}
}
Log4j2.xml (It is my understanding that the packages attribute of Configuration should read in ThreadLookup.java and based on the annotation create a new threadLookup prefix to let me call lookup(String key) with whatever value I want to -- in this case I am not using a specific value because this class will only do a threadName lookup):
<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="error" strict="true" schema="Log4J-V2.0.xsd"
packages="log4j2.plugins">
<Properties>
<Property name="logMsgPattern">%date{yyyy/MM/dd HH:mm:ss.SSS} %-5level ${sys:pid}[%thread] %class %method:%line - %message%n</Property>
</Properties>
<Appenders>
<Console name="console" target="SYSTEM_OUT" >
<PatternLayout pattern="${logMsgPattern}" />
</Console>
<Routing name="routing">
<Routes pattern="$${threadLookup:threadName}">
<Route>
<RollingFile name="RollingFile-${threadLookup:threadName}"
fileName="${sys:log4j.dir}/thread-${threadLookup:threadName}.log"
filePattern="${sys:log4j.dir}/thread-${threadLookup:threadName}-%i.log.gz">
<PatternLayout pattern="${logMsgPattern}"/>
<Policies>
<SizeBasedTriggeringPolicy size="100 MB" />
</Policies>
</RollingFile>
</Route>
</Routes>
</Routing>
<!-- Config for other appenders snipped -->
</Appenders>
<Loggers>
<!-- Config for other loggers snipped -->
<Root level="${sys:log4j.console.threshold}">
<AppenderRef ref="rootOut" level="trace" />
<AppenderRef ref="rootErr" level="error" />
<AppenderRef ref="console" level="${sys:log4j.console.threshold}" />
<AppenderRef ref="routing" level="trace" />
</Root>
</Loggers>
</Configuration>
However, when I launch my app, it just creates an additional file called thread-${threadLookup (no extension) in my log directory. It also never hits any breakpoints in ThreadLookup.java.
How can I register the plugin with log4j2 (I was using version 2.2, I also tried 2.3)? Note, I am using a spring-framework 4.1.7 project, if that helps at all; I use maven for the project as well, but I am only using it to resolve dependencies, I build the project via ant script.
UPDATE
When I build the script via ant, I do actually get a Log4j2Plugins.dat that shows up in my classpath (-cp resources:bin), but it doesn't seem to effect the outcome of the logs that are generated on the server:
$ find bin/META-INF/ -type f
bin/META-INF/org/apache/logging/log4j/core/config/plugins/Log4j2Plugins.dat
$ cat bin/META-INF/org/apache/logging/log4j/core/config/plugins/Log4j2Plugins.dat
lookup
threadlookupog4j2.plugins.ThreadLookup
threadLookup
$ vi bin/META-INF/org/apache/logging/log4j/core/config/plugins/Log4j2Plugins.dat
^A^Flookup^A^Lthreadlookup^[log4j2.plugins.ThreadLookup^LthreadLookup
$ find logs -type f -name "thread-*"
logs/thread-${threadLookup:threadName}.log
logs/thread-${threadLookup:threadName}-1.log.gz</pre>
Thanks
I ended up finding out that the issue was that my Plugin name cannot be camelCased.
I was debugging through PluginManager.java (Log4j2 - 2.3), on line 169 in private static void mergeByName(final Map<String, PluginType<?>> newPlugins, final List<PluginType<?>> plugins), and I saw that I had the following properties to go into newPlugins.put(key, pluginType);
key: threadlookup,
pluginType: PluginType [pluginClass=class log4j2.plugins.ThreadLookup, key=threadlookup, elementName=threadLookup, isObjectPrintable=false, isDeferChildren==false, category=Lookup]
After seeing that, I modified my Routing appender in my log4j2.xml config to the following (without needing to change the annotation in my Plugin class that implemented StrLookup) and it worked:
<Routing name="routing">
<Routes pattern="$${threadlookup:threadName}">
<Route>
<RollingFile name="RollingFile-${threadlookup:threadName}"
fileName="${sys:log4j.dir}/thread-${threadlookup:threadName}.log"
filePattern="${sys:log4j.dir}/thread-${threadlookup:threadName}-%i.log.gz">
<PatternLayout pattern="${logMsgPattern}"/>
<Policies>
<SizeBasedTriggeringPolicy size="100 MB" />
</Policies>
</RollingFile>
</Route>
</Routes>
</Routing>
Hopefully this can help others out, as I had to spend a few days to figure this out and I didn't find this in any of the documentation or questions I was reviewing for Log4j2.
Thanks!