Caner Tosuner

Leave your code better than you found it

Asp.Net Core ElasticSearch Logging ve Kibana Kurulumu & Kullanımı

Daha önceki yazılarda asp.net coreelasticsearchlogging konularına ayrı ayrı farklı örneklerle değinmiştik. Bu yazımızda ise asp.net core projelerinde default logging storage olarak elasticsearch konfigure edip bu elasticsearch'de ki index'lerde bulunan log kayıtlarını Kibana kullanarak nasıl görüntüleyebiliriz örnek proje ile anlatacağız. 

Logging bir uygulama için olmazsa olmazların başında gelmektedir. Uygulama cycle'ın da loglama işlemi doğru zamanda doğru yerde ve en önemlisi bir birine bağlı olacak şekilde yaptığınızda log sonucunda oluşan veri aslında sizin için paha biçilmez bir monitoring aracı olabilir. Analiz yapabilir, alert oluşturabilir, çeşitli raporlar sağlayabiliriz. Bütün bu saydıklarımız ve daha fazlası için çeşitli çözümler sunulabilir ancak şuan ki günümüz yazılım dünyasında ElasticSearch, Kibana with Logstach üçlüsü en performanslı ve open-source olduğundan community'si en sağlam çözüm olarak karşımıza çıkmakta.

Uygulama geçmeden önce bilgisayarınızda .Net Core SDK, ElasticSearch ve Kibana yüklü olmalı. Kurulumlarla ilgili detaylara .Net Core SDK ve ElasticSearch için aşağıdaki başlık altında bulunan yazılarımızdan ulaşabilirsiniz. Kibana kurulumunu ise bu yazımızda anlatacağız.

1) .Net Core Sdk 2.1 Kurulumu

.Net Core SDK 2.1 kurulumunu NET Core 2.0 to 2.1 Migration yazımızda anlatmıştık ve bu yazıda belirtilen instraction'ları takip ederek sdk kurulunu sağlayabilirsiniz.

2) ElasticSearch Kurulumu

ElastciSearch kullanabilmek için bu yazıda anlatıldığı gibi kurulum işlemlerini yapıp kurulumun doğru olup olmadığını test etmek adına browser üzerinden  http://localhost:9200/ adresine httpget isteği yaptığınızda kurulu olan es'ün bilgilerini görüntüleyebilirsiniz.

3) Kibana Kurulumu

Kibana kurulumu için elastic.co adresinde yer alan download sayfasından Kibana için ilgili işletim sisteminize ait dosyaları download edelim. Ben local'de windows kullandığım için Windows uyumlu versiyonu indirdim.

Download işlemi bittikten sonra rar'lı dosyaları ben C sürücüsünü seçtim extract edelim. Extract ettikten sonra C:\kibana-6.3.2\bin klasöründe bulunan kibana.bat dosyasını run edip kibanayı start etmesini bekleyelim. Dilerseniz Kibanayı işletim sistemine service olarak register'da edebilirsiniz.

Kibananın çalışıp çalışmadığından emin olmak için browser üzerinden http://localhost:5601 adresine giderek ulaşabilirsiniz. Elasticsearch'te index oluşturduktan sonra kibana'ya tekrar döneceğiz.

4) Asp.Net Core Api Proje Oluşturulması

Artık örnek projemizi geliştirmeye başlayalım. İlk olarak vs'da ProductApi adında bir Asp.net core 2.1 Web Api projesi oluşturalım.

Projeyi oluşturduktan sonra nuget'ten indirip kullanacağımız kütüphaneleri projemiz için kuralım. Uygulama loglarını atarken Serilog kütüphanesini ve onun ElasticSearch ve .net Core için olan extension dll'lerini projemize nuget üzerinden bulup ekleyelim.

Yukarıdaki paketlerin nuget üzerinden kurulum işlemleri tamamlandıktan sonra projede yer alan Startup.cs sınıfı içerisinde serilog ve elasticsearch için gerekli olan logging konfigurasyonlarını aşağıdaki gibi yapalım. İlk olarak ConfigureServices metodunda serilog ve serilog'un storage olarak elasticsearch'ü kullanacağını belirten kod bloğunu aşağıdaki gibi yazalım.

public void ConfigureServices(IServiceCollection services)
{
    Log.Logger = new LoggerConfiguration()
        .Enrich.FromLogContext()
        .WriteTo.Elasticsearch(new ElasticsearchSinkOptions(new Uri("http://localhost:9200/"))
        {
            AutoRegisterTemplate = true,
        })
        .CreateLogger();

    services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
}

Sonrasında ise Configure metodunda yukarıda ilgili tanımlamalarını yaptığımız serilog'u LoggerFactory'e ekleyip uygulamanın serilog üzerinden logging yapacağını belirttiğimiz kısmı yazalım.

