Log4Net Günlüklerine Güzel Bir Arayüz

   Daha önceki makalelerimde Log4Net’ten ve biz yazılımcıların hayatını nasıl kolaylaştırdığından sizlere bahsetmiştim. Bu makalemde ise sizlere Log4Net ile oluşturulan uygulama günlüklerini browser üzerinden nasıl daha güzel ve anlaşılır olarak gösterebileceğinizi anlatacağım.

   Kolay işlenebilmesi ve pek çok araç ile desteklenmesi nedeniyle günümüzde pek çok veri yazılımcılar tarafından xml formatında tutulmakta. Öyle ki, bazı web sitelerinin kodları incelendiğinde doğrudan veritabanı sorgu sonuçları xml olarak istemciye gönderildiği, ek olarak belirtilen bir xslt yardımıyla da bu verinin istemcide html’e dönüştürüldüğü görülecektir. Böylesi bir işlem sonrası hem sunucu işlemcisi daha az kullanılacak, hem de sayfa boyutunu önemli derece azalacaktır.

   Benzer şekilde, pek çok yazılımcı programsal olarak işleyebilmek adına Log4Net ile tuttuğu uygulama günlüklerini xml formatter ile dosyalara saklamakta. Bu sayede günlük dosyasını istediği şekilde işleyebilmektedir. Bu yöntemin aklıma gelen tek dez avantajı ise düz bir metin halindeki bir günlük dosyasına kıyasla gözle daha zor okunuyor olmasıdır. Bu noktada bir önceki paragrafta örneklediğim web sitelerinin yaklaşımına benzer bir şekilde Log4Net’in xml günlük dosyaları da bir xslt ile işlenerek oldukça görsel bir çıktı elde edilebilir.

  Aşağıda, makalemin devamında örnek olarak kullanacağım ve xml formatter ile loglanmış bir günlük dosyasının içeriğini bulabilirsiniz;

