Makale Özeti

Bu yazımızda , uygulamalarda Tracing (İz Sürme) işleminin nasıl yapıldığını inceleceğiz.

Makale

Bu yazımızda , uygulamalarda Tracing (İz Sürme) işleminin nasıl yapıldığını inceleceğiz.

Yazdığımız uygulamalarda, bazen uygulamananın nerede nasıl davrandığını öğrenmek isteriz. Özellikle kurumsal uygulamalarda bu durum istek olmaktan çıkar bir zorunluluk haline gelebilir. Kullanıcının sisteme ne girmek istediğini, hangi veritabanı erişminde hangi Sql cümleciğinin yaratıldığını , nerede hangi hataya düştüğünü vb. bilmek isteriz.

Eğer orta katmanda çalışan ve birden fazla uygulama/sistem  tarafından çağırılan bir uygulama yazdıysak , uygulamanın hangi inputu alıp , hangi işlemleri yaptığını ve sonuçta hangi outputu yarattığını takip etmek isteriz. İşte burada karşımıza tracing kavramı çıkıyor.

Tracing (İz Sürme) , çalışan bir sistemi durdurmadan  oluşan problemleri , bu problemlerin nereden kaynaklandığını ve uygulamanın hangi aşamalardan geçtiğini farketmemizi , yakaladığımız bilgileri çeşitli çıktı noktalarına yazabilmemizi sağlayan bir teknolojidir.

.Net Framework bu tür işlemler için , System.Diagnostics isim uzayı (namespace) içerisinde Trace ve Debug sınıfları bulunduruyor. Bu sınıflar içerisindeki metodlar ile uygulamamızın ne zaman ,  ne yaptığını istediğimiz bir yere loglama şansına sahibiz.

Biz bu yazımızda Trace sınıfını inceleyeceğiz.

Trace sınıfı , uygulamalarımızın yaptığı işleri takip edebilmemiz ( trace alabilmemiz) için gerekli metodları barındırmaktadır.

Uygulamamızın, Trace sınıfının metodlarını kullanabilmesi için ,uygulamamızın derlenmesi esnasında Trace opsiyonun açık tutulması gerekir. Aynı şekilde eğer Debug sınıfının metodlarını kullanacaksak o zaman Debug opsiyonunun açık olması gerekir. Visual Studio.Net ile uygulama geliştiriyorsanız , uygulamalar DEBUG ve TRACE opsiyonları açık olarak derlenmektedir.Bu opsiyonlar üzerinde değişiklik yapmak için ,Solution Explorer da projemizin adı üzerine sağ tıklayıp Properties menü adımını seçtikten sonra, çıkan pencereden Configuration Properties adımını seçmeliyiz. Bu penceredeki Conditional Compilation Constants özelliğinin karşısında TRACE;DEBUG değerlerini görebilirsiniz.

Bu değerler uygulamanın derlenmesi sırasında kullanılırlar. Bunlardan TRACE opsiyonu kaldırıldığında , C# derleyicisi uygulamamızda kullandığımız Trace sınıfındaki metodları derleme sırasında uygulama içerisine almaz. Dolayısı ile uygulamamızda Trace sınıfını kullanıyorsak , Conditional Compilation Constants parametresinde Trace opsiyonun bulunduğundan emin olmalıyız.Aynı durum Debug sınıfı içinde geçerlidir.

Eğer uygulamamızı komut satırından derliyorsak , Trace kodlarımızın , yaratılacak uygulamamıza dahil olması için  /d:TRACE parametresini, Debug kodlarımızın yaratılacak uygulamamıza dahil olması için de /d:DEBUG parametresini  eklemeliyiz.

csc /d:TRACE mytrace.cs

csc /d:DEBUG mytrace.cs

Gelelim  uygulamamızda nasıl ve nerelere trace alabileceğimize.

System.Diagnostics isim uzayı içerisindeki Trace işleminde , alacağımız çıktıları nereye yazacağımızı belirtebileceğimiz sınıflar bulunmaktadır. Bu sınıflara Listener (Dinleyici) diyoruz. Listener sınıfları Trace sınıfının yazdırma metodlarını kullanarak , yazdırmaya çalıştığımız mesajları alırlar ve belirtilen fiziksel yerlere yazarlar. Bir nevi aracılık görevi yaparlar.