public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
{
    if (env.IsDevelopment())
    {
        app.UseDeveloperExceptionPage();
    }
    else
    {
        app.UseHsts();
    }

    loggerFactory.AddSerilog();//serilog servisini eklediğimiz yer

    app.UseMvc();
}

Kurulumlarımızı ve proje geliştirme adımlarını tamamladık artık projemizi run ederek örnek olarak bir ProductController açıp içerisinde bulunan Get metoduna ürün isimleri girmiştim browser üzerinden http://localhost:60506/api/product adresine httpGet isteği attığımızda aşağıdaki gibi ürün isimlerini listelediğini göreceğiz.

[Route("api/[controller]")]
[ApiController]
public class ProductController : ControllerBase
{
    // GET api/product
    [HttpGet]
    public ActionResult<IEnumerable<string>> Get()
    {
        return new List<string> { "Mobile Phone", "Laptop", "Books", "Shoes" };
    }
}

Uygulamada minimum log level Information olduğundan hem uygulama start event'leri hemde end-point'e yaptığımız request-response'a ait log mesajlarını şuan elasticsearch'de logstash-yyy.MM.dd (logstash-2018.07.26 gibi.) formatında bir index oluşturup bu index'e günlük olarak insert etmiş bulunuyor. Bu index'in yaratılıp yaratılmadığını anlamak içinse yine browser üzerinden elasticsearch'ün api'sine istekte bulunarak öğrenebiliriz. Browser'dan http://localhost:9200/_cat/indices?v adesine httpGet isteği yolladığınızda yukarıda bahsettiğimiz formatta index'in oluştuğunu göreceksinizdir.

Şimdi ise son adım olarak index'lemiş olduğumuz bu logları Kibana üzerinde görüntüleyelim. http://localhost:5601 adresine gittiğimizde şuan için herhangi bir index tanımlaması yapmadığımızdan hiçbir şey görüntülenmemekte. Bunun için Kibana'da sol menüde yer alan Management sayfasına giderek Index Patterns ekranında Index pattern textbox'ına "logstash-*" yazarak Next dedikten sonra çıkan ekranda Time Filter'ı log hangi property'ye göre yapacağını belirttiğimiz dropdown'dan @timestamp field'ını seçip Create Index Pattern butonuna tıkladıktan sonra logstash- formatına uygun bütün indexleri Kibana'ya tanımlamış olduk.

 

Indexlemiş olduğumuz logları görüntüleyebilmek için yine sol menüden Discover sayfasına giderek zaman filtresine göre aşağıdaki gibi uygulamamıza ait logları görebiliriz. Dilersek search box'ı kullanarak log içersiinde aramak istediğimiz bir metni kolayca arayabilir yada uygulamanın throw ettiği exception'lar için dashboard'lar tanımlayıp daha metric'ler kullanarak kolayca görüntüleyebiliriz. 

 

Geleneksel logging tekniklerinde genelde erişilmesi ve anlaşılması zor içinde kaybolunabilen yapılar söz konusuydu. Öyle ki log dosyaları arasında aradığımız bir text'i bulmak bazen saatlerimizi bile alabilmekteydi. Ancak elasticsearch ve kibana bunu tamamiyle değiştirdi desek yanlış olmaz. Bu ikili ile birlikte uygulamanızın ürettiği günlük yüzlerce megabyte'lık log text'ini elasticsearch'e index'leyip çok rahat ve h��zlı bir şekilde kibana üzerinden erişebilirsiniz. X pack kullanarak çeşitli alert yapıları tasarlayabilir uygulamanızla ilgili herhangi olağan dışı bir durumda en hızlı şekilde kolayca haberdar olabilirsiniz. 

Source Code

Asp.Net Core Logging

Asp.net core yazılarında daha önce asp.net core'a giriş yapmıştık ve devamında build-in container'dan bahsetmiştik. Kısaca tanımlayacak olursak; asp.net core microsoft tarafından open-source olarak geliştirilmiş asp.net'e göre daha modüler bir cross platform web kütüphanesidir. 

Bu yazıda ise asp.net core'da logging nedir nasıl yapılır inceleyeceğiz. 

Log bir uygulama için olmazsa olmazların başında gelir ve projeler için oldukça önemli bir feature'dır. Yukarıda da yazdığımız gibi asp.net core modüler bir framework dür ve logging de asp.net core uygulamanızda kolayca ayağa kaldırabileceğiniz bir service olarak yer almaktadır.

Öncelikle Vs'da AspCoreLogging adında bir web-api projesi oluşturalım. Eğer oluşturduğunuz proje asp.net core 1.x versiyonu ise projemize Microsoft.Extensions.Logging dll'ini referans olarak eklememiz gerekmekte ama eğer asp.net core 2.x versiyonlarından birine ait ise default olarak gelmekte.

