1
I have an application developed in C# that uses an SQL Server database, this application is made available through a virtualized application server, I do not have direct access to the database nor the application server.
I intend to create a way log in all application errors so that later I can check them and correct them, if possible.
I was able to do it this way:
// Fontes
// http://www.macoratti.net/13/07/c_excep.htm
// https://tiesontrowbridge.com/code/using-linq-to-easily-serialize-an-exception-to-xml
// Classe que executa a aplicação (Program.cs)
static void Main()
{
    // define o modo de tratamento dos erros não manipulados
    Application.SetUnhandledExceptionMode(UnhandledExceptionMode.CatchException);
    Application.EnableVisualStyles();
    Application.SetCompatibleTextRenderingDefault(false);
    Application.Run(new frmMenu());
}
// -----------------------------------------------------------------------------
// Classe que serializa Exception (ExceptionXElement.cs)
using System;
using System.Collections;
using System.Linq;
using System.Xml.Linq;
public class ExceptionXElement : XElement
{
    public ExceptionXElement(Exception exception)
        : this(exception, false)
    { ; }
    public ExceptionXElement(Exception exception, bool omitStackTrace)
        : base(new Func<XElement>(() =>
        {
            XElement root = new XElement(exception.GetType().ToString());
            if (exception.Message != null)
            {
                root.Add(new XElement("Message", exception.Message));
            }
            if (!omitStackTrace && exception.StackTrace != null)
            {
                root.Add(
                    new XElement("StackTrace",
                        from frame in exception.StackTrace.Split('\n')
                        let prettierFrame = frame.Substring(6).Trim()
                        select new XElement("Frame", prettierFrame))
                    );
            }
            if (exception.Data.Count > 0)
            {
                root.Add(
                        new XElement("Data",
                        from entry in exception.Data.Cast<DictionaryEntry>()
                        let key = entry.Key.ToString()
                        let value = (entry.Value == null) ? "null" : entry.Value.ToString()
                        select new XElement(key, value))
                );
            }
            if (exception.InnerException != null)
            {
                root.Add(new ExceptionXElement(exception.InnerException, omitStackTrace));
            }
            return root;
        })())
    { ; }
}
// -----------------------------------------------------------------------------
// Classe que representa o formulário principal de aplicação (frmMenu.cs)
using System;
using System.Threading;
using System.Windows.Forms;
public partial class frmMenu : Form
{
    public frmMenu()
    {
        InitializeComponent();
        // assina o evento para tratar exceções não manipuladas
        Application.ThreadException += 
            new System.Threading.ThreadExceptionEventHandler(Application_ThreadException);
    }
    private void Application_ThreadException(object sender, ThreadExceptionEventArgs e)
    {
        ExceptionXElement logException = new ExceptionXElement(e.Exception);
        logException.Save(@"D:\" + DateTime.Now.ToString("dd-MM-yy_HH-mm-ss") + ".xml");
        Close();
    }
    private void frmMenu_Shown(object sender, EventArgs e)
    {
        int dividendo = 15, divisor = 0, resultado;
        resultado = dividendo / divisor; // linha 25
        Console.WriteLine("{0} / {1} = {2}", dividendo, divisor, resultado);
    }
}
The way out was like this:
<?xml version="1.0" encoding="utf-8"?>
<System.DivideByZeroException>
  <Message>Tentativa de divisão por zero.</Message>
  <StackTrace>
    <Frame>frmMenu.frmMenu_Shown(Object sender, EventArgs e) na frmMenu.cs:linha 25</Frame>
    <Frame>System.Windows.Forms.Form.OnShown(EventArgs e)</Frame>
    <Frame>System.Windows.Forms.Form.CallShownEvent()</Frame>
    <Frame>System.Windows.Forms.Control.InvokeMarshaledCallbackDo(ThreadMethodEntry tme)</Frame>
    <Frame>System.Windows.Forms.Control.InvokeMarshaledCallbackHelper(Object obj)</Frame>
    <Frame>System.Threading.ExecutionContext.runTryCode(Object userData)</Frame>
    <Frame>System.Runtime.CompilerServices.RuntimeHelpers.ExecuteCodeWithGuaranteedCleanup(TryCode code, CleanupCode backoutCode, Object userData)</Frame>
    <Frame>System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state)</Frame>
    <Frame>System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)</Frame>
    <Frame>System.Windows.Forms.Control.InvokeMarshaledCallback(ThreadMethodEntry tme)</Frame>
    <Frame>System.Windows.Forms.Control.InvokeMarshaledCallbacks()</Frame>
  </StackTrace>
</System.DivideByZeroException>
My doubts are as follows:
- This is the right way to log in all errors of the application?
 - Is there any contraindication to use this method?
 - How should I display the error message to users in the method 
Application_ThreadException? Something very generic or more specific? 
considering your answer, I believe I will not have problems with this method, I tried to do some tests with the
EventLog, but from what I’ve noticed he needs administrator privileges to work, which unfortunately I won’t be able to, but it would be a legal option to use as well– mateusalxd