HAVIT Knowledge Base

Vývoj webových aplikací, .NET, SQL, návrh
Welcome to HAVIT Knowledge Base Sign in | Join | Help
-
Home Články Forums Obrázky Soubory

.NET Framework

Microsoft .NET Framework, Base Class Library

Jednoduchý exception logging pomocí Trace/TraceSource mechanizmů .NET

Pokud se sháníte po jednoduchém mechanizmu, jak ve Vašich aplikacích logovat výjimky, pak zřejmě v .NET pro consolové/WinForm aplikace marně hledáte něco, jako je healthMonitoring pro ASP.NET, kde je připraven jednoduchý, ale mocný nástroj a lze pomocí pouhých několika řádků ve web.config souboru získat přehled o výjimkách ve Vaší aplikaci, např.:

<configuration>
    <system.web>
        <healthMonitoring enabled="true">
            <rules>
                <add name="Mail Notifications on All Errors" eventName="All Errors" provider="SimpleMailWebEventProvider" profile="Default"/>
            </rules>
            <providers>
                <add name="SimpleMailWebEventProvider" type="System.Web.Management.SimpleMailWebEventProvider, System.Web, Version=2.0.0.0, Culture=neutral, PublicKeyToken=B03F5F7F11D50A3A" from="errors@havit.cz" to="errors@example.cz" subjectPrefix="MyApplication: " buffer="true" bufferMode="Notification" maxEventLength="4096" maxMessagesPerNotification="2"/>
            </providers>
        </healthMonitoring>
    </system.web>
</configuration>
...výše uvedená konfigurace Vám zajistí zasílání mailových notifikacích o neobsloužených výjimkách a chyách Vaší aplikace, jednoduché, prosté.

Jak na to u consolových a WinForm aplikací?

Pro consolové či WinForm aplikace nic jako healthMonitoring připraveno není, nicméně s pár řádky kódu lze dosáhnout obdobného efektu a dokonce u toho využít široké možnosti pro tracing v .NET 2.0. Základní myšlenka je prostá:

  • .NET 2.0+ v sobě obsahuje široké možnosti pro tracing, kdy můžeme definovat různé zdroje zpráv (TraceSource), zprávy různé rozdělovat (Switch), filtrovat (TraceFilter) a směrovat na různé listenery (výstup do konzole, XML, textového souboru, event-logu, SQL, SMTP, atd. další si můžeme napsat) - to vše bez nutnosti jakýchkoliv doplňků - ať už Microsoftích Enterprise Library / Application Blocků, či produktů třetích stran typu Log4Net. Základní přehled o možnostech si můžeme udělat například z článku A Tracing Primer - Part I [Mike Rousos].
  • .NET sám nemá mechanizmus, jak výjimky zapisovat do trace
  • napsat pár řádků kódu, které zajistí zápis výjimek do trace je snadné!!!
  • do trace můžeme buď výjimky posílat explicitně (níže volání ExceptionTracer.TraceException(myException)),
  • nebo se můžeme přihlásit k odběru událostí, které neošetřené výjimky způsobují,
    • obecně jde o událost AppDomain.CurrentDomain.UnhandledException
    • ve WinForm aplikacích pak událost Application.ThreadException

Interface pro nasazení?  ...prostý

V nejjednodušší variantě si můžeme udělat například třídu ExceptionTracer, kterou přihlásíme k odběru příslušných událostí a v obsluze událostí už budeme jen výjimku posílat do trace.

Pro konzolové aplikace:

class Program
{
    static void Main(string[] args)
    {
        ExceptionTracer.SubscribeToUnhandledExceptions();

        throw new InvalidOperationException("Chybka!");

        // ExceptionTracer.Default.TraceException(new ArgumentNullException("param", "Sakrapísek!"));
    }
}
Pro WinFormAplikace:

static class Program
{
    [STAThread]
    static void Main()
    {
        ExceptionTracer.SubscribeToWindowsFormsThreadExceptions();

        Application.EnableVisualStyles();
        Application.SetCompatibleTextRenderingDefault(false);
        Application.Run(new Form1());
    }
}

App.config pak může vypadat nějak takto:

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
    <system.diagnostics>
        <sources>
            <source name="Exceptions" switchValue="Error">
                <listeners>
                    <add name="LogFileListener"
                        type="System.Diagnostics.TextWriterTraceListener"
                         initializeData="Exceptions.log"
                    />
                    <add name="XmlListener"
                         initializeData="Exceptions.xml"
                         type="System.Diagnostics.XmlWriterTraceListener"
                    />
                </listeners>
            </source>
        </sources>
    </system.diagnostics>
</configuration>

ExceptionTracer [Simplified Version]

Jednoduchá, ale plně funkční verze ExceptionTracekru může vypadat třeba takto:

using System;
using System.Collections.Generic;
using System.Text;
using System.Diagnostics;
using System.Windows.Forms;

