Java Log4J 2 - Configurate own appender in xml - log4j2

I tried to configurate Log4J2 per xml-file. I want to register an own appender (which shows an speciale panel if errors happend).
With logback it was no problem - till I wanted to use it in my webStart-Project. So I hope it works with log4j2.
With my own configuration I get an CLASS_NOT_FOUND output.
I am looking the log4j2 xml-shema for:
<appender name="myAppender" class="mypackage.myappender">
I tried everything like
<Appenders>
<Myappender name="MyAppender" class="mypackage.myappender">
</Myappender>
</Appenders>
I hope someone can help me.
P.S.: sorry for my bad english

You would need to implement your appender as a log4j2 plugin.
This is not that difficult (just look at some of the existing appenders to see which annotations to use and methods to implement).
You also need to help log4j2 find your plugin by specifying the appender's package in the configuration:
<Configuration packages="com.mycomp.mylog4j2appenderpackage">
<Appenders>
<MyAppender name="MyAppender" />
</Appenders>
...
</Configuration>

Related

Translating prometheus LOG4j conf from XML to properties file

I have used LOG4j many times on quite common basics, and mainly through a properties file. I am though very unfamiliar with the XML form and with uncommon features (such as third party lib custom logging).
The prometheus log4j2 configuration is written for xml conf files, and I actually don't understand it. Although I could use it as such, I would like to understand it by translating in a form I am confortable with : as a properties file .
<?xml version="1.0" encoding="UTF-8"?>
<Configuration packages="io.prometheus.client.log4j2">
<Appenders>
<Prometheus name="METRICS"/>
</Appenders>
<Loggers>
<Root level="info">
<AppenderRef ref="METRICS"/>
</Root>
</Loggers>
</Configuration>
properties file :
name=PropertiesConfig
property.filename = /var/logs
appenders = console, METRICS?
appenders.METRICS?.
...?
rootLogger.appenderRefs = METRICS, console
...?
Can anyone help me on this one?
like this:
log4j.rootLogger=CONSOLE,METRICS
log4j.appender.CONSOLE=org.apache.log4j.ConsoleAppender
log4j.appender.Threshold=DEBUG
log4j.appender.CONSOLE.Target=System.out
log4j.appender.CONSOLE.layout=org.apache.log4j.PatternLayout
log4j.appender.CONSOLE.layout.ConversionPattern=[%-5p][%d{yyyy-MM-dd HH\:mm\:ss,SSS}][%c] \:%m%n
log4j.appender.METRICS=io.prometheus.client.log4j.InstrumentedAppender
after see log4j_appender_total flag in prometheus
converstion refer: https://www.journaldev.com/10698/log4j-properties-file-example

Modify existing log4j2 FileAppender configuration during runtime

I am migrating application (huge web application) from log4j1.x to log4j 2.11.0.
I need help/clarification to migrate following scenarios -
--------scenario1
log4j1.x:
<appender name="import_log_file" class="xxxx">
During runtime i want to change the file so i would just do appender.setFile(...new file...). And done.
log4j2:
how do I migrate above code?
Few ideas but not a straight answer:
Creating brand new appender via LoggerContext, Configuration might be a way but i want to update an existing appender's configuration and reload the log4j2 xml. How do I do that?
Another way could be redefining something like this
<appender name="import_log_file" class="xxxx">
And then setup "dynamic_name" property in threadcontext. But I am loosing original default file import.log
Any help is appreciated. Let me know if you have ideas.
During runtime i want to change the file
You can use the RoutingAppender together with a lookup to do this. See the log4j2 FAQ page for details.
Here is a very simple example of how to change the log file name at runtime:
package pkg;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.apache.logging.log4j.ThreadContext;
public class Log4j2DiffFilePerCtxVarMain {
private static final Logger LOG = LogManager.getLogger();
public static void main(String[] args){
ThreadContext.put("myFileNameVar", "file1");
LOG.info("This should appear in file1.log");
ThreadContext.put("myFileNameVar", "file2");
LOG.info("This should appear in file2.log");
}
}
The configuration looks like this:
<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="WARN">
<Appenders>
<Routing name="myAppender">
<Routes pattern="$${ctx:myFileNameVar}">
<Route>
<File
fileName="logs/${ctx:myFileNameVar}.log"
name="myAppender-${ctx:myFileNameVar}">
<PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n"/>
</File>
</Route>
</Routes>
</Routing>
</Appenders>
<Loggers>
<Root level="trace">
<AppenderRef ref="myAppender" />
</Root>
</Loggers>
</Configuration>
The result of running the above code will be two files - file1.log an file2.log each with a single entry. The file1.log will contain the first log message and file2.log will contain the second message.
Hope this helps!

