How to configure Log4Net to log unhandled exceptions - log4net

I would like to be able to log unhandled exceptions via configuring log4net.
Is that possible to achieve by only making changes to the config file? if yes, how to do that?
Otherwise if it's not possible, what should I implement in the code to make this happen?

You can't do this with only configuration, you need log the actual exception somewhere. So you need to catch the 'uncatched' exception and them log it.
public static void Main(string[] args)
{
// Add the event handler for handling UI thread exceptions to the event.
Application.ThreadException += new
ThreadExceptionEventHandler(ErrorHandlerForm.Form1_UIThreadException);
// Set the unhandled exception mode to force all Windows Forms errors
// to go through our handler.
Application.SetUnhandledExceptionMode(UnhandledExceptionMode.CatchException);
// Add the event handler for handling non-UI thread exceptions to the event.
AppDomain.CurrentDomain.UnhandledException += new
UnhandledExceptionEventHandler(CurrentDomain_UnhandledException);
}
In the handlers you can log to log4net. After that you can switch them on and off with configuration.
However there are some cases that the exception is not catched. For example when there is a failfast called.

Related

Handling Error in asynchronous process using #Async annotation on custom method vs on #Gateways method

I have a process where I need to upload file to Sftp server asynchronously. So after exploring more about Async in gateways I found that I need to have error channel defined in #MessagingGateway parameter then handler to handle the Exception propagated to error channel but I felt handling this way is complicated for me, as I will have to update Pojo field and persist into DB depending on the file upload, success or failure.
So I thought of having a custom method annotated with #Async and call the gateway method. Also surround gateway method with try block and catch any exception occurred in the downstream
Code Sample:
#Async
void upload(Resource file, FileStatus fileStatus){
try{
uploadGateway.upload(file,fileStatus.getFilePath(),fileStatus.getFileName());
}catch(RuntimeException e){
fileStatus.setUploadStatus("Failed");
//save into db
}
}
Upload Gateway without error channel so that error can be sent back to caller
#MessagingGateway
public interface UploadGateway {
#Gateway(requestChannel = "input.channel")
void upload(#Payload Resource file, #Header("path") String path, #Header("name") String fileName);
}
Handler:
#Bean
public IntegrationFlow uploadDocument() {
return IntegrationFlows.from("input.channel")
.log(LoggingHandler.Level.WARN)
.handle(Sftp.outboundAdapter(sftpSessionFactory(), FileExistsMode.FAIL)
.autoCreateDirectory(true)
.remoteDirectoryExpression("headers['path']")
.fileNameExpression("headers['name']"))
.get();
}
Question:
What will be the consequences if I'm handling error this way? Is this the right way to handle any error occurred in downstream flow?
Since #MessagingGateway is like an RPC in messaging, it is fully OK to catch an exception on its method call like that. Since you make your flow fully sync, it works like typical Java exceptions sub-system.
Your concern about async error handling with errorChannel really makes sense since it is similar in complexity with standard Java async method handling and its errors processing.
On the other hand it is really commended to handle errors downstream via errorChannel if that is going to be some complex logic in some other flow. Plus you are going to return back some compensation message.
However in the end of day the choice is yours: there is no drawbacks to handle errors yourself.
See Error Handling chapter for more food to think on.

Spring Cloud Stream: how to republish to dead letter queue and also throw exception

I'm migrating a project that uses Spring AMQP to a project that uses Spring Cloud Stream with RabbitMQ.
In my old project, when some exception occurred while processing a message using #RabbitListener, that exception was thrown. If there was a dead letter queue binded, exception was still thrown (only once if there were retries, the last one I guess). This was very helpful for logging purposes.
In Spring Cloud there is a dead letter queue mechanism for #StreamListener if you define the properties:
spring.cloud.stream.bindings.input1.destination=dest1
spring.cloud.stream.rabbit.bindings.input1.consumer.auto-bind-dlq=true
spring.cloud.stream.rabbit.bindings.input1.consumer.republishToDlq=true
But if you have a method like this (is just an example):
#StreamListener("input1")
public void process(String message){
System.out.println("Trying...");
throw new RuntimeException();
}
Logs are:
Trying...
Trying...
Trying...
(end of log, no exception thrown)
Is there any way to throw the exception (only in the last retry)?
Thanks!
See the documentation about consumer properties.
Set ...consumer.max-attempts=1 to disable retry.
You can handle the exception, log it and then throw AmqpRejectAndDontRequeueException. This will send the message to dead letter queue
You are under #StreamListener where would you expect the exception to go? who is catch it?
you can do it something like that:
#StreamListener("input1")
public void process(String message){
try {
System.out.println("Trying...");
throw new RuntimeException();
// or the actual code that handle the message
} catch (RuntimeException re) {
// handle the exception, logging etc.
throw re
}
}

How to define a request timeout on asp.net core MVC on linux

Given:
ASP.Net Core MVC application, deployed in docker containers on linux.
Nginx reverse proxy + load balancer
When the ASP.Net core container gets stuck (after a timeout on nginx), it calls a different instance of the application. At that point, the application should cancel the processing in order to not perform data manipulation operations twice. This works great with a global:
public override async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next)
{
using (context.HttpContext.RequestAborted.Register(() => context.HttpContext.RequestAborted.ThrowIfCancellationRequested()))
{
await base.OnActionExecutionAsync(context, next);
}
}
The problem here is, that nginx might cancel the request, right after the transaction in the controller and underlying services completed. Which means, the request was successful, but just slightly too long, and nginx will try a second time anyway. In order to solve this, we wanted to set a second timeout which would be few seconds shorter than nginx timeout. The only solution I've found is this:
public override async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next)
{
var timeout = new CancellationTokenSource();
timeout.CancelAfter(ActionTimeout);
using (timeout.Token.Register(() => timeout.Token.ThrowIfCancellationRequested()))
using (context.HttpContext.RequestAborted.Register(() => context.HttpContext.RequestAborted.ThrowIfCancellationRequested()))
{
await base.OnActionExecutionAsync(context, next);
}
}
But this is throwing the following exception:
System.AggregateException was unhandled
Message: An unhandled exception of type 'System.AggregateException' occurred in System.Private.CoreLib.ni.dll
Additional information: One or more errors occurred.
And afterwards the application is crashing. Putting try/catch anywhere around of course also doesn't help and adding a global exception filter to the middleware doesn't help either.
What is the best way to cancel Requests on linux after a custom timout, without depending on a reverse proxy to do it?
Update - details on exceptions:
At first I see the following exception:
System.OperationCanceledException was unhandled by user code
HResult=-2146233029
Message=The operation was canceled.
Source=System.Private.CoreLib
StackTrace:
at System.Threading.CancellationToken.ThrowOperationCanceledException()
at ...BaseController.<>c__DisplayClass4_0.<OnActionExecutionAsync>b__0() in ...\Controllers\BaseController.cs:line 28
at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
InnerException:
Which is fine, that's the cancellation token throwing the exception. But the second one, the one which I can't catch, not sure how I could see the details there, I just see the following screen:
And regardless of what I tried, the process always stopped afterwards (even if I press continue execution)