Microsoft.Extensions.Logging namespace'i bizim asp.net core içerisinde logging için gerekli olan sınıf&arayüz ve metotları vs. içermekte.

Bunlara bakacak olursak;

  • ILogger
  • ILoggingFactory
  • LoggingFactory
  • ILoggingProvider

built-in class ve interface'leri bu namespace altında bulunmakta.

ILogger interface'i kullanacağımız log-storage'a log kaydetmemizi sağlayan gerekli metotları içerir.

public interface ILogger
{ 
   void Log<TState>(LogLevel logLevel, EventId eventId, TState state, Exception exception, Func<TState, Exception, string> formatter);
   bool IsEnabled(LogLevel logLevel);
   IDisposable BeginScope<TState>(TState state);
}

Geliştireceğimiz custom-logger'ı oluşturmak için ILogger interface'ine ait metotları extend edip metotlarını kullanacağız.

ILoggerFactory interface'i ise yukarıda bahsettiğimiz ILogger arayüzünü extend eden custom-logger'ın instance'ını oluşturmada kullanacağımız interface'dir.

public interface ILoggerFactory : IDisposable
{
    ILogger CreateLogger(string categoryName);
    void AddProvider(ILoggerProvider provider);
}

Asp.net Core içerisinde yukarıda bahsettiğimiz ILoggerFactor interface'ini implement eden LoggerFactory sınıfı bulunmakta. Runtime'da asp.net core framework bu sınıfa ait instance yaratarak default gelen kendi built-in IoC container'ına register eder.

ILoggingProvider interface'i istenilen logging kategorisindeki gerekli logger sınıflarını yaratır ve yönetir. Framework içerisinde default olarak gelen provider'lar şu şekildedir;

  • Console
  • Debug
  • EventSource
  • EventLog
  • TraceSource
  • Azure App Service
public interface ILoggerProvider : IDisposable
{
   ILogger CreateLogger(string categoryName);
}

Bu interface'i bize projede kullanacağımız customLogger'ın instance'ını oluşturmamızı sağlayacak sınıfı tanımlarken kullanacağız.

File Logging Impl.

Şimdi ise yukarıda bahsettiğimiz adımları fileLogging için geliştirmeye başlayalım. İlk olarak projemize ILogger interface'ini implement eden FileLogger sınıfını aşağıdaki gibi tanımlayalım.

    public void Log<TState>(LogLevel logLevel, EventId eventId, TState state, Exception exception, Func<TState, Exception, string> formatter)
    {
        var message = string.Format("{0}: {1} - {2}", logLevel.ToString(), eventId.Id, formatter(state, exception));
        WriteMessageToFile(message);
    }
    private static void WriteMessageToFile(string message)
    {
        const string filePath = "C:\\AspCoreFileLog.txt";
        using (var streamWriter = new StreamWriter(filePath, true))
        {
            streamWriter.WriteLine(message);
            streamWriter.Close();
        }
    }
    public IDisposable BeginScope<TState>(TState state)
    {
        return null;
    }
    public bool IsEnabled(LogLevel logLevel)
    {
        return true;
    }

Yukarıda da görüldüğü üzre projede üretilen loglar server'da bulunan C sürücüsünde AspCoreFileLog.txt adındaki dosyaya yazılacak. FileLogger sınıfını oluşturduktan sonra bu sınıfı projemize inject etmemizi sağlayacak olan ILoggerProvider interface'ini implement edecek olan FileLogProvider sınıfını tanımlayalım.

public class FileLogProvider : ILoggerProvider
{
    public ILogger CreateLogger(string category)
    {
        return new FileLogger();
    }
    public void Dispose()
    {

    }
}

FileLogProvider sınıfı proje içerisinde tanımlanan logger'ın instance'ının create edilmesini sağlar. 

Son adım olarak yukarıda tanımladığımız FileLogProvider'ı Startup.cs sınıfında bulunan Configure metodunda loggerFactory'nin provider'larına eklememiz kalıyor. Bu işlemi de aşağıdaki gibi startup.cs içerisinde yapalım.

public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
{
    //provider'ı ekledik
    loggerFactory.AddProvider(new FileLogProvider());

    if (env.IsDevelopment())
    {
        app.UseDeveloperExceptionPage();
    }

    app.UseMvc();
}

 

Geliştirmemiz bitti artık yazdığımız kodları test edebiliriz. Bunun için ILogger interface'inin projede yer alan aşağıdaki controller'a constructor seviyesinde inject ettikten sonra end-point'lere sırasıyla browser üzerinden get işlemi yapalım.

