Custom ThrowableRenderer not working log4j 1.x - java

I am trying to get a custom throwableRenderer to work with log4j 1.2.17.
Note that I cannot upgrade to log4j2 at this stage so I am looking for 1.x solution.
See e.g.
How to make log4j syslog appender write a stack trace in one line?
I am trying to do just that - get the stack trace to be printed on 1 line. I tried 2 approaches I could find on the web - using custom renderer and using Enhanced Pattern Layout. Still no luck!
But the class WRThrowableRenderer (which is my custom renderer)
and its method doRender is simply not called.
This is all in a web app running inside WildFly 8 (Java 8).
I tried at least 10 different things while testing the two approaches but nothing works.
What am I doing wrong?!
Also, is this renderer supposed to affect all loggers and change their behavior when an exception is logged? I think so. I am asking this because I have child loggers under this rootLogger. And they all log via the rootLogger in one single file.
log4j.rootLogger=INFO, stdout
log4j.throwableRenderer=com.yb.common.logging.WRThrowableRenderer
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.EnhancedPatternLayout
# log4j.appender.stdout.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss.SSS} %-5p [%t] ###%c{20}:%L### - [[[%m]]]%n
# log4j.appender.stdout.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss.SSS} %-5p [%t] ###%c{20}### [[[%m]]]%n %throwable{separator(|)}
log4j.appender.stdout.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss.SSS} %-5p [%t] ###%c{20}### [[[%m]]]%n
# log4j.appender.stdout.layout.ConversionPattern=%m%n
log4j.appender.stdout.threshold=INFO
log4j.appender.stdout.immediateFlush=true

I am trying to do just that - get the stack trace to be printed on 1 line. I tried 2 approaches I could find on the web - using custom renderer and using Enhanced Pattern Layout.
Without a custom ThrowableRenderer
If you want the stack trace all on one line without using a custom ThrowableRenderer, the best you'll be able to do is get the first line of the stack trace.
For example, using this configuration:
log4j.rootLogger=INFO, stdout
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.EnhancedPatternLayout
log4j.appender.stdout.layout.ConversionPattern=[%d] %-5p %m %throwable{short}%n
Will generate this log:
[2020-11-20 10:54:53,454] ERROR Test error message, with stack trace java.lang.IllegalArgumentException: Test exception message
With a custom ThrowableRenderer
If you want the entire stack trace printed on one line, you'll need to use a custom ThrowableRenderer.
Create the custom ThrowableRenderer, e.g.
package org.example;
import org.apache.log4j.DefaultThrowableRenderer;
import org.apache.log4j.spi.ThrowableRenderer;
import java.util.ArrayList;
import java.util.Arrays;
public class CustomThrowableRenderer implements ThrowableRenderer {
private final DefaultThrowableRenderer defaultRenderer = new DefaultThrowableRenderer();
#Override
public String[] doRender(Throwable throwable) {
String[] defaultRepresentation = defaultRenderer.doRender(throwable);
String[] newRepresentation = {String.join("|", Arrays.asList(defaultRepresentation))};
return newRepresentation;
}
}
Configure log4j1 to use the custom ThrowableRenderer
log4j.throwableRenderer=org.example.CustomThrowableRenderer
At this point, the stack trace portion of the log will all be on one line, although it may be on a separate line from the rest of the log.
For example, your configuration from above:
log4j.rootLogger=INFO, stdout
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.EnhancedPatternLayout
log4j.appender.stdout.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss.SSS} %-5p [%t] ###%c{20}### [[[%m]]]%n
log4j.throwableRenderer=org.example.CustomThrowableRenderer
Will generate two lines because the stack trace is put on its own line by default:
2020-11-20 11:45:04.706 ERROR [main] ###org.example.App### [[[Test error message, with stack trace]]]
java.lang.IllegalArgumentException: Test exception message| at org.example.App.logErrorWithStackTrace(App.java:31)| at org.example.App.okayThatsEnough(App.java:25)| at org.example.App.notLongEnough(App.java:21)| at org.example.App.makeStackTraceLonger(App.java:17)| at org.example.App.testLoggingWithStackTraces(App.java:13)| at org.example.App.main(App.java:9)
You can get the error message and stack trace on one line by using %throwable in your pattern:
log4j.appender.stdout.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss.SSS} %-5p [%t] ###%c{20}### [[[%m]]] %throwable%n
However a blank line will be generated after:
2020-11-20 11:46:46.897 ERROR [main] ###org.example.App### [[[Test error message, with stack trace]]] java.lang.IllegalArgumentException: Test exception message| at org.example.App.logErrorWithStackTrace(App.java:31)| at org.example.App.okayThatsEnough(App.java:25)| at org.example.App.notLongEnough(App.java:21)| at org.example.App.makeStackTraceLonger(App.java:17)| at org.example.App.testLoggingWithStackTraces(App.java:13)| at org.example.App.main(App.java:9)
That could probably be fixed as well but it might require a custom appender.
I made a small sample app you can use as a reference: https://github.com/bmaupin/junkpile/tree/master/java/log4j1-custom-throwablerenderer