namespace Havit.Diagnostics
{
    public class ExceptionTracer
    {
        /// <summary>
        /// Přihlásí ExceptionTracer k odběru všech neobsloužených výjimek (event AppDomain.CurrentDomain.UnhandledException).
        /// </summary>
        public static void SubscribeToUnhandledExceptions()
        {
            AppDomain.CurrentDomain.UnhandledException += new UnhandledExceptionEventHandler(CurrentDomain_UnhandledException);
        }
        private static void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e)
        {
            if (e.ExceptionObject is Exception)
            {
                TraceException((Exception)e.ExceptionObject);
            }
        }

        /// <summary>
        /// Přihlásí ExceptionTracer k odběru všech neobsloužených výjimek WinForm (event Application.ThreadException).
        /// </summary>
        public static void SubscribeToWindowsFormsThreadExceptions()
        {
            Application.ThreadException += new System.Threading.ThreadExceptionEventHandler(Application_ThreadException);
        }
        private static void Application_ThreadException(object sender, System.Threading.ThreadExceptionEventArgs e)
        {
            TraceException(e.Exception);

            // původní implementace obsluhy výjimky, WinForm dialog s chybou
            using (ThreadExceptionDialog excptDlg = new ThreadExceptionDialog(e.Exception))
            {
                DialogResult result = excptDlg.ShowDialog();
                if (result == DialogResult.Abort)
                {
                    Application.Exit();
                }
            }
        }

        /// <summary>
        /// Pošle do trace zadanou výjimku.
        /// </summary>
        /// <param name="exception">výjimka k zaznamenání</param>
        public static void TraceException(Exception exception)
        {
            TraceSource ts = new TraceSource("Exceptions");

            ts.TraceEvent(TraceEventType.Critical, 0, exception.ToString());

            ts.Flush();
            ts.Close();
        }
    }
}

Příklad výstupu [XML]

<E2ETraceEvent xmlns="http://schemas.microsoft.com/2004/06/E2ETraceEvent">
<System xmlns="http://schemas.microsoft.com/2004/06/windows/eventlog/system">
  <EventID>0</EventID>
  <Type>3</Type>
  <SubType Name="Critical">0</SubType>
  <Level>1</Level>
  <TimeCreated SystemTime="2008-01-31T21:08:35.0625000Z" />
  <Source Name="Exceptions" />
  <Correlation ActivityID="{00000000-0000-0000-0000-000000000000}" />
  <Execution ProcessName="WindowsFormsApplication1" ProcessID="1232" ThreadID="1" />
  <Channel />
  <Computer>OSKAR</Computer>
</System>
<ApplicationData>System.ApplicationException: Test !!! at WindowsFormsApplication1.Form1.button1_Click(Object sender, EventArgs e) in D:\Development\ExceptionLogging\WindowsFormsApplication1\Form1.cs:line 20 at System.Windows.Forms.Control.OnClick(EventArgs e) at System.Windows.Forms.Button.OnClick(EventArgs e) at System.Windows.Forms.Button.OnMouseUp(MouseEventArgs mevent) at System.Windows.Forms.Control.WmMouseUp(Message& m, MouseButtons button, Int32 clicks) at System.Windows.Forms.Control.WndProc(Message& m) at System.Windows.Forms.ButtonBase.WndProc(Message& m) at System.Windows.Forms.Button.WndProc(Message& m) at System.Windows.Forms.Control.ControlNativeWindow.OnMessage(Message& m) at System.Windows.Forms.Control.ControlNativeWindow.WndProc(Message& m) at System.Windows.Forms.NativeWindow.Callback(IntPtr hWnd, Int32 msg, IntPtr wparam, IntPtr lparam)</ApplicationData>
</E2ETraceEvent>

 

Published 31. ledna 2008 21:27 by Robert Haken

Comment Notification

If you would like to receive an email when updates are made to this post, please register here

Subscribe to this post's comments using RSS

Comments

 

Robert Haken said:

Michale, co má Log4Net užitečného, co tohle (trace/healthMonitoring) nemá? ;-)

...co mi přinesou zajímavého dalšího?

ledna 31, 2008 22:17
 

Michal said:

1) Podpora .net 1.0 a libovolny vyssi, Mono

2) stejne logovani v libovolnem typu .NET aplikace (winform, DLL, ASP.NET)

3) vice ruznorodych "listeneru"  a vyssi moznosti konfigurace (v nazvoslovi HealtMonitoru)

4) vysoky a overeny vykon

5) zvyk a stabilita. Je to treti "framework" od MS pro podobne logovani. Log4net se za poslednich 5 let koncepcne nezmenil.

body 1) a 2) povazuji za podstatne, zbytek je minoritni, resp. pri zjednoduseni srovnatelny

ledna 31, 2008 23:57
 

Robert Haken said:

1) Pro nás nepodstatný

2) ExceptionTracer můžeš subscribovat i k události HttpApplication.Error a máš to pak sjednocený. Ale uznávám, že tady MS nepochopitelně rozdvojili koncept.

...pro mě by byl nejpodstatnější asi zvyk, jinak mi to přijde celkem rovnocenný.

února 1, 2008 8:31

What do you think?

(required) 
(optional)
(required) 
Enter the code you see below

Submit