<event logger="Enterprisecoding.OrnekUygulama.MainForm" timestamp="2011-09-23T22:36:56.8609054+03:00" level="DEBUG" thread="1" domain="OrnekUygulama.exe" username="fatih"><message>Uygulama başladı</message><properties><data name="log4net:HostName" value="terra" /><data name="LogDirectory" value="C:\Logs" /></properties></event>
<event logger="Enterprisecoding.OrnekUygulama.ParametreYoneticisi" timestamp="2011-09-23T22:36:57.8609054+03:00" level="INFO" thread="1" domain="OrnekUygulama.exe" username="fatih"><message>Komut satırı parametreleri işleniyor</message><properties><data name="log4net:HostName" value="terra" /><data name="LogDirectory" value="C:\Logs" /></properties></event>
<event logger="Enterprisecoding.OrnekUygulama.ParametreYoneticisi" timestamp="2011-09-23T22:36:57.8609054+03:00" level="WARN" thread="1" domain="OrnekUygulama.exe" username="fatih"><message>Komut satırı parametreleri belirtilmemiş</message><properties><data name="log4net:HostName" value="terra" /><data name="LogDirectory" value="C:\Logs" /></properties></event>
<event logger="Enterprisecoding.OrnekUygulama.EklentiYoneticisi" timestamp="2011-09-23T22:36:57.8609054+03:00" level="INFO" thread="1" domain="OrnekUygulama.exe" username="fatih"><message>Eklentilerin işlenmesine başlanıyor</message><properties><data name="log4net:HostName" value="terra" /><data name="LogDirectory" value="C:\Logs" /></properties></event>
<event logger="Enterprisecoding.OrnekUygulama.EklentiYoneticisi" timestamp="2011-09-23T22:36:57.8609054+03:00" level="DEBUG" thread="1" domain="OrnekUygulama.exe" username="fatih"><message>abc.dll içerisindeki eklentiler işleniyor</message><properties><data name="log4net:HostName" value="terra" /><data name="LogDirectory" value="C:\Logs" /></properties></event>
<event logger="Enterprisecoding.OrnekUygulama.EklentiYoneticisi" timestamp="2011-09-23T22:36:57.8609054+03:00" level="DEBUG" thread="1" domain="OrnekUygulama.exe" username="fatih"><message>xyz.dll içerisindeki eklentiler işleniyor</message><properties><data name="log4net:HostName" value="terra" /><data name="LogDirectory" value="C:\Logs" /></properties></event>
<event logger="Enterprisecoding.OrnekUygulama.EklentiYoneticisi" timestamp="2011-09-23T22:36:57.8609054+03:00" level="INFO" thread="1" domain="OrnekUygulama.exe" username="fatih"><message>Eklentilerin işlenmesi tamamlandı</message><properties><data name="log4net:HostName" value="terra" /><data name="LogDirectory" value="C:\Logs" /></properties></event>
<event logger="Enterprisecoding.OrnekUygulama.VeritabaniYoneticisi" timestamp="2011-09-23T22:36:58.8609054+03:00" level="INFO" thread="1" domain="OrnekUygulama.exe" username="fatih"><message>Veritabanı bağlantısı kuruluyor</message><properties><data name="log4net:HostName" value="terra" /><data name="LogDirectory" value="C:\Logs" /></properties></event>
<event logger="Enterprisecoding.OrnekUygulama.VeritabaniYoneticisi" timestamp="2011-09-23T22:36:58.8609054+03:00" level="DEBUG" thread="1" domain="OrnekUygulama.exe" username="fatih"><message>Veritabanı bağlantısı için kullanılan bağlantı cümleciği : Data Source=localhost; Initial Catalog=veritabanim; User Id=su; Password=1234;</message><properties><data name="log4net:HostName" value="terra" /><data name="LogDirectory" value="C:\Logs" /></properties></event>
<event logger="Enterprisecoding.OrnekUygulama.VeritabaniYoneticisi" timestamp="2011-09-23T22:36:59.8609054+03:00" level="ERROR" thread="1" domain="OrnekUygulama.exe" username="fatih"><message>Bağlantı sırasında hata oluştu</message><properties><data name="log4net:HostName" value="terra" /><data name="LogDirectory" value="C:\Logs" /></properties><exception>System.NullReferenceException: Nesne başvurusu bir nesnenin örneğine ayarlanmadı.
   konum: Enterprisecoding.OrnekUygulama.VeritabaniYoneticisi.Baglan() C:\Enterprisecoding\OrnekUygulama\VeritabaniYoneticisi.cs içinde: satır 118
   konum: Enterprisecoding.OrnekUygulama.MainForm.BaglantiKur(ParametreYoneticisi parametreYoneticisi) C:\Enterprisecoding\OrnekUygulama\MainForm.cs içinde: satır 384</exception></event>