Log4j2: Empty log file in case of parallel tests

I have in my test automation project problem with logging. I'm using log4j2 logger with FileAppender. The way I'm using it is:
Logger logger = (Logger) LogManager.getLogger(loggerName);
Appender appender = FileAppender.newBuilder()
.withAppend(false)
.withBufferedIo(true)
.withFileName(DIR_NAME + File.separator + loggerName + ".log")
.withIgnoreExceptions(false)
.withImmediateFlush(true)
.withLocking(false)
.withLayout(PatternLayout.newBuilder().withPattern("%d{HH:mm:ss.SSS} [%-5level] %msg%n").withCharset(Charset.forName("UTF-8")).build())
.withName(loggerName)
.build();
appender.start();
logger.addAppender(appender);
It works when I'm running single test. All data are visible in console, the file is created and test log is written in the file. Problem occurs in case of tests are running in parallel - in different threads.
In this case, two different loggers and file appenders are created. Log files from both file appenders are created too and logs from both tests are visible in console. Everything seems to be fine, but every time one of these log files is empty. The empty log belongs to test which started later.
I suspect problem with caching. The first file appender holds all cache for writing so the second one is not able to write. Am I right? What is the solution for this?
Thank you.
You should be able to achieve what you want without using programmatic configuration. There are many reasons not to configure log4j2 programmatically, but the best one, in my opinion, is that in doing so you would make your code dependent on aspects of log4j2 that are not part of the public API. This means that if the implementation of log4j2 changes your code has to change as well. This creates more work for you in the long run.
So, with that in mind I will provide a demo of how to set up log4j2 using an XML config file such that it will generate separate logs for each test. I am assuming, since it was not specified in your question, that your goal is to create a log for each method with a Test annotation and that each of these methods is executed in parallel.
First, here is my TestNG class:
package testpkg;
import java.lang.reflect.Method;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.apache.logging.log4j.ThreadContext;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.Test;
public class NewTest {
private static final Logger log = LogManager.getLogger();
#BeforeMethod
public void setThreadName(Method method){
ThreadContext.put("threadName", method.getName());
}
#Test
public void test1() {
log.info("This is the first test!");
log.warn("Something may be wrong, better take a look.");
}
#Test
public void test2() {
log.info("Here's the second test!");
log.error("There's a problem, better fix it");
}
}
As you can see here I have two Test methods and a BeforeMethod called setThreadName. The setThreadName method is, obviously, executed before each of the Test methods. It places a key named threadName into the log4j2 ThreadContext using the name of the method that is about to be run. This will be used as part of the log file name in the log4j2 config file.
Here is the log4j2.xml file:
<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="WARN">
<Appenders>
<Routing name="MyRoutingAppender">
<Routes pattern="$${ctx:threadName}">
<Route>
<File
fileName="logs/${ctx:threadName}.log"
name="appender-${ctx:threadName}"
append="false">
<PatternLayout>
<Pattern>[%date{ISO8601}][%-5level][%t] %m%n</Pattern>
</PatternLayout>
</File>
</Route>
</Routes>
</Routing>
<Console name="STDOUT" target="SYSTEM_OUT">
<PatternLayout pattern="[%date{ISO8601}][%-5level][%t] %m%n" />
</Console>
</Appenders>
<Loggers>
<Logger name="testpkg" level="TRACE" additivity="false">
<AppenderRef ref="STDOUT" />
<AppenderRef ref="MyRoutingAppender" />
</Logger>
<Root level="WARN">
<AppenderRef ref="STDOUT" />
</Root>
</Loggers>
</Configuration>
As you can see I've set up the config file to use a RoutingAppender to dynamically generate appenders at runtime based on the ThreadContext key threadName and that threadName is also used in the fileName attribute of the FileAppender.
Here is my testNG config file:
<!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd" >
<suite name="My suite" parallel="methods" thread-count="5" verbose="1">
<test name="testpkg" >
<classes>
<class name="testpkg.NewTest" />
</classes>
</test>
</suite>
As you can see here I've set it up so that each Test method within my class is run in parallel.
When executed this results in the following console output:
[RemoteTestNG] detected TestNG version 6.14.3
[2018-05-04T21:54:54,703][INFO ][TestNG-test=testpkg-2] Here's the second test!
[2018-05-04T21:54:54,703][INFO ][TestNG-test=testpkg-1] This is the first test!
[2018-05-04T21:54:54,709][WARN ][TestNG-test=testpkg-1] Something may be wrong, better take a look.
[2018-05-04T21:54:54,709][ERROR][TestNG-test=testpkg-2] There's a problem, better fix it
===============================================
My suite
Total tests run: 2, Failures: 0, Skips: 0
===============================================
You can clearly see that the output of the two methods is interleaved, so we know that the methods are indeed running in parallel.
The execution of the test class also creates two log files as expected. They are named test1.log and test2.log
Here are their contents:
test1.log:
[2018-05-04T21:54:54,703][INFO ][TestNG-test=testpkg-1] This is the first test!
[2018-05-04T21:54:54,709][WARN ][TestNG-test=testpkg-1] Something may be wrong, better take a look.
test2.log:
[2018-05-04T21:54:54,703][INFO ][TestNG-test=testpkg-2] Here's the second test!
[2018-05-04T21:54:54,709][ERROR][TestNG-test=testpkg-2] There's a problem, better fix it
So we see here that as expected the logs from the first method went to test1.log and the logs from the second method went to test2.log
Enjoy!