Related

how to find out the full name of Java class in DropWizard logs

We are using DropWizard in a Java based micro-service. In the logs, we have lines like:
[dw-1000 - POST myservice/endpoint] c.s.x.m.s.c.p2p - my error message
My question is: how can I find out the full names of the Java class path represented as "c.s.x.m.s.c.p2p" in the above log message?
Thanks.
You need to change the default configuration in your yaml:
The logFormat is the key to your solution - %c displays the full logger name, and if there is no number followed, it's the full name with no name-cuts:
logging:
appenders:
- type: file
...
logFormat: '[%d{yyyy-MM-dd HH:mm:ss.SSS}] [%-5level] [%c] [%thread] [-[%msg]-] %n'

how to make Log4j configuration properly

I am new to the Log4j framework and after reading some stuff i got some fare idea about logging mechanism, but still
i have some doubt about the following properties.
log4j.category.com.cloud.sample=INFO, file, C
log4j.additivity.com.cloud.sample=true
log4j.appender.C=org.apache.log4j.ConsoleAppender
log4j.appender.C.Target=System.out
log4j.appender.C.ImmediateFlush=true
log4j.appender.C.layout=org.apache.log4j.PatternLayout
log4j.appender.C.layout.ConversionPattern=%-5p %d [%t] %m%n
#log4j.rootLogger=INFO, A1
log4j.appender.A1=org.apache.log4j.ConsoleAppender
log4j.appender.A1.layout=org.apache.log4j.PatternLayout
log4j.appender.A1.layout.ConversionPattern=%d [%t] %-5p %c - %m%n
### direct messages to file ###
log4j.appender.file=org.apache.log4j.RollingFileAppender
log4j.appender.file.File=${catalina.home}/var/basic/logs/sample.log
log4j.appender.file.Append=true
log4j.appender.file.MaxFileSize=10MB
# mylog.log.10 \u307e\u3067\u4fdd\u6301
log4j.appender.file.MaxBackupIndex=50
log4j.appender.file.layout=org.apache.log4j.PatternLayout
log4j.appender.file.layout.ConversionPattern=%d %5p [%t] %c{1} - %m%n
log4j.rootLogger=INFO, C, file
In the first line of the above code contains two appenders(file, C) after that we will be having appender for both file and C. So as per my understanding logs will of category will be stored to Console and sample.log. Please let me know if i am wrong.
log4j.rootLogger=INFO, A1 and respective properties are not used right?
log4j.rootLogger=INFO, C, file: This line is about root logger, I think in my case it is not useful, because it is defined at the last line and there is no properties defined over here.
Please could any body confirm my understanding and suggest me if any changes required in the above configuration
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).

log4j:ERROR while writing the logs statements in file