<event logger="Enterprisecoding.OrnekUygulama.MainForm" timestamp="2011-09-23T22:37:00.8609054+03:00" level="FATAL" thread="1" domain="OrnekUygulama.exe" username="fatih"><message>Yönetilememiş hata nedeniyle uygulama sonlandırılıyor</message><properties><data name="log4net:HostName" value="terra" /><data name="LogDirectory" value="C:\Logs" /></properties></event>
<event logger="Enterprisecoding.OrnekUygulama.MainForm" timestamp="2011-09-23T22:37:01.8009002+03:00" level="DEBUG" thread="1" domain="OrnekUygulama.exe" username="fatih"><message>Uygulama sonlandı</message><properties><data name="log4net:HostName" value="terra" /><data name="LogDirectory" value="C:\Logs" /></properties></event>

   Bu dosyayı bir browser üzerinde xslt ile işlenmiş olarak görmek için öncelikle dosyanın başında kullanılacağı olan xslt belirtilmelidir. İşte tam da bu noktada tahminimce ilk problemimizi farkedeceksiniz; günlük dosyamız düzgün bir xml dosyası değil! Günlüğün geçerli bir xml içermesi için öncelikle tek bir ana düğüme sahip olması gerekli; fakat bizim örneğimizde 12 adet ana düğüm bulunmakta (event düğümleri). Dolayısıyla da browser’lar bu haliyle günlüğü yorumlayamayacaktır.

   Bu durumu  düzeltmek için Log4Net appender’larının header ve footer özelliklerini kullanmak akla gelebilir. Header yardımıyla günlük dosyasının en başına bir başlangıç düğümü ve xslt dosyamıza bir atıf eklenebilir; fakat peki ya footer? Dosyamızın içeriğini ne zaman inceleyeceğimiz belli olmadığı için bu yaklaşım çözüm olmayacaktır. Log4Net footer’ı sadece dosyayı kapatırken koyacaktır. Bunun anlamı ise henüz kapanmamış, logların yazılmaya devam ettiği bir sırada günlük içeriğinin geçerli bir xml olmayacağıdır. Peki bu durumda ne yapmalıyız?

  Bu noktada sanırım biraz xml bilgisi faydalı olacaktır; xml tanımlaması bize bir xml dosyası içerisinde bir başka xml dosyasına atıfta bulunma şansı sunmakta. ENTITY anahtar kelimesi yardımıyla yapılabilecek bu işlemi en basit haliyle aşağıda bulabilirsiniz;

<!ENTITY [isim] SYSTEM [konum]>

  Bu tanımlamada [isim] yazılı yere verdiğimiz değer harici dosyamıza bir referans, [konum] yazılı yere verdiğimiz değer ise harici dosyamızın konum bilgisi olacaktır. Bunu aynı bir değişken tanımı gibi düşünebilirsiniz, [isim] değişkenimizi adı olurken, [konum] ile belirtilen dosya içeriği değişkenimizi değeri olacaktır. Bu tanımlama ardından & ve ; karakterleri arasına değişken adını verek içeriği ana xml dosyamızda istediğimiz noktada kullanabiliriz.

   Xml ile ilgili bu detay bilgi ardından sanırım günlük dosyamızın bir ana düğüme sahip olmaması problemini nasıl aşabileceğimiz konusunda kafanızda yeni fikirler oluşmuştur. Oluşturacağımız ikinci bir xml dosyasına ihtiyacımız olan ana düğümü koyarak içeriğini günlük dosyamızı referans gösterek doldurabiliriz. Bu durumda, oluşturacağımız ikinci dosyamız aşağıdaki şekilde olmalıdır;

<?xml version='1.0' encoding='utf-8'?>
<!DOCTYPE log4j:eventSet SYSTEM 'log4j.dtd' [<!ENTITY data SYSTEM 'Log.xml'>]>
<log4j:eventSet version='1.2' xmlns:log4j='http://jakarta.apache.org/log4j'>&data;</log4j:eventSet>

  Benim gibi daha çok XSD dünyasında bulunuyorsanız aklınıza log4j:event tanımlamasının ne olduğu sorusu gelebilir. Bu tanımlama bize özel şema tanımlaması yapabilme olanağı sunmakta. Kısaca tarayıcıya kendi tasarladığımız bir xml dosyasıyla karşı karşıya olduğunu ve bunun şemasının da log4j.dtd dosyası içerisinde bulunabileceğini belirtmekteyiz. Tarayıcı otomatik olarak şemayı tanıyacak, log.xml dosyası içeriğini de bu dosya içerisine yerleştirecektir. Bu durumda nihayi görüntümüzde ana düğüm içerisinde log girdilerimiz bulunacak ve düzgün bir xml’e sahip olacağız. Oluşturduğumuz bu ikinci dosyayı bir browser ile açacak olursanız aşağıdaki görüldüğü gibi tam bir xml ile karşılaşacaksınız;

