I'd like Log4j2 to output a complete Java stack trace only once when an exception is first raised and not repeat that information as exceptions are propagated up the call chain. I'm trying to figure out what custom Log4j2 components would implement this minimal call chain logging strategy.
I'm creating a custom layout based on PatternLayout and wondering if I need to create my own PatternSelector. Before I get too far down this path, I'd love advice from those that understand the internals of Log4j2 (v2.13.3).
The following pseudocode illustrates the problem.
m0() {try {m1();} catch (Exception e) {log.error("emsg0", e);} }
m1() {try {m2();} catch (Exception e) {log.error("msg1", e); throw new Exception("emsg1", e);} }
m2() {try {m3();} catch (Exception e) {log.error("msg2", e); throw new Exception("emsg2", e);} }
m3() {_log.error("msg3"); throw new Exception("emsg3"); }
Here are the log records when the real code runs:
14:08:47.425 [main] ERROR edu.utexas.tacc.log4j2.Log4j2TestA - msg3
14:08:47.426 [main] ERROR edu.utexas.tacc.log4j2.Log4j2TestA - msg2
java.lang.Exception: emsg3
at edu.utexas.tacc.log4j2.Log4j2TestA.m3(Log4j2TestA.java:24)
at edu.utexas.tacc.log4j2.Log4j2TestA.m2(Log4j2TestA.java:22)
at edu.utexas.tacc.log4j2.Log4j2TestA.m1(Log4j2TestA.java:19)
at edu.utexas.tacc.log4j2.Log4j2TestA.m0(Log4j2TestA.java:17)
at edu.utexas.tacc.log4j2.Log4j2TestA.main(Log4j2TestA.java:14)
14:08:47.431 [main] ERROR edu.utexas.tacc.log4j2.Log4j2TestA - msg1
java.lang.Exception: emsg2
at edu.utexas.tacc.log4j2.Log4j2TestA.m2(Log4j2TestA.java:23)
at edu.utexas.tacc.log4j2.Log4j2TestA.m1(Log4j2TestA.java:19)
at edu.utexas.tacc.log4j2.Log4j2TestA.m0(Log4j2TestA.java:17)
at edu.utexas.tacc.log4j2.Log4j2TestA.main(Log4j2TestA.java:14)
Caused by: java.lang.Exception: emsg3
at edu.utexas.tacc.log4j2.Log4j2TestA.m3(Log4j2TestA.java:24)
at edu.utexas.tacc.log4j2.Log4j2TestA.m2(Log4j2TestA.java:22)
... 3 more
14:08:47.432 [main] ERROR edu.utexas.tacc.log4j2.Log4j2TestA - msg0
java.lang.Exception: emsg1
at edu.utexas.tacc.log4j2.Log4j2TestA.m1(Log4j2TestA.java:20)
at edu.utexas.tacc.log4j2.Log4j2TestA.m0(Log4j2TestA.java:17)
at edu.utexas.tacc.log4j2.Log4j2TestA.main(Log4j2TestA.java:14)
Caused by: java.lang.Exception: emsg2
at edu.utexas.tacc.log4j2.Log4j2TestA.m2(Log4j2TestA.java:23)
at edu.utexas.tacc.log4j2.Log4j2TestA.m1(Log4j2TestA.java:19)
... 2 more
Caused by: java.lang.Exception: emsg3
at edu.utexas.tacc.log4j2.Log4j2TestA.m3(Log4j2TestA.java:24)
at edu.utexas.tacc.log4j2.Log4j2TestA.m2(Log4j2TestA.java:22)
at edu.utexas.tacc.log4j2.Log4j2TestA.m1(Log4j2TestA.java:19)
... 2 more
Here's what I'd rather see:
14:08:47.425 [main] ERROR edu.utexas.tacc.log4j2.Log4j2TestA - msg3
14:08:47.426 [main] ERROR edu.utexas.tacc.log4j2.Log4j2TestA - msg2
java.lang.Exception: emsg3
at edu.utexas.tacc.log4j2.Log4j2TestA.m3(Log4j2TestA.java:24)
at edu.utexas.tacc.log4j2.Log4j2TestA.m2(Log4j2TestA.java:22)
at edu.utexas.tacc.log4j2.Log4j2TestA.m1(Log4j2TestA.java:19)
at edu.utexas.tacc.log4j2.Log4j2TestA.m0(Log4j2TestA.java:17)
at edu.utexas.tacc.log4j2.Log4j2TestA.main(Log4j2TestA.java:14)
14:08:47.431 [main] ERROR edu.utexas.tacc.log4j2.Log4j2TestA - msg1
java.lang.Exception: emsg2
Caused by: java.lang.Exception: emsg3
14:08:47.432 [main] ERROR edu.utexas.tacc.log4j2.Log4j2TestA - msg0
java.lang.Exception: emsg1
Caused by: java.lang.Exception: emsg2
Caused by: java.lang.Exception: emsg3
Any guidance is appreciated,
Rich
You would need to create a custom ThrowablePatternConverter. But doing this probably isn't a good idea. In real life where apps run for a long time (days, weeks, or months) you might not see the exception for long periods of time and only seeing a 1 line caused by might get a bit frustrating since the root caused by exception is typically the most interesting one.
In addition, caching the exceptions and trying to do matching would make processing the exceptions pretty slow.
I think the best solution to this problem is to take njzk2's advice and either log or throw an exception, but don't do both. As long as the code is reasonably well structured, each exception will get logged exactly once and Log4j2 will record the complete exception chain in an acceptable way.
Related
We are using log4j2 for logging. After doing initial benchmark I have concluded that for same QPS, logging exception is 80 times slower than logging normal message.
Here is a sample error log message.
2022-08-25 11:09:14,699 - [pool-2-thread-1][{id=eb9bcf4f-1dcc-4cd7-8588-fd7916d623b8, path=/hellowworld}] - [Test2] ERROR - error wile doing something important java.lang.RuntimeException: exception
at Test2.recursiveCount(Test2.java:140) ~[logging.jar:?]
at Test2.recursiveCount(Test2.java:142) ~[logging.jar:?]
at Test2.recursiveCount(Test2.java:142) ~[logging.jar:?]
at Test2.access$000(Test2.java:17) ~[logging.jar:?]
at Test2$LoggerRunnable.run(Test2.java:75) ~[logging.jar:?]
at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511) ~[?:1.8.0_202]
at java.util.concurrent.FutureTask.run(FutureTask.java:266) ~[?:1.8.0_202]
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149) ~[?:1.8.0_202]
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624) ~[?:1.8.0_202]
at java.lang.Thread.run(Thread.java:748) [?:1.8.0_202]
Here is a sample log message
2022-08-25 18:12:02,125 - [pool-2-thread-1][{id=90e8ebda-e02a-4c48-bc37-560190bda40a, path=/hellowworld}] - [Test2] INFO - adding log with number=ok uuid=1661431322125
It could be attributed to
Note: Logging exceptions and stack traces will create temporary objects with any layout. (However, Layouts will only create these temporary objects when an exception actually occurs.) We haven't figured out a way to log exceptions and stack traces without creating temporary objects. That is unfortunate, but you probably still want to log them when they happen.
source log4j2 documentation
Are there any config change that can be done to reduce the overhead of exception logging? Like
For similar stacktrace errors only log few sample stacktrace and not all the stack traces
limiting the deapth of stacktrace?
anything else?
Like in this picture
I know that both of them works fine but I just wanted to know how are they different from each other? PS: I am a beginner.
A LogEvent can contain both a message and an exception. If you use the first form:
LOGGER.error(exception.getMessage());
only the error message will be recorded and you'll have a similar output in your logs (depends upon the layout):
[ERROR] - Exception message.
If you use the second form:
LOGGER.error(exception.getMessage(), exception);
you'll have both a message and an exception. This typically outputs the stack trace in the logs:
[ERROR] - Exception message.
java.lang.RuntimeException: Exception message.
at pl.copernik.log4j.Log4j2Test.run(Log4j2Test.java:19) [classes/:?]
at pl.copernik.log4j.Log4j2Test.main(Log4j2Test.java:15) [classes/:?]
Since you can always configure Log4j 2.x to suppress stack traces from the output (see alwaysWriteExceptions in the PatternLayout documentation), the second form is always better, as it provides more information.
Remark: Since the stack trace always prints the error's message, I'd suggest a third form:
LOGGER.error("An unexpected condition occurred while performing foo: {}",
exception.getMessage(), exception);
This way you can explain the context, when the exception occurred:
[ERROR] - An unexpected condition occurred while performing foo: Exception message.
java.lang.RuntimeException: Exception message.
at pl.copernik.log4j.Log4j2Test.run(Log4j2Test.java:19) [classes/:?]
at pl.copernik.log4j.Log4j2Test.main(Log4j2Test.java:15) [classes/:?]
I'm facing some weird NPE with no details thrown by org.springframework.integration.handler.LoggingHandler. The previous log entry is 2 minutes before which is also strange.
Does anyone have any idea what can be the reason behind it?
2017-07-25 18:33:38.561 DEBUG o.s.b.f.s.DefaultListableBeanFactory : Returning cached instance of singleton bean 'markEodPositionsAsProcessedChannel'
2017-07-25 18:35:36.985 ERROR o.s.integration.handler.LoggingHandler : org.springframework.messaging.MessageHandlingException: nested exception is java.lang.NullPointerException
at org.springframework.integration.handler.MethodInvokingMessageProcessor.processMessage(MethodInvokingMessageProcessor.java:96)
at org.springframework.integration.handler.ServiceActivatingHandler.handleRequestMessage(ServiceActivatingHandler.java:89)
at org.springframework.integration.handler.AbstractReplyProducingMessageHandler.handleMessageInternal(AbstractReplyProducingMessageHandler.java:109)
at org.springframework.integration.handler.AbstractMessageHandler.handleMessage(AbstractMessageHandler.java:127)
at org.springframework.integration.dispatcher.AbstractDispatcher.tryOptimizedDispatch(AbstractDispatcher.java:116)
at org.springframework.integration.dispatcher.UnicastingDispatcher.doDispatch(UnicastingDispatcher.java:148)
at org.springframework.integration.dispatcher.UnicastingDispatcher.access$000(UnicastingDispatcher.java:53)
at org.springframework.integration.dispatcher.UnicastingDispatcher$3.run(UnicastingDispatcher.java:129)
at org.springframework.integration.util.ErrorHandlingTaskExecutor$1.run(ErrorHandlingTaskExecutor.java:55)
at java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)
at java.lang.Thread.run(Unknown Source)
Caused by: java.lang.NullPointerException
The code you talk about looks like:
public T processMessage(Message<?> message) {
try {
return this.delegate.process(message);
}
catch (Exception e) {
throw new MessageHandlingException(message, e);
}
}
The clearly means that delegate.process() throws NPE somehow.
According to the StackTrace you have some Service Activator to call your POJO service method. And that looks like exactly your method already throws that NPE.
I also believe that there is something else in the StackTrace after Caused by: java.lang.NullPointerException.
You see that as an ERROR in your logs, because you have some polling flow starting from some source - Inbound Channel Adapter. And any exception thrown downstream are caught by the error handler in the Poller Ednpoint and sent to the errorChannel with the LoggingHandler as a default subscriber.
See Reference Manual for more info.
I am getting the following error in the OPC client code.
I start my client- close it - start it again to see the following error.
It is clear that something from previous run is causing it. But I am unable to figure out what it is.
When I diff the jstack of my first run and close. I do not see any running thread from opc.
Has anyone seen this issue? Or
Is there some other way I can debug the issue?
2016-05-19 16:35:53,564 WARN [netty-event-loop-0] io.netty.channel.ChannelInitializer - Failed to initialize a channel. Closing: [id: 0xe25cac5b] java.lang.ExceptionInInitializerError
at com.digitalpetri.opcua.stack.client.UaTcpStackClient$1.initChannel(UaTcpStackClient.java:340)
at com.digitalpetri.opcua.stack.client.UaTcpStackClient$1.initChannel(UaTcpStackClient.java:337)
at io.netty.channel.ChannelInitializer.channelRegistered(ChannelInitializer.java:69)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRegistered(AbstractChannelHandlerContext.java:133)
at io.netty.channel.AbstractChannelHandlerContext.fireChannelRegistered(AbstractChannelHandlerContext.java:119)
at io.netty.channel.DefaultChannelPipeline.fireChannelRegistered(DefaultChannelPipeline.java:733)
at io.netty.channel.AbstractChannel$AbstractUnsafe.register0(AbstractChannel.java:449)
at io.netty.channel.AbstractChannel$AbstractUnsafe.access$100(AbstractChannel.java:377)
at io.netty.channel.AbstractChannel$AbstractUnsafe$1.run(AbstractChannel.java:423)
at io.netty.util.concurrent.SingleThreadEventExecutor.runAllTasks(SingleThreadEventExecutor.java:380)
at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:357)
at io.netty.util.concurrent.SingleThreadEventExecutor$2.run(SingleThreadEventExecutor.java:116)
at java.lang.Thread.run(Thread.java:745) Caused by: java.lang.IllegalArgumentException: 'awaiting-handshake' is already in use
at io.netty.util.UniqueName.<init>(UniqueName.java:53)
at io.netty.util.AttributeKey.<init>(AttributeKey.java:47)
at io.netty.util.AttributeKey.valueOf(AttributeKey.java:39)
at com.digitalpetri.opcua.stack.client.handlers.UaTcpClientAcknowledgeHandler.<clinit>(UaTcpClientAcknowledgeHandler.java:44)
... 13 more
Looks like you might have some kind of ClassLoader issue - a static final field of UaTcpAcknowledgeHandler is being defined twice somehow.
What exactly happens when you "close" your client?
I'm chasing what should be a simple NullPointerException but a webservice proxy keeps swallowing the error.
The WS is exposed through a simple client library, that client then calls the WS. Somewhere in the WS theres an NPE and I can't find it because the stack trace only shows "$Proxy.someMethod" instead of the cause of the issue.
How can I get the stack trace from the proxy object? Is there a good strategy to log or handle these exceptions?
...
Caused by: javax.xml.ws.soap.SOAPFaultException: java.lang.NullPointerException
at com.sun.xml.ws.fault.SOAP11Fault.getProtocolException(SOAP11Fault.java:187)
at com.sun.xml.ws.fault.SOAPFaultBuilder.createException(SOAPFaultBuilder.java:116)
at com.sun.xml.ws.client.sei.SyncMethodHandler.invoke(SyncMethodHandler.java:254)
at com.sun.xml.ws.client.sei.SyncMethodHandler.invoke(SyncMethodHandler.java:224)
at com.sun.xml.ws.client.sei.SEIStub.invoke(SEIStub.java:117)
******** I need the trace from this line *********
at $Proxy43.myMethod(Unknown Source)
*****************
at com.mypackage.client.MyClient.aMethod(MyClient.java:70)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at org.mozilla.javascript.MemberBox.invoke(MemberBox.java:161)
... 17 more
I've done some reading and it seems like this has to do with checked vs. unchecked exceptions. So if I were throwing an IOException I'd get the stack trace, but since there is a NullPointerException bubbling up its not giving me the trace.
Wrap your service in a try/catch block and throw the exception that's defined as the fault element of the called service in your WSDL. That way the client will get a useable stacktrace.