Serilog ile Structured Logging
Serilog 2013’de yayınlanan ve çeşitli platformlara loglama yapmayı oldukça basite indirgeyen bir üçüncü parti kütüphanedir. Serilog’u diğer kütüphanelerden ayıran şey oldukça kullanışlı bir şekilde kurgulanmış “structured logging” özelliğidir.
Structured Logging Nedir?
Structured logging, bir veriyi nesne yapısında loglamak ve bu yapısal veriyi kolayca sorgulamaktır diyebiliriz. Bu kavramın daha iyi anlaşılması için örnek üzerinden gitmemiz daha kolay olacaktır. Hem böylece Serilog’un çalışma mantığını kavramış oluruz.
Herhangi bir loglama yaparken log mesajımızın içerisinde genellikle iki element olur; bunlar mesaj ve değeridir. Örnek verecek olursak:
Log.Debug(“Hello {name}”, name);
Yazdığımız bu kod vermiş olduğumuz nesneyi bir stringe döndürecek ve o şekilde loglama yapacaktır. Herhangi bir arama yapmak istediğimizde tüm stringin içerisinde arama yapmamız gerekecektir. Fakat serilog yapısında bu durum şu şekilde ilerlemektedir.
Kullanım 1
Log.Debug(“Hello {name}”,name);
Kullanım 2
Log.Debug(“Hello {@name}”,name);
Kullanım 1’de parametreyi bir string olarak ele alırsak şu şekilde logladığını görürüz.
Ve bu string parametreyi aşağıdaki gibi arayabilir ve sonucunu alabiliriz.
Burada bir string değer üzerinden loglama yaptık ve sorgulamayı gerçekleştirdik. Peki bir nesneyi tamamen loglamak ve sorgulamak isteseydik bunu nasıl yapabilirdik?
var user = new { Name = "Hakkı", Age = 15 }; Log.Error("Hello {@User}", user);
Yukarıda gördüğümüz gibi User parametremiz artık bir obje. İlk kullanımdan farklı olarak burada string içerisindeki süslü parantez ifadesini @User şeklinde yazdığımız dikkatinizi çekmiştir. Bu şekilde bir loglama yaptığımızda karşımıza şöyle bir log satırı çıkacak. Aşağıda hem loglanan veriyi, hem de log sorgusu sonrasında Name=”Hakkı” olan bilgiye ulaştığımızı görebilirsiniz.
Aslında yazının başında structured logging’in ne anlama geldiğine dair kısa bir açıklama yapmıştım. Bu örnekte gördüğümüz kullanım şekliyle structured logging’i basit ve iyi bir örnekle göstermiş olduk.
Peki yazımızın konusu olan Serilog’a dönecek olursak; Serilog’u nasıl kullanabileceğimize adım adım bakalım. Örneği bir konsol uygulaması üzerinden anlatacağım. Aşağıdaki paketleri projemize ekleyelim.
Projeye ilgili Serilog bileşenlerini kurduktan sonra logger objesini ilk kez oluşturmamız ve akabinde log yazacak ifadeleri yazmamız gerekiyor. using Serilog; ile ihtiyaç duyduğumuz namespace’i sınıfımızın başına yazıyoruz. Sonrasında aşağıdaki kod parçasıyla logger objesini oluşturuyoruz.
Log.Logger = new LoggerConfiguration() .WriteTo.Console() .CreateLogger(); var user = new { Name = "Hakkı", Age = 15 }; Log.Error("Hello {@User}", user);
Burada yapmış olduğumuz tanım konsol ekranında loglama yapmak için. Kodu çalıştırdığımızda konsol ekranında aşağıdaki gibi user nesnesinin serileştirilerek konsola yazıldığını görebiliriz.
Serilog Sinks
Serilog kütüphanesi içerisinde farklı formatlardaki kaynaklara log yazmamızı sağlayan provider’lara Sink adı verilmektedir. SQL Server, PostgreSQL, Elasticsearch, MongoDB, RabbitMQ gibi kaynakların yanında Amazon DynamoDB, Azure DocumentDB gibi bulut tabanlı veri hizmetlerine kadar çok sayıda kaynağa log atmamıza olanak sağlayan yapılara Serilog Sink adı veriliyor. Bu adresten Serilog üzerinde loglama yapabileceğiniz kaynakların bir listesini ve detaylarını görebilirsiniz.
Bir örnekle SQL Server sink’ini nasıl kullanabileceğimize bakalım. Yeni bir konsol projesini açıp ilk olarak aşağıdaki nuget paketlerini kuruyoruz.
Bu işlemin ardından kodlamaya geçmeden önce veritabanında ilgili log tablosunu oluşturalım. Aşağıdaki CREATE sorgusunu kullanacağımız veritabanı üzerinde çalıştırmamız gerekiyor.
CREATE TABLE [dbo].[Logs]( [Id] [int] IDENTITY(1,1) NOT NULL, [Message] [nvarchar](max) NULL, [MessageTemplate] [nvarchar](max) NULL, [Level] [nvarchar](128) NULL, [TimeStamp] [datetimeoffset](7) NOT NULL, [Exception] [nvarchar](max) NULL, [Properties] [xml] NULL, [LogEvent] [nvarchar](max) NULL, CONSTRAINT [PK_Logs] PRIMARY KEY CLUSTERED ( [Id] ASC )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY] ) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY] GO
SQL Server tablosu için aşağıdaki iki namespace’i kodun yazılacağı sınıfa eklenmesi gerekiyor.
using Serilog; using Serilog.Sinks.MSSqlServer;
Akabinde log nesnesini oluşturuyor ve yeni bir log atmak için gerekli kodlamayı aşağıdaki gibi yapıyoruz.
Log.Logger = new LoggerConfiguration() .WriteTo.MSSqlServer("Server=localhost;Database=SeriLog;User Id=sa;Password=123456;","Logs") .CreateLogger(); Log.Information("Hakkı bugün okuldan kaçtı"); Log.ForContext("User", "Müdür").Information("Hakkı fizikten kaldı."); Log.Error("Hakkı adlı öğrencinin velisinin telefon numarası bulunamadı."); Log.Fatal("Hakkı hakka kavuştu.");
Burada 4 farklı loglama metodunu kullandık. Aşağıdaki görüntüde kayıtların Logs tablosuna atılmış hallerini görebilirsiniz.
Seq Dashboard
Attığımız logları bir arayüzden düzgün şekilde okumamızı ve filtrelemeler yapmamızı sağlayan Seq Dashboard adında bir ürün bulunmaktadır. Yazının başında belirttiğimiz gibi Serilog structured logging yapılmasını sağlıyordu. İşte Seq Dashboard’da bilhassa bu yapısal log objelerini düzgün şekilde bir ekranda listeleyip okumamızı ve veriler üzerinde filtreler yapmamızı sağlıyor.
Seq’i kullanabilmek için öncelikle kendi sitesi olan https://datalust.co/ adresinden indirme yapmamız gerekiyor. İndirme tamamlandıktan sonra kurulumu oldukça basit. Kurulum esnasında, Seq’e gönderilen logların nereden yayınlanacağını seçiyoruz, bu bölüm varsayılan olarak http://localhost:5341 olarak geliyor.
Bu yönlendirmeyi hiç değiştirmediğimizi var sayarak kodlarımızı yazmaya başlayalım. Yine bir konsol uygulaması üzerinden ilerliyoruz. Nuget Package Manager’dan aşağıda bulunan kütüphaneleri indirelim.
Akabinde aşağıdaki gibi kodlarımızı yazıyoruz.
using Serilog; ... Log.Logger = new LoggerConfiguration() .WriteTo.Seq("http://localhost:5341") .CreateLogger(); var user = new { Name = "Hakkı", Age = 15 }; for (int i = 0; i < 10; i++) { Log.Error("Hello {@User} {@Id} numaralı üyesin.",user,i); }
Dashboard’da biraz fazla log olması için bir döngü içinde loglar oluşturduk. Kodları çalıştırdıktan sonra http://localhost:5341 adresini tarayıcımızdan açtığımızda logları Seq Dashboard ekranında görebileceğiz.
Atılan logları listelendiği bu sayfada herhangi bir kayıda tıklayarak loglanan structured yapıda nesnenin detaylarını da görebiliriz.
Seq Dashboard dışında loglarınızı farklı cihaz ve platformlardan okumak isterseniz Seq’in API kütüphanesi de bulunmaktadır. Dilerseniz yine nuget’ten bu örnekte kurduğumuz paketlere ek olarak Seq.Api paketini de uygulamanıza dahil ederek loglarınızı bir Api üzerinden kolayca dışarı açabilirsiniz.
Bu yazıda structured logging’i kolayca yapmamızı sağlayan Serilog’u, farklı kaynaklara log atmamızı sağlayan Sink yapısını ve Seq Dashboard’u basit örneklerle ele almaya çalıştık.