C# ile Hata Mini Dökümünü Almak

    Hata ayıklama konusunda şimdiye kadarki paylaşımlarımda sizlere önemli bilgiler aktarabildiğimi umuyorum. Bu makale serisinde en başından, daha uygulamalarımızı geliştirirken nasıl log tutarak oluşabilecek hatalar hakkında bilgi kaydedebileceğimizi görmüştük. Devamında çalışan bir işlemin hata dökümünü yazacağımız bir C# programıyla ya da ADPlus kullanarak nasıl alabileceğimizi öğrenmiş, son olarak da debugger mantığını öğrenerek Win32 uygulamaları için basit bir debugger geliştirmiştik.

    Bu makalemde daha önceden sizlerle paylaştığım iki bilgiyi, C# ile mini dökümü alma ve Win32 debugger yazma, nasıl hata ayıklamada birlikte kullanabileceğimizi anlatıyor olacağım. Makalemin sonunda oluşturmuş olacağımız uygulama, işlev olarak ADPlus ile Hata Dökümü makalemde sizlerle paylaştığım ADPlus uygulamasının Hata/Çakılma (Crash) modu ile benzer bir işleve sahip olacaktır.

    C# ile mini dökümü almak için geliştirdiğimiz, aşağıda ekran görüntüsünü bulacağınız, örnek uygulamayı hatırlayın;

MiniDump

    Geliştirdiğimiz bu uygulama, "Seçili İşlemin Dump’ını Al" butonuna basılması ile Win32 API’lerini kullanarak belirtilen işin mini hata dökümünü almaktaydı. Gerçek hayatta, bu uygulamaya ihtiyaç duyduğunuz zamanlar muhtemelen geliştirdiğiniz uygulamada sorunla karşılaştığınız zamanlar olacaktır. Böyle bir durumda da anlık olarak alınacak bir hata anında hızla bu butona basarak mini hata dökümü almak büyük bir olasılıkla da mümkün olmayacaktır. Böylesi bir durumda, hata dökümü alan uygulamadan bekletiniz yazılımınızı takip ederek hata durumu oluştuğu anda işleyişi durdurup bir mini hata dökümü alması olacaktır.

    Debugger yazdığımız makaleyi hatırlayacak olursak; Win32 API’lerini kullanarak çalışan bir işleme bağlanarak dll yüklenmesi/kaldırılması, işlem ve iş parçacığı başlatılması/sonlanması gibi pek çok olay bildirimi yanında hata olayları da iletilmekteydi. Aslına bakarsanız bu hata bildirimleri de tam da yukarıdaki isterimize uygun. Bu durumda mini hata dökümü uygulamamıza kısmi debugger yeteneklerini de katacak olursak istediğimiz uygulamaya ulaşmış olacağız. Her ne kadar debugger’lara pek çok olay hakkında bilgi iletiliyor olsa da, bizim ihtiyacımız olan tek bilgi hata olay bildirimidir. Bu durumda bir işleme bağlanarak gelen olay bildirimlerinden sadece hata bildirimini dinleyen ve bu bildirim geldiğinde de işlemin mini hata dökümünü alan bir uygulama ihtiyacımızı karşılayacaktır.

Yeni haliyle mini sump uygulama ekranı

    Yukarıdaki ekran görüntüsünden de göreceğiniz gibi, önceki mini döküm uygulamamıza ek bir buton daha ekleyerek hata durumunda döküm alınması seçeneği sunabiliriz. Kullanıcı bu butona tıkladığında, seçili olan işleme bir debugger gibi bağlanılacak ve debug döngüsü başlatılacaktır; fakat bu debug döngüsü debugger makalemizdekinden farklı olarak gönderilen olay bildirimleri arasından sadece hata ve sonlanma bildirimlerini dinleyecek, bunları event olarak önyüze bildirecektir. Bu bildirimleri alan önyüz ise daha önce olduğu gibi Win32 API’leri yardımıyla o an işletim sistemince durdurulmuş olan bu işlemin mini dökümünü alacaktır. C# ile mini hata dökümü için geliştirdiğimiz projemizde yer alan IslemIzleyici sınıfı içerisine Win32 debugger’ımızda yer alan Debugger sınıfı içerisindeki debug mantığını kopyalayıp, OlayBilgisiniIsle fonksiyonunu aşağıdaki şekilde güncellemeliyiz;