How to use org.perf4j.log4j.AsyncCoalescingStatisticsAppender in log4j2?

Below is the sample used in log4j 1.x. I am not getting any example to convert the same in log4j2.
<appender name="CoalescingStatisticsAppender"
class="org.perf4j.log4j.AsyncCoalescingStatisticsAppender">
<!--
The TimeSlice option is used to determine the time window for which
all received StopWatch logs are aggregated to create a single
GroupedTimingStatistics log. Here we set it to 10 seconds, overriding
the default of 30000 ms
-->
<param name="TimeSlice" value="30000" />
<appender-ref ref="perf4jFileAppender" />
</appender>
The Appender won't work as is in Log4j 2. It would have to be rewritten.
You may be interested to know that Log4j 2 supports nanoTime timestamps in PatternLayout. This, in combination with the low overhead Async Loggers, allow you to use Log4j as a rough profiling tool.

Disable freemarker logs from logs4j

Similar question but i'm using log4j2.
I need a way to disable All logs from freemarker, in their documentation they say we can do it by calling Logger.selectLoggerLibrary(Logger.LIBRARY_NONE) but they say
selectLoggerLibrary must be called early, before FreeMarker could log anything, or else it will not have (consistent) effect.
Where do I call this in a struts2 application? (I tried calling it in prepare() method in my action class but its not working.) or is there any other way to disable the logs?
Question is, why do you need to disable it like that?
You shouldn't need that, so I guess that's where the real problem lies. Is there some kind of malfunction? Because if there isn't, why not just set the freemarker logger category to be ignored in your logger configuration? That's the normal way of doing this, FreeMarker or not.
Anyway, in 2.3.22 (release expected in early 2015) you can use the -Dorg.freemarker.loggerLibrary=none where you start the JVM (that is, you set the org.freemarker.loggerLibrary system property). Otherwise, if you could call that method in a ServletContextListener that's certainly early enough.
Update:
Reacting to the comments... in most applications you will have 3rd party libraries that use various logging "frameworks", like SLF4J, commons-logging, JUL, Log4j, Log4j2. Thus you have to ensure that all these get redirected into the same logger library, which is certainly Log4j2 in your case. I suspect that wasn't properly done in your case, so now multiple logger libraries log to the console, each with its own configuration settings.
FreeMarker 2.3.x uses Log4j 1.x if it detects that org.apache.log4j.Logger is present. Other logger libraries that it also can detect and use (Log4j2 is not amongst them) have lower priority. (FreeMarker 2.4.x will always use SLF4J if it's present.) Thus, if you add org.apache.logging.log4j:log4j-1.2-api to your dependencies, then FM will use org.apache.log4j.Logger, and so log4j-1.2.-api will redirect the FM log messages to Log4j2. That worked for me, with this Log4j2 configuration:
<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="WARN">
<Appenders>
<Console name="Console" target="SYSTEM_OUT">
<PatternLayout pattern="%d{HH:mm:ss.SSS} %-5level %logger{36} - %msg%n" />
</Console>
</Appenders>
<Loggers>
<Root level="debug">
<AppenderRef ref="Console" />
</Root>
<Logger name="freemarker" level="off">
<AppenderRef ref="Console" />
</Logger>
</Loggers>
</Configuration>
This came up as the first search result for "disable freemarker logging" which I searched for because I got double error logs for template errors, one from within the Freemarker library and one from my own code catching the same exception and logging it. The solution to this is simple and different from the answers already given: call setLogTemplateExceptions(false) on the Freemarker Configuration. In full:
Configuration configuration = new Configuration(Configuration.VERSION_2_3_31);
configuration.setLogTemplateExceptions(false);
The default behavior of logging the exception even though it propagates out of the Freemarker library is mentioned as a quirk on the Freemarker Logging documentation.
Use this statement:
freemarker.log.Logger.selectLoggerLibrary(freemarker.log.Logger.LIBRARY_NONE);

Resources