3 adet Listener sınıfı .Net Framework ile birlikte bizlere sunulmaktadır.

  • DefaultTraceListener       : Eklenmese bile, öndeğer  olarak Trace sınıfına eklenmiş sınıftır.
  • TextWriterTraceListener  : Aldığımız trace bilgilerini bir text dosyaya yazmak için kullandığımız sınıftır.
  • EventLogTraceListener    : Aldığımız trace bilgilerini işletim sisteminin Event Log una yazmak için kullandığımız sınıftır.

Trace sınıfının metodlarını inceleyelim

  • Trace.Assert      :Assert metodu , ilk parametresini şarta bağlı olarak alır , eğer şarta uygunsa yazacağımız mesajı bir mesaj ekranına çıkarır.
  • Trace.Fail          :Fail metodu da Assert metodu gibi bir mesaj ekranı çıkararır. Farkı ise herhangi bir şarta bağlı değildir.
  • Trace.Write       :Write metodu ile yazılmak istenen bilgi herhangi bir çıktı noktasına yazdırılır.
  • Trace.WriteIf:     :WriteIf metudu da write metodu ile aynı işi yapmakla birlikte ,farkı sadece bir şarta bağlı olarak çalışıyor olmasıdır.
  • Trace.WriteLine  :WriteLine Metodu yazılmak istenen mesajı, herhangi bir çıktı noktasına yazdırırken her bilgiyi satır satır yazdırmaya yarar.
  • Trace.WriteLineIf:WriteLineIf metodu da Writeline metodu ile aynı işi yapmakla birlikte farkı sadece bir şarta bağlı olarak çalışmasıdır.

Bu bilgiler eşliğinde nasıl trace alabileceğimizi , kod üzerinden incelemeye başlayalım. Yazacağımız uygulama bir konsol uygulaması olacak.

Öncelikle using System.Diagnostics; ifadesini ekliyoruz.

static void Main(string[] args)

{

        Trace.Assert(1=2,"Hata");

}

Uygulamamızda kullandığımız Assert metodunun "Hata" mesajını  yazması için , ilk parametresindeki değerin false olması gerekir. Uygulamamızda da şarta bağlı olan ifade 1=2 , false döndürdüğü için ekramıza bir mesaj ekranı çıkacaktır.  Çıkan mesaj ekranında istersek uygulamayı sonlandırma (Abort), yapılan işlemi tekrar denetme (Retry) veya mesajı pas geçme şansımız bulunuyor.

 

EventLogTraceListener  ile Event Viewer a Trace yazma

static void Main(string[] args)

{

 EventLogTraceListener eltl = new EventLogTraceListener();

eltl.EventLog= new EventLog("Application");

eltl.EventLog.Source="YazGelistir";

Trace.Listeners.Add(eltl);

Trace.Write("YazGelistir Logu");

Trace.Close();

eltl.Close();

}

Yukarıdaki örneğimizi inceleyecek olursak ;

EventLogTraceListener eltl = new EventLogTraceListener(); ifadesi ile eltl adında bir Event Log Listener ı yaratıyoruz. Listenera gönderilen mesajın hangi event loga yazılacağını  eltl.EventLog=new EventLog("Application"); satırında belirtiyoruz. Uygulamamız Event Viewer daki , Application kısmına bilgi yazacak.Event Log a yazılacak mesajın Source bilgisini de eltl.EventLog.Source="YazGelistir"; ifadesi ile veriyoruz. Sonraki satırda yarattığımız listener nesnesini Trace nesnesine bir listener olarak ekliyoruz. Trace.Write("YazGelistirde Hata"); satiri ile mesajımızı tampona(buffer) yazıyoruz. Trace.Close(); ifadesi ile tamponda bulunan bilgileri event loga yazıyoruz. Event Viewer dan Application isimli logu inceleyecek olursak aşağıdaki şekilde yazdığımız mesajı görebiliriz.

 

TextWriterTraceListener ile bir dosyaya Trace yazma

static void Main(string[] args)

{

TextWriterTraceListener twtl= new TextWriterTraceListener("c:\\yazgelistir.Log");

Trace.Listeners.Add(twtl);

Trace.WriteLine("İşlem Başladı");

Trace.Flush();

Trace.Indent();

Trace.WriteLine("Sayma İşlemi yapılıyor");

for(int i=0;i<10;i++)

{

Console.WriteLine(i.ToString());

}

Trace.Unindent();

Trace.WriteLine("İşlem Bitti");

Trace.Close();

twtl.Close();

}