I have created a java project called Project1. for this project i created a log4j.properties file. For writing the log statements in log file, i used DailyRollingFileAppenders. I am using log4j-1.2.16.jar. The log file is :
log4j.logger.com.gridsense.server.automode=DEBUG, stdout,Rollfile
log4j.rootLogger=off
log4j.logger.com.gridsense.server.automode=debug,Rollfile,stdout
log4j.appender.Rollfile=org.apache.log4j.DailyRollingFileAppender
log4j.appender.Rollfile.ImmediateFlush=false
log4j.appender.Rollfile.Append=true
log4j.appender.Rollfile.Threshold=DEBUG
log4j.appender.Rollfile.bufferedIO = true
log4j.appender.Rollfile.File=D:/logs/AutoGS.log
log4j.appender.Rollfile.layout=org.apache.log4j.PatternLayout
log4j.appender.Rollfile.layout.ConversionPattern=[%t] %-5p %c %d{dd/MM/yyyy HH:mm:ss} %m%n
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.Threshold=DEBUG
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%-4r [%t] %-5p %c %x %m%n
When i run the project i get the following error
log4j:ERROR Could not close org.apache.log4j.helpers.QuietWriter#1105348
java.io.IOException: The handle is invalid
at java.io.FileOutputStream.writeBytes(Native Method)
at java.io.FileOutputStream.write(FileOutputStream.java:282)
at sun.nio.cs.StreamEncoder.writeBytes(StreamEncoder.java:202)
at sun.nio.cs.StreamEncoder.implWrite(StreamEncoder.java:263)
at sun.nio.cs.StreamEncoder.write(StreamEncoder.java:106)
at java.io.OutputStreamWriter.write(OutputStreamWriter.java:190)
at java.io.BufferedWriter.flushBuffer(BufferedWriter.java:111)
at java.io.BufferedWriter.close(BufferedWriter.java:246)
at java.io.FilterWriter.close(FilterWriter.java:87)
at org.apache.log4j.FileAppender.closeFile(FileAppender.java:185)
at org.apache.log4j.FileAppender.reset(FileAppender.java:343)
at org.apache.log4j.WriterAppender.close(WriterAppender.java:207)
at org.apache.log4j.AppenderSkeleton.finalize(AppenderSkeleton.java:144)
at java.lang.ref.Finalizer.invokeFinalizeMethod(Native Method)
at java.lang.ref.Finalizer.runFinalizer(Finalizer.java:83)
at java.lang.ref.Finalizer.access$100(Finalizer.java:14)
at java.lang.ref.Finalizer$FinalizerThread.run(Finalizer.java:160)
log4j:ERROR Failed to write [[DefaultQuartzScheduler_Worker-2] DEBUG com.gridsense.server.automode.backgroundWorker.TimerTaskToBeFired 03/05/2013 17:34:45 ? TimerTaskToBeFired.execute - firing timer job with Key [DropBoxFileFetchingSchedulerGroup.JobDetail-ID-1]].
I don't understand what is the problem.
My reading of the stacktrace is that something has leaked a FileAppender object, and that appender's finalize method is attempting to clean it up. But it looks like that is failing because the resource in question has already been closed.
That's the easy part. The hard part is identifying the source of the leak. My guess is that it is caused by this line:
log4j.logger.com.gridsense.server.automode=debug,Rollfile,stdout
which appears to be configuring a second logger tree duplicating the one configure a couple of lines earlier.

how to configure log4j to log sql statements from mybatis