How to catch exceptions in a thread?

My web server is based on Delphi / DataSnap.
When a server method raises an exception, how can I handle it?
I tried Application.OnException but it does not work because each connection is a new thread and it only works for the IDE thread.
I want to manage them for adding the data in a log file.
UPDATE:
As #Remy Lebeau says, I do not have control aver the creation of the thread. It is a DataSnap based application that works as Web Api server. A TDSServerClass components instances my TServerMethods class. Then, when a web connection arrives, DataSnap creates a new thread and call to my TServerMethods methods. If within the method, a exception is raised, then it is lost because each thread has its stack. With Application.OnException, I only can catch unhandheld exceptions from the IDE thread. What I want to do is to log any handheld exception in a log file.
From the System.Classes.TThread.FatalException documentation:
If the Execute method raises an exception that is not caught and handled within that method, the thread terminates and sets FatalException to the exception object for that exception. Applications can check FatalException from an OnTerminate event handler to determine whether the thread terminated due to an exception.
If an exception occurs in the Execute method of a TThread object its FatalException property is assigned and the thread terminates.
You can check if an exception occurred in a thread implementing its OnTerminate event:
procedure TForm1.YourThreadTerminate(Sender: TObject);
var
ex: Exception;
begin
ex := Exception(TYourThread(Sender).FatalException);
if Assigned(ex) then
//an exception has occurred: your code here
end;
This is how you can assign the event to you thread:
var
yourThread: TYourThread;
begin
yourThread := TYourThread.Create(True);
yourThread.OnTerminate := YourThreadTerminate;
yourThread.Start;
end;
You may need to hook into the exception handling mechanism itself - JCL has code that does that, for example, or you could use third party libraries like madExcept, EurekaLog or others. They also collect stack traces and other info useful to understand what lead to an exception.
I used JCL some time ago in a Datasnap DCOM server to log unhandled exception to a custom event log. If you're going to write to a file, beware of concurrent access, because more than one thread could try to write to it. Also Event Tracing for Windows (ETW) may be a a better, although more complex way, to log to a file for diagnostic purposes.
Anyway, in this kind of applications, it's better to handle "expected" exceptions, and never let them propagate up to a generic handler. Of course, being able to trap and log "unexpected" ones is useful.

Possible to set up Log4net Notification When it Crashes?

Log4net fails silently by design. Good. I don't want it taking down my app.
Is there a way to set up a notification when Log4net crashes and stops logging?
Is there some kind of event handler that I can hook into which will tell me that Log4net has gone silent?
I want to know when this happens so I can recycle the app pool as soon as possible.
Thanks!
If I'm understanding you correctly, you would like log4net to signal you when an appender fails. If we look at the logging code for the Logger implementation we see that the only point that takes into account the appenders failing is the internal logging mechanism:
// log4net.Repository.Hierarchy.Logger
public virtual void Log(Type callerStackBoundaryDeclaringType, Level level, object message, Exception exception)
{
try
{
if (this.IsEnabledFor(level))
{
this.ForcedLog((callerStackBoundaryDeclaringType != null) ? callerStackBoundaryDeclaringType : Logger.ThisDeclaringType, level, message, exception);
}
}
catch (Exception exception2)
{
LogLog.Error("Log: Exception while logging", exception2);
}
catch
{
LogLog.Error("Log: Exception while logging");
}
}
Of course this occurs only if the appender throws an exception. The LogLog component then forwards the message to the Console and Trace components:
// log4net.Util.LogLog
private static void EmitErrorLine(string message)
{
try
{
Console.Error.WriteLine(message);
Trace.WriteLine(message);
}
catch
{
}
}
So, by listening messages coming from the trace you can get an idea of what happens in your appenders. To turn this into an event you can add a trace listener that triggers in some specific cases: you can take a look at what is in this answer regarding custom trace listeners in order to trigger an event from one.

Resources