private ContinueStatus OlayBilgisiniIsle(SynchronizationContext synchronizationContext, DebugEventHeader header, DebugEventUnion union) {
    var debugState = ContinueStatus.DBG_CONTINUE;
    var debugEventArgs = new DebugEventArgs(header, union);

    switch (header.dwDebugEventCode) {
        case DebugEventCodes.EXCEPTION_DEBUG_EVENT:
            synchronizationContext.Send(HataOlustuBildir, debugEventArgs);
            debugState = debugEventArgs.DebugState;
            break;
        case DebugEventCodes.EXIT_PROCESS_DEBUG_EVENT:
            synchronizationContext.Send(IslemSonlandiBildir, debugEventArgs);
            debugState = debugEventArgs.DebugState;
            break;
        case DebugEventCodes.CREATE_THREAD_DEBUG_EVENT:
        case DebugEventCodes.CREATE_PROCESS_DEBUG_EVENT:
        case DebugEventCodes.EXIT_THREAD_DEBUG_EVENT:
        case DebugEventCodes.LOAD_DLL_DEBUG_EVENT:
        case DebugEventCodes.UNLOAD_DLL_DEBUG_EVENT:
        case DebugEventCodes.OUTPUT_DEBUG_STRING_EVENT:
            break;
        case DebugEventCodes.RIP_EVENT:
            synchronizationContext.Send(IslemSonlandiBildir, debugEventArgs);
            debugState = debugEventArgs.DebugState;
            break;
    }

    return debugState;
}

#region Olay Bildirimleri
private void HataOlustuBildir(object veri) {
    var debugEventArgs = (DebugEventArgs)veri;

    if (HataOlustu != null) {
        HataOlustu(this, debugEventArgs);
    }
}

private void IslemSonlandiBildir(object veri) {
    var debugEventArgs = (DebugEventArgs)veri;

    if (IslemSonlandi != null) {
        IslemSonlandi(this, debugEventArgs);
    }

    izle = false;
}
#endregion

    Uygulamamıza eklediğimiz "Seçili İşlemin Dump’ını Al" butonuna tıklandığında işleme bağlanarak hatalara karşı takip etmek için ise aşağıdaki kodlar AnaEkran sınıfına eklenmeli;

private void hataDokumuAl_Click(object sender, EventArgs e) {
    var seciliIslem = (Process)islemListesi.SelectedRows[0].DataBoundItem;
    var onerilenDosyaAdi = seciliIslem.ProcessName + ".mdmp";

    dosyaSaklamaDiyalogu.FileName = onerilenDosyaAdi;
    if (dosyaSaklamaDiyalogu.ShowDialog() == DialogResult.OK) {
        progressPanel.Visible = true;

        var islemIzleyici = new IslemIzleyici(seciliIslem) { Tag = dosyaSaklamaDiyalogu.FileName };
        islemIzleyici.HataOlustu += islemIzleyici_HataOlustu;
        islemIzleyici.IslemSonlandi += islemIzleyici_IslemSonlandi;

        islemIzleyici.Izle();
    }
}

private void islemIzleyici_IslemSonlandi(object sender, DebugEventArgs args) {
    var islemIzleyici = (IslemIzleyici)sender;

    islemIzleyici.IslemSonlandi -= islemIzleyici_IslemSonlandi;
    islemIzleyici.HataOlustu -= islemIzleyici_HataOlustu;

    progressPanel.Visible = false;
}