I am using MyBatis3 I need a way to log all my select, insert, update statements to my log4j log file.
Here is my log4j file. Please help
# Root logger option
log4j.rootLogger=INFO, file, stdout
# Direct log messages to a log file
log4j.appender.file=org.apache.log4j.RollingFileAppender
log4j.appender.file.File=test.log
log4j.appender.file.MaxFileSize=2MB
log4j.appender.file.MaxBackupIndex=1
log4j.appender.file.layout=org.apache.log4j.PatternLayout
log4j.appender.file.layout.ConversionPattern=%d{ABSOLUTE} %5p %c{1}:%L - %m%n
# Direct log messages to stdout
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.Target=System.out
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%d{ABSOLUTE} %5p %c{1}:%L - %m%n
You can see the Log4J configuration info here. In short - you need to set Log4J loglevel to DEBUG or TRACE on your mapper or mapper package or specific mapper method. E.g. log4j.logger.org.mybatis.example.BlogMapper.selectBlog=TRACE. TRACE will print SQL, params and resultsets, and DEBUG will print SQL and params only.
I found a way, putting in so others can benefit too
In order to log sql statements download Simple Logging Facade for Java (download slf4j here)
Added the following to my classpath, apart from regular mybatis, odbc and oracle jars
log4j-xxxx.jar
log4j-over-slf4j-xxxx.jar
log4j-rolling-appender.jar
slf4j-api-xxxx.jar
slf-log4j12-xxxx.jar
Note: xxxx is appropriate version here
and append the following lines in my log4j (see my question)
# logger debug
log4j.logger.test.Log4jTestMyBatis=DEBUG, convert
log4j.appender.convert = org.apache.log4j.ConsoleAppender
log4j.appender.convert.layout=org.apache.log4j.PatternLayout
log4j.appender.convert.layout.ConversionPattern=[%d{HH:mm:ss}] %-5p %c{3} %x - %m%n
# end logger debug
# mybatis loggers #
log4j.logger.com.ibatis=DEBUG, convert
log4j.logger.com.ibatis.common.jdbc.SimpleDataSource=DEBUG, convert
log4j.logger.com.ibatis.common.jdbc.ScriptRunner=DEBUG, convert
log4j.logger.com.ibatis.sqlmap.engine.impl.SqlMapClientDelegate=DEBUG, convert
Here is a Groovy class example that I used for testing
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.apache.ibatis.session.SqlSession;
import org.apache.log4j.PropertyConfigurator;
import com.abc.db.ConfigInfo;
import com.abc.db.ConfigInfoExample;
import com.abc.db.client.ConfigInfoMapper;
import com.abc.db.init.DatabaseConnectivity;
class Log4jTestMyBatis {
static Logger logger = LoggerFactory.getLogger(Log4jTestMyBatis.class)
static main(args) {
PropertyConfigurator.configure(Log4jTestMyBatis.class.getResource("log4j.properties"));
DatabaseConnectivity.init()
SqlSession newABCSession = DatabaseConnectivity.getNewABCSessionFactory().openSession()
ConfigInfoMapper mapper = newABCSession.getMapper(ConfigInfoMapper.class)
ConfigInfoExample qExample = new ConfigInfoExample()
qExample.createCriteria().andProjectIdEqualTo("0-12170")
List<ConfigInfo> ctlist = mapper.selectByExample(qExample)
logger.debug(ctlist.get(0).getCfgName())
newABCSession.close()
logger.debug("debug")
}
}

Log4j Logging to multiple files

In my Java console app, I want to log certain events to a log file and certain others to console. This is what I've got now
log4j.rootLogger=error, stdout
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.Target=System.out
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%d{ABSOLUTE} %5p %c{1}:%L - %m%n
log4j.appender.L1=org.apache.log4j.FileAppender
log4j.appender.L1.layout=org.apache.log4j.PatternLayout
log4j.appender.L1.layout.ConversionPattern=%-22d{dd/MMM/yyyy HH:mm:ss} – %m%n
log4j.appender.L1.file=failedtoaddusers.log
In my Java app, I instantiate two log instances using
private static Logger log = Logger.getLogger(ActiveDirectoryManage.class);
private static Logger failedToAddUsersLogger = Logger.getLogger("FailedToAddUsersLogging");
My issue is that failedToAddUsersLogger.warn("xyz") also writes to the console in addition to the log file failedtoaddusers.log.
I just want it to write to the log file and not to the console.
How do I accomplish that?
You need to set additivity to "false" (read more on logger additivity in the Appenders and Layouts section of the log4j manual):
log4j.additivity.FailedToAddUsersLogging=false
log4j.logger.FailedToAddUsersLogging = your level, L1
Also, make sure you have one of new versions of log4j, "additivity" setting was not available from beginning.

Categories