Log dosyası içeriğinin <!ENTITY data SYSTEM 'Log.xml'> kullanılarak ikinci bir dosyaya eklenmiş hali

   Elimizde artık düzgün bir xml olduğuna göre xslt kullanarak bunu html’e dönüştürebilmekte bir engel yok. Bunu için log4j:eventSet ana düğümünden hemen önce aşağıda tanımlama ile xslt işlemini tetikleyebiliriz;

<?xml-stylesheet type='text/xsl' href='Log2Html.xslt'?>

  Aşağıda ise en basit haliyle log dosyamızı html’e dönüştürecek olan xslt’yi bulabilirsiniz;

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<xsl:stylesheet version="1.0"
         xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
         xmlns:log4j="http://jakarta.apache.org/log4j">
 <xsl:output method="html" doctype-system="http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd" doctype-public="-//W3C//DTD XHTML 1.0 Strict//EN" indent="yes" />

 <xsl:template match="/">
  <html lang="tr-TR" xml:lang="tr-TR" xmlns="http://www.w3.org/1999/xhtml">
   <head>
    <title>Uygulama Logları</title>      </head>
   <body>
    <table cellpadding="0" cellspacing="0" border="1" class="display" id="uygulamaLoglari">
        <thead>
            <tr>
               <th width="10">Id</th>
               <th width="138">Zaman</th>
               <th width="70">Seviye</th>
               <th width="100">Sınıf</th>
               <th>Mesaj</th>
            </tr>
        </thead>
        <tbody>
      <xsl:for-each select="log4j:eventSet/event">
       <tr>
        <td>
         <xsl:value-of select="position()"/>
        </td>
        <td>
         <xsl:call-template name="FormatDate">
          <xsl:with-param name="DateTime" select="@timestamp"/>
         </xsl:call-template>
        </td>
        <td>
         <xsl:value-of select="@level"/>
        </td>
        <td>
         <xsl:value-of select="@logger"/>
        </td>
        <td>
         <xsl:value-of select="message/text()"/>
        </td>
       </tr>
      </xsl:for-each>
     </tbody>
    </table>
   </body>
  </html>
 </xsl:template>

 <xsl:template name="FormatDate">
  <xsl:param name="DateTime" />
  <xsl:variable name="mo">
   <xsl:value-of select="substring($DateTime,6,2)" />
  </xsl:variable>
  <xsl:variable name="day">
   <xsl:value-of select="substring($DateTime,9,2)" />
  </xsl:variable>
  <xsl:variable name="year">
   <xsl:value-of select="substring($DateTime,1,4)" />
  </xsl:variable>
  <xsl:variable name="time">
   <xsl:value-of select="substring($DateTime,12,8)" />
  </xsl:variable>
  <xsl:variable name="hh">
   <xsl:value-of select="substring($time,1,2)" />
  </xsl:variable>
  <xsl:variable name="mm">
   <xsl:value-of select="substring($time,4,2)" />
  </xsl:variable>
  <xsl:variable name="ss">
   <xsl:value-of select="substring($time,7,2)" />
  </xsl:variable>
  <xsl:value-of select="$day"/>
  <xsl:value-of select="'.'"/>
  <xsl:value-of select="$mo"/>
  <xsl:value-of select="'.'"/>
  <xsl:value-of select="$year"/>
  <xsl:value-of select="' '"/>
  <xsl:value-of select="$hh"/>
  <xsl:value-of select="':'"/>
  <xsl:value-of select="$mm"/>
  <xsl:value-of select="':'"/>
  <xsl:value-of select="$ss"/>
 </xsl:template>
</xsl:stylesheet>

  XSLT dönüşümü ardından ortaya çıkan html içeriği

 

   Bu haliyle artık log dosyamızı browser üzerinden kolaylıkla analiz edebilir, hataya daha kolay ulaşarak düzeltebiliriz.

   İşin içine biraz da JQuery ve DataTables eklentisini katacak olursak ortaya çok daha güzel sonuçlar çıkacaktır. Aşağıda, yazımın sonunda sizlerle paylaşacağım ve JQuery, DataTable yardımıyla oluşturduğum nihayi xslt dönüşümünü görebilirsiniz;