Yukarıdaki kodumuzda twtl adında bir TextWriterTraceListener nesnesi yaratıyoruz. Bu nesnenin trace olarak alınan bilgileri nereye yazacağını da nesneyi yaratırken c:\\yazgelistir.log parametresini verecek belirtiyoruz. Tüm trace bilgilerimiz C sürücüsünde yazgelistir.log isimli dosyada olacak.twtl nesnesini Trace sınıfımıza bir listener olarak ekliyoruz ve,  Trace.WriteLine("İşlem Başladı"); ifadesi ile "İşlem Başladı" satırını  tampona (buffer) yazıyoruz. Bu örnek kodumuzda Trace sınıfının WriteLine metodunu kullanıyoruz. Çünkü bir dosyaya bilgi yazıyoruz ve yazdığımız her bilginin ayrı ayrı satırlarda gösterilmesini istiyoruz.

Trace.Flush() metodunu çağırarak "İşlem Başladı" ifadesinin tampondan yazgelistir.log isimli dosyaya yazılmasını sağlıyoruz. Eğer bu işlemi yapmasaydık, Close() metodu çağırılana kadar dosyada herhangi bir satır göremeyecektik. Flush() metodu tampona yazılmış olan ifadelerin fiziksel olarak belirtilmiş yerlerine yazmamızı sağlar.Ancak Flush() metodunu çağırmayı unutabiliriz. İşte bu iş için yaratılmış bir AutoFlush özelliği bulunmaktadır. Bu özelliğin değerini true yaparak her mesaj yazdırma işleminden sonra Flush() metodunun otomatik olarak çağırılmasını sağlayabilirsiniz. Böylece yazmayı düşündüğümüz mesajlar otomatik olarak ilgili yere yazılmış olacaktır. 

Trace.Indent() metodunu çağırarak yazılacak ifadenin sağa doğru kayması sağlanır. Trace.IndentLevel özelliğine değer vererek , Indent metodunun yazılacak ifadenin kaç birim sağa ötelemesi gerektiğini belirtebiliriz. Trace.IndentSize özelliği ise 1 birim kaydırma yapıldığında , kaç karakter boşluk bırakılacağını belirtir. Değiştirilmediği durumda IndentSize özelliğinin değeri 4 tür.

Aşağıdaki örnekte , 2 birim sağa kayma yapılması gerektiği, her bir birim için ise  3 karakter boşluk bırakılacağı ve bu şekilde sağa kayma işleminin yapılması gerektiği belirtilmiştir.

 Trace.IndentLevel=2; // 2 birim sağa kayma

 Trace.IndentSize=3; // her bir birim için 3 karakter boşluk

Trace.Indent();         

Eğer IndentLevel değerini atamazsak IndentLevel özelliği 0 (Sıfır) değerini alır. Bu da 1 birim sağa kayma demektir. Bizde uygulamamızda "Sayma İşlemi yapılıyor" ifadesinin 1 birim sağa yazılmasını istediğimiz için IndentLevel özelliğini belirtmedik.

"Sayma İşlemi Yapılıyor " ifadesini yazdırdıktan sonra bir döngüye girip i değerini 0 dan 9 a kadar ekrana yazdırıyoruz. Trace.Unindent() metodu ile yazma işleminin bir birim sola alınmasını sağlıyoruz. "İşlem bitti" ifadesi dolayısı ile tekrar bir birim soldan başlayarak yazılıyor.

Burada Flush metodunu çağırmadığımız için ,Close metodu çağırılana kadar "Sayma işlemi yapılıyor" ve "İşlem Bitti" ifadeleri dosyaya yazılmayacaktır. Mesajlar Close() metodu çağırıldığında dosyaya yazılıyor.Sonuçta dosyamızın içi aşağıdaki şekilde oluşuyor.

İşlem Başladı
    Sayma İşlemi yapılıyor
İşlem Bitti

AutoFlush ve IndentSize özelliklerinin Konfigürasyon dosyasında belirtilmesi

AutoFlush ve IndentSize özellikleri uygulamanın konfigürasyon dosyasından aşağıdaki şekilde verilebilir.

