2
I have an application (which is a Windows service) that currently runs N Threads. What I want to do is capture whichever error that occurs in the application to write to a log file '.txt'. Only I want to do it so global.
I’m wearing the event FirstChanceException
, only that this event executes only by Appdomain and if only to register the event in the main thread of the application, all errors would be recorded in a single file '.txt', causing a lot of competition and etc.
So I thought I’d create several Appdomains (each AppDomain
with one of those Threads I have in the app) to capture exceptions
of each Thread. I made a test application and it works: at the end I have a log file for each Thread.
Only my doubts are:
- Is this the best way to globally capture exceptions in N Threads applications? Would you have another way to do this?
- Creating an Appdomain for each Thread will not generate any process overload in S.O.?
- If you crash Firstchanceexception, you will get an endless loop of errors. Especially if you write in text file. Would have some Firstchanceexpception alternative?
Research I’ve already done: https://docs.microsoft.com/pt-br/dotnet/framework/app-domains/application-domains?view=netframework-4.8
https://stackoverflow.com/questions/5569580/exceptions-in-multithreaded-application/43934857
Below follows what I did for testing:
public class Program
{
private static ReaderWriterLockSlim lock_ = new ReaderWriterLockSlim();
public static void Main(string[] args)
{
try
{
AppDomain.CurrentDomain.FirstChanceException += (object sender, FirstChanceExceptionEventArgs e) =>
{
GravarLog(e.Exception);
};
AppDomain domain1 = AppDomain.CreateDomain("Consumidor-1");
domain1.FirstChanceException += (object sender, FirstChanceExceptionEventArgs e) =>
{
GravarLog(e.Exception);
};
Consumer consumer1 = (Consumer)domain1.CreateInstanceAndUnwrap(
typeof(Consumer).Assembly.FullName,
typeof(Consumer).FullName);
consumer1.Iniciar();
AppDomain domain2 = AppDomain.CreateDomain("Consumidor-2");
domain2.FirstChanceException += (object source, FirstChanceExceptionEventArgs e) =>
{
GravarLog(e.Exception);
};
Consumer consumer2 = (Consumer)domain2.CreateInstanceAndUnwrap(
typeof(Consumer).Assembly.FullName,
typeof(Consumer).FullName);
consumer2.Iniciar();
}
catch (Exception ex)
{
throw;
}
Console.ReadLine();
}
private static void GravarLog(Exception exception)
{
lock_.EnterWriteLock();
try
{
File.AppendAllText($"D:\\Temp\\Log\\Thread-{Thread.GetDomainID()}-error.txt",
DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss:ff") + " - " +
$@"{AppDomain.CurrentDomain.FriendlyName} -> FirstChanceException: {exception.Message}");
}
finally
{
lock_.ExitWriteLock();
}
}
}
public class Consumer : MarshalByRefObject
{
public void Iniciar()
{
var tarefa = new Thread(() =>
{
int contador = 1;
while (true)
{
contador++;
var resultado = VerificarRegras();
Thread.Sleep(10000);
}
});
tarefa.Start();
}
public string VerificarRegras()
{
string regraNegocio = "Tudo OK!";
try
{
throw new ArgumentException("Thrown Exception" + Environment.NewLine);
}
catch
{
regraNegocio = "A validação da regra retornou...";
}
return regraNegocio;
}
}
Because your work of
Threads
is not managed by a common class, where in this class there are exceptions management? Imagine a classThreadManager
that possesses an objectThread
. You can make this class receive oneAction
, where theconstructor
class would receive this action. A private function with the name, for example,DoWork()
(example) would invoke thisAction
with a global Try-catch. The log is generated based on theThreadId
. And instead of you spawnar Nthreads
, you spawna N managersthread
.– Kevin Kouketsu
You may even have other things to do that might make your solution better, but you could only tell by knowing the case. Why do I wonder why N threads, for example
– Kevin Kouketsu
@Kevinkouketsu actually has 42 threads in the app today, but this number can go up. What happens: the application processes messages that were sent by the middleware Rabbitmq. Each Thread is a
Consumidor
/Assinante
of a queue of messages in Rabbitmq, and has the task of receiving and processing each message. In fact each Thread represents a "task/process" to process message. If instead of each thread a process was created, it would have all the operating system scheduling and in the Windows task manager would appear 42 ". exe". So I opted for Threads.– Raquel Pinheiro