JQuery ve DataTable yardımıyla oluşturduğum nihayi xslt dönüşümünü

   Artık xml olarak tuttuğunuz günlük dosyanızın içeriğini kolaylıkla  bir browser içeriğinde görebilir, filtreleme yapabilir, sütünları sıralayabilir, sayfalama ile daha temiz bir görünüm elde edebilirsiniz. Üstelik tüm bunları bir kaç basit adım ile yapacaksınız. Bunu bir adım daha ileri taşımak isterseniz, basit bir uygulama oluşturarak formunuzun üzerine web browser kontrolünü koyabilir ve logları bu browser üzerinde kullanıcılarınıza gösterebilirsiniz.

Örnek bir Log4Net günlük dosyası Xslt dönüşümü Uygulaması

JQuery ve DataTable yardımıyla oluşturduğum nihayi xslt dönüşümünü

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+

7 yorum

  1. halit   •  

    Merhaba Fatih Bey,
    vermiş olduğunuz uygulamayı indirdim ancak günlükdosyasi.xml i açtığımda Bir sonuç bulunamadı yazıyor çok uğraştım ama bir türlü veri getirmeyi başaramadım çalışan bir örneğini bana maille atabilirmisiniz acaba

    • Fatih Boy   •     Yazar

      Merhaba Halit,
      Tahminimce günlükdosyasi.xml’i Internet Explorer 9 ile açtın. Tarayıcı modunu IE8 yapıp denersen çalışacaktır.

  2. halit   •  

    Teşekkürler Fatih Bey

  3. Mehmet   •  

    Merhaba hocam,
    Belirttiğiniz XML formatını oluşturamadım, projeyi yayınlayabilirseniz ya da xml formatter ile nasıl formatlandığı hakkında bilgi verebilirseniz sevinirim.

    Saygılarımla

    • Fatih Boy   •     Yazar

      Merhaba Mehmet,
      Aşağıdaki appender yardımıyla uygun log xml’leri oluşturabilirsin. Burada dikkat edilecek nokta dosya layout’u olarak XmlLayoutSchemaLog4j kullanılması;


      <appender name="FileAppender" type="log4net.Appender.FileAppender">
      <file value="log-dosyasi.txt" />
      <appendToFile value="true" />
      <layout type="log4net.Layout.XmlLayoutSchemaLog4j">
      <locationInfo value="true" />
      </layout>
      </appender>

  4. Mehmet   •  

    Merhaba Fatih Bey,
    XML Schema’sını sizin örneğinizdeki gibi oluşturamıyorum, aşağıdaki gibi oluşuyor. IE’nin açmaması bir yana, timestamp vs. hiç okunaklı değil.

    <log4j:event logger="LoggingConcern.Program" timestamp="1415884738020"…..

    Custom XML save mi yaptınız?

    Saygılarımla

    • Fatih Boy   •     Yazar

      Merhaba Mehmet,
      Sanırım oluşan log dosyasını doğrudan browser’da açmayı denedin. Bu durumda xml dosyasına herhangi bir xslt uygulanmayacağı için browser varsayılan olarak dosya içeriğini göstermeyi deneyecektir. Başarılı bir şekilde çıktı alabilmek adına makalemde paylaştığım adımları takip etmen önemli. Bu adımları takip ederek browser’da günlükdosyasi.xml‘i açarak istediğin içeriğe ulaşabilirsin.

      Not; bir önceki açıklamamda yer alan log-dosyasi.txt örnek olup, makaleye uyarladığımızda bunu yerine Log.xml değerini vermek daha doğru olacaktır.

Bir Cevap Yazın

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