private void islemIzleyici_HataOlustu(object sender, DebugEventArgs args) {
    if (args.Union.Exception.ExceptionRecord.ExceptionCode != ExceptionCode.STATUS_BREAKPOINT && !args.Union.Exception.dwFirstChance) {
        var islemIzleyici = (IslemIzleyici)sender;

        using (var dumpFileStream = new FileStream((string)islemIzleyici.Tag, FileMode.Create, FileAccess.ReadWrite, FileShare.Write)) {
            MiniDumpWriteDump(islemIzleyici.Islem.Handle,
                    (uint)islemIzleyici.Islem.Id,
                    dumpFileStream.SafeFileHandle,
                    0x00000002, //MiniDumpWithFullMemory, http://msdn.microsoft.com/en-us/library/ms680519%28v=VS.85%29.aspx
                    IntPtr.Zero,
                    IntPtr.Zero,
                    IntPtr.Zero);
        }

        MessageBox.Show("Mini Dump başarıyla alındı");
    }

    args.DebugState = ContinueStatus.DBG_EXCEPTION_NOT_HANDLED;
}

    Tüm ikinci şans hata bildirimlerinde mini döküm alan ve ardından işletim sistemine DBG_EXCEPTION_NOT_HANDLED mesajını ileten bu uygulamayı kendi iş mantığınız doğrultusunda değiştirebilmeniz de mümkündür. Hatırlarsanız bazı istisnai durumlarda ilk şans hata bildirimlerinin dökümleri daha detaylı bilgi verebiliyordu. Yazılım geliştirici isterse sadece belirli bir hata kodu için mini döküm alabilir ya da sadece ilk bildirimlerde döküm alabilir. Başka bir kullanım senaryosunda da hata bilgileri kullanıcıya gösterilerek mini döküm almayı isteyip istemediği de sorulabilir.

    Alternatif olarak; bir Windows Forms uygulamasında bu tarz bir yöntem takip etmek yerine bir Windows Hizmeti geliştirilerek okunacak olan bir yapılandırma dosyasından belirli işlemin/işlemlerin takip edilmesi ve hata durumlarında mini dökümlerinin alınması da mümkündür.

    Mini döküm alma ve bir işlemin olay bildirimlerini yakalayabilme konusunda bilgi sahibi olunduktan sonra, bu bilgiler yukarıda da örneklemeye çalıştığım gibi çok farklı senaryolarda kullanılabilir ve hatanın kaynağına ulaşmanızı kolaylaştırabilir.

   Aşağıda, makalemde bahsettiğim ve hata durumunda mini döküm alabilen uygulamanın kaynak kodlarını bulabilirsiniz.

alt

Hata Mini Dökümü uygulaması

Fatih Boy

Ankara'da yaşayan Fatih, bir kamu kurumunda danışman olarak çalışmaktadır. ALM süreçleri, kurumsal veri yolu sistemleri, kurumsal altyapı ve yazılım geliştirme konularında destek vermektedir. Boş zamanlarında açık kaynak kodlu projeler geliştirmeyi ve bilgisini yazdığı makalelerle paylaşmayı seven Fatih, aynı zamanda Visual C# ve Visual Studio teknolojileri konusundan Microsoft tarafından altı yıl üst üste MVP (En Değerli Profesyonel) ödülüne layık görülmüştür. İş hayatı boyunca masaüstü uygulamaları, web teknolojileri, akıllı istemciler gibi konularda Asp.Net, Php, C#, Java programlama dilleri ve MySql, MsSql ve Oracle gibi veritabanı yönetim yazılımları ile çalışmıştır. İngilizce ve Türkçe olarak yayınlanan makalelerini gerek İngilizce bloğunda, gerekse de Türkçe bloğunda bulabileceğiniz gibi web sitesinden de açık kaynak kodlu geliştirdiği yazılımlarına ulaşabilirsiniz. vCard - Twitter - Facebook - Google+

Bir Cevap Yazın

E-posta hesabınız yayımlanmayacak. Gerekli alanlar * ile işaretlenmişlerdir