[Route("api/[controller]")]
public class ValuesController : Controller
{
    private readonly ILogger<ValuesController> _logger;
    public ValuesController(ILogger<ValuesController> logger)
    {
        this._logger = logger;
    }

    // GET api/values
    [HttpGet]
    public IEnumerable<string> Get()
    {
        _logger.LogInformation("Hi from logger !");
        return new string[] { "value1", "value2" };
    }

    // GET api/values/5
    [HttpGet("{id}")]
    public string Get(int id)
    {
        throw new NullReferenceException("Null exp. from myApp !");
        return "value";
    }
}

Http-Get request'i yolladıktan sonra C:\\AspCoreFileLog.txt adresine gittiğimizde içerisinde hem framework'ün ürettiği hemde bizim controller metodunda yazdırdığımız log row'larını görebilirsiniz.

 

 

Yazının başında da bahsettiğimiz üzre Asp.Net Core'da logging moduler bir şekilde ayrı bir service olarak gelmekte ve fileLog dışında database, flat file yada diğer log target türlerini kullanarak logging'i genişletebilirsiniz. Bunun dışında NLog, Serilog yada .net core desteği olan third-party logging provider'ları da kullanabilirsiniz.

Asp.Net Core'a Giriş

.Net Core Microsoft tarafından open-source olarak geliştirilmiş  modüler bir framework'dür. Asp.Net Core ise klasik bildiğimiz Asp.Net kütüphanesinin open-source olarak microsoft tarafından release edilmiş halidir.

Asp.Net yaklaşık 15 yıl önce Microsoft tarafından geliştirilmiş olup günümüz web teknolojileri arasından oldukça popüler olan bir kütüphanedir. Microsoft open-source dünyanın önlenemez yükselişi ile birlikte daha fazla dayanamadı ve en base de bildiğimiz .Net çatısı altında olan bütün teknolojilerini yeniden yapılandırıp open-souce olarak bütün dünya ile paylaşacağını bizlere 3 yıl önce duyurmuştu. Akabinde sırayla .Net çatısı altındaki framework'ler git-hub üzerinde yayınlanmaya başlandı.

Ms'in web için geliştirdiği kütüphanelerin kronolojik sırasına bakacak olursak

  • 2002 - ASP.Net 
  • 2008 - ASP.Net MVC 
  • 2012 - ASP.Net Web API and SignalR

son olarak ise 2016 yilinda .Net Core 1.0 release oldu ve bunula birlikte Asp.Net Core hayatımıza girdi.

Asp.Net Core Asp.Net'in daha sade ve modern bir yüzü olarak karşımıza çıkıyor. Microsoft'un Zamarin'i satın alması sonrası sahip olduğu cross-platform deneyiminide işin içine katarak Asp.Net Core'u bir Cross Platform kütüphane olarak bizlere sundu. Framework'ü kullanarak IoT uygulamaları, back-end service uygulamaları ve web projeleri geliştirebiliriz.


.Net Standart 2.0

Ms ilk olarak .Net Core 1.0 versiyonunu release etti ancak bu sürüm biz .net developer'lar için biraz alışkın olduğumuzdan farklı bir mimariye sahipti ve geliştirme yaparkende bazı zorluklarıda bulunuyordu. Microsoft 1.0 dan sonra yayınladığı 2.0 versiyonu ile birlikte .Net Standart 2.0 adında bir yenilik daha getirdi. .Net standart microsoft için şu demekti ben bütün .net teknolojilerini, dillerini vs hepsini bir standart altında topluyorum ve bunun adınıda .Net standart 2.0 koyuyorum dedi. Bu standart ile birlikte bütün .net platformlarının base'i .Net Standart olmuş oldu ve CoreCLR adında yeni bir ortak iletişim dili geliştirildi.

Asp.Net Core'un getirdiği yenilikleri ve faydaları sıralayacak olursak

  • Cross platform
  • High performance
  • Flexible deployment
  • Open source
  • Support for built-in dependency injection
  • Light-weight and modular
  • Side by side support
  • Faster development


Mac ve Linux işletim sistemlerinde çalışır hale getirildi ve cross platfrom coverage'ını yükseltmiş oldu.


Geliştirme Yaparken

İlk olarak bilgisayarınızda Vs 2015 update 3 yada vs2017 .Net Core SDK ile birlikte yüklü olması gerekmekte.
Proje oluşturuken ise klasik herzaman yaptığımız gibi new aşağıdaki gibi new project diyerek geliştirmek istediğimiz proje türünü seçerek solution'ımızıo yaratabiliriz.


Bu yazıda Asp.Net Core'a küçük bir giriş yaptık. Diğer yazılarımızda framework'ü örnek uygulamalar ile incelemeye devam edeceğiz.