Bu şekilde her ifadenin ,aynı anda fiziksel loguna yazılmasını , eğer Indent metodu kullanılıyorsa da 3 karakter sağa kayması gerektiğini belirtebiliriz. 

Switch Kullanım

Switch sınıfları, Trace sınıfı ile yazacağımız mesajları parametrik olarak ,kullanıp, kullanmayacağımızı veya hangi filtreyi kullanacağımızı belirtebileceğimiz sınıf kütaphaneleridir. .Net Framework içerisinde TraceSwitch  ve BooleanSwitch olarak iki adet switch sınıfı bulunmaktadır.

BooleanSwitch sınıfı bir aç kapa düğmesi gibi çalışır., Enabled özelliğine true veya false değerlerini alır. Verilen değer true ise Trace mesajları yazdırılabilir, False ise mesajlar yazdırılamaz.

TraceSwitch sınıfı, bize aşamalı olarak trace mesajları yazdırmamızı sağlar. Herhangi bir aşama belitildiyse , belirtilen aşamanın altındaki tüm aşamalarda mesajlara dahil olur.Bu şekilde alınacak trace mesajlarını da aynı zamanda filtrelemiş oluruz. Bu yetenekleri Trace.Level özelliğini değiştirerek kullanabiliriz.. Trace.Level özelliği değerlerini TraceLevel numaratöründen alır.

Trace.Level =TraceLevel.Error; şeklinde  hata durumunda mesaj yazılması gerektiğini belirtmiş oluruz..

TraceLevel numaratörünün aldığı değerleri inceleyelim

  • Off          : Hiçbirşey yazılmaz.
  • Error       : Sadece hata mesajlarının yazılmasını sağlar.
  • Warning  : Uyarı ve hata mesajlarının yazılmasını sağlar
  • Info         : Bilgi, uyarı ve hata mesajlarının yazılmasını sağlar.
  • Verbose  : Tüm tip mesajların yazılmasını sağlar.

Switch sınıfları kullanıldıklarında , Trace sınıfının WriteIf ve WriteLineIf metodlarıyla kullanılırlar. Çünkü WriteIf ve WriteLineIf  metodlar belirli şartlara bağlı olarak çalışırlar ve switch sınıflarının aldıkları değerlerde bu şartları sağlarlar veya sağlamazlar. Aşağıdaki örnekte bu şart durumunu daha iyi inceleyebiliriz.

static void Main(string[] args)

{

TraceSwitch ts= new TraceSwitch("YazGelistir","YazGelistir switch"); //Switch nesnesini yaratıyoruz.

ts.Level=TraceLevel.Error;     //Sadece Error tipli mesajlar loga yazılsın.

EventLogTraceListener eltl= new EventLogTraceListener();

eltl.EventLog= new EventLog();

eltl.EventLog.Source="YazGelistir";

Trace.Listeners.Add(eltl);

Trace.WriteIf(ts.TraceError,"YazGelistir Logu");  // Eğer switch nesnesi Error aşamasında ise mesajı yazsın.

Trace.Close();

eltl.Close();

}

İlk satırda ts adında bir TraceSwitch sınıfını yarattık. TraceSwitch sınıfının Level özelliğini TraceLevel numaratöründen Error değerini alarak atadık. Biz uygulamızda sadece TraceSwitvh aşaması Error durumunda ise mesaj yazmak istiyoruz.Trace.WriteIf metodunun ilk parametresi şart bağlı bir parametredir. ts.TraceError ifadesi ts.Level değeri ile aynı olduğundan true döndürür ve "YazGelistir Logu" ifadesini Event Viewer da Application kısmına yazar.

Switch sınıflarını  en büyük özelliği , yazdığımız uygulamanın konfigürasyon dosyası içerisinden tanımlama yapılabilmesidir. Bu şekilde uygulama koduna müdahale etmeden , değerleri değiştirebilir  veya , aktif veya pasif yapabiliriz

Yukarıdaki örnekte YazGelistirSwitch isimli bir switch yarattık ve değerini 0 (Off) verdik

 

Sonuç

Umarım yaralı bir döküman olmuş, Tracing ile ilgili az da olsa bilgi sahibi olabilmişsinizdir.Sorularınız için cemkubilays@hotmail.com adresinden bana ulaşabilirsiniz.