Logstash ile Veri Analizi

Share Button

Logstash farklı kanallardan veri toplayıp, konfigürasyon seviyesinde filtrelerle belirli kuralalra göre parçalamanızı sağlayan ve farklı tipterde kanallara dağıtabilen gerçek zamanlı ve açık kaynaklı bir veri toplama moturudur.

Logstash, ayrıştırma işlemini kendi komut seti içerisinde klasik regex eşleştirmeleri ile yapabildiği gibi LOGLEVEL, TIMESTAMP_ISO8601, DATETIME.. gibi ön tanımlı çok sayıda veri tipleriyle de kolayca yapabilmenizi sağlar.

Logstash, TCP/UDP soketleri ve log dosyaları gibi basit kaynaklar dışında çeşitli streaming protokollerindan tutun, kafka, log4j, redis araçlardan github, heroku, twitter ve irc gibi servislere kadar pek çok kaynaktan beslenebilme yeteneğine sahiptir. Ayrıca tüm bu kaynaklardan aldığınız verileri belirlediğiniz kurallar çerçevesinde işledikten sonra dilerseniz email olarak gönderebilir, ya da elastic search üzerine yazarak Kibana gibi veri görselleştirme araçlarıyla analiz edebilrsiniz.

Logstash aynı anda birden fazla kaynaktan beslenip yine birden fazla kaynağa veri dağıtabilir. Desteklenen veri kaynakları ile ilgili olarak şuraya, aktarım kaynakları ile ilgili olarak buraya bakabilirsiniz.

Logstash, tüm sistem/servis loglarınızı toplamaktan, özel olarak yazacağınız filtrelerle ödeme sisteminizin loglarını işleyerek istatistiksel veriler çıkarmanıza olanak sağlayacak çok geniş bir kullanım alanına sahiptir.

NGINX Access Logları Logstash ile Nasıl İşlenir ?

Aşağıdaki adresten logstash uygulamasının güncel sürümünü indirelim.
https://www.elastic.co/downloads/logstash

Ben şu anki güncel sürüm olan 2.2.2 sürümünü indiriyorum.
https://download.elastic.co/logstash/logstash/logstash-2.2.2.tar.gz

$ wget https://download.elastic.co/logstash/logstash/logstash-2.2.2.tar.gz

Sıkıştırılmış logstash paketini açalım.

$ tar -zxvf logstash-2.2.2.tar.gz

Konfigürasyon dosya(ları)mızı barındıracağımız conf.d dizinini oluşturalım.

$ cd logstash-2.2.2
$ mkdir conf.d

Logstash konfigürasyon dosyası, json benzeri bir yapıya sahiptir. Konfigürasyon dosyası, veri kaynaklarının tanımlandığı input{}, işleme tanımlamalarının yapıldığı filter{} ve işlenen verinin aktarılacağı kaynaklarla ilgili tanımlamaların yapıldığı output{} olmak üzere üç bölümden oluşur.

input {
	# Bu bölümde logstash i besleyecek veri kaynakları 
	# ve veri kaynaklarının opsiyonları ile ilgili 
	# ayarlar yeralır.
}

filter {
	# Bu bölümde gelen verinin nasıl parse edileceği,
	# verinin hangi bölümünün hangi alanlarda tutulacağı
	# gibi tanımlamalar yeralır.
}

output {
	# Burada işlenen verinin hangi kaynaklara aktarılacağı 
	# ve kaynakların ayarları ile ilgili tanımlamalar yeralır.
}

Okuyacağımız veri, nginx access loglarında yeraldığına göre file eklentisini kullanarak dosyayı okumak için gerekli tanımlamaları gerçekleştirelim.

input {
	file {
		path => "/var/log/nginx/*-access*"
		exclude => "*.gz"
		start_position => "beginning"
	}
}

Yukarıdaki konfigürasyonda;

path => “/var/log/nginx/*” ifadesi, /var/log/nginx dizinindeki tüm dosyaların okunması gerektiğini logstash e söyler. *-access* kullanılmasının nedeni, logstash in güncel ve rotate edilmiş tüm access loglarını değerlendirmesini sağlamaktır. Ancak bu dizinde arşivlenen log dosyaları da barındırıldığından exclude komutunu kullanarak *.gz uzantılı arşiv dosyalarını hariç tutulmasını sağlıyoruz.

Logstash varsayılan olarak path bölümünde verilen dosya yada dosyaların sonuna eklenen satırları değerlendirmektedir. Ancak log stash in rate edilmiş logları da değerlendirebilmesi için start_position parametresine beginning değerini vererek, dosyaları başından itibaren değerlendirmesi gerektiğini logstash e söylüyoruz.

Artık tüm nginx access loglarını okuyabilir durumda olduğumuza göre, aşağıdaki örnek log çıktısının logstash tarafından incelenmesini sağlamaya hazırız.

157.55.39.132 - - [20/Mar/2016:06:49:05 -0400] "GET /tag/software-engineering/page/2/ HTTP/1.1" 200 9329 "-" "Mozilla/5.0 (compatible; bingbot/2.0; +http://www.bing.com/bingbot.htm)"
157.55.39.132 - - [20/Mar/2016:06:49:06 -0400] "GET /tag/yii-framework/ HTTP/1.1" 200 14823 "-" "Mozilla/5.0 (compatible; bingbot/2.0; +http://www.bing.com/bingbot.htm)"
157.55.39.132 - - [20/Mar/2016:06:49:07 -0400] "GET /goygoy-yonelimli-programlama-ggop/ HTTP/1.1" 200 14980 "-" "Mozilla/5.0 (compatible; bingbot/2.0; +http://www.bing.com/bingbot.htm)"
157.55.39.132 - - [20/Mar/2016:06:49:07 -0400] "GET /django-uygulamalarinin-apache-uzerinde-sanal-ortam-virtualenv-ile-birlikte-calistirilmasi/ HTTP/1.1" 200 10964 "-" "Mozilla/5.0 (compatible; bingbot/2.0; +http://www.bing.com/bingbot.htm)"
157.55.39.132 - - [20/Mar/2016:06:49:08 -0400] "GET /dekorator-tasarim-deseni/ HTTP/1.1" 200 13180 "-" "Mozilla/5.0 (compatible; bingbot/2.0; +http://www.bing.com/bingbot.htm)"
157.55.39.132 - - [20/Mar/2016:06:49:08 -0400] "GET /cv/ HTTP/1.1" 200 9723 "-" "Mozilla/5.0 (compatible; bingbot/2.0; +http://www.bing.com/bingbot.htm)"
157.55.39.132 - - [20/Mar/2016:06:49:09 -0400] "GET /tasarim-candir/ HTTP/1.1" 200 12253 "-" "Mozilla/5.0 (compatible; bingbot/2.0; +http://www.bing.com/bingbot.htm)"
157.55.39.132 - - [20/Mar/2016:06:49:10 -0400] "GET /cem-karaca-5-nisan-1945-8-subat-2004/ HTTP/1.1" 200 9825 "-" "Mozilla/5.0 (compatible; bingbot/2.0; +http://www.bing.com/bingbot.htm)"
157.55.39.132 - - [20/Mar/2016:06:49:10 -0400] "GET /page/2/?s=git+di HTTP/1.1" 200 33628 "-" "Mozilla/5.0 (compatible; bingbot/2.0; +http://www.bing.com/bingbot.htm)"

Logdaki veriyi parse edecek filtre konfigürasyonunu oluşturalım.

filter {
	grok {
		match => {"message" => "%{COMBINEDAPACHELOG}+%{GREEDYDATA:extra_fields}"}
	}

	mutate {
		convert => ["response", "integer"]
		convert => ["bytes", "integer"]
		convert => ["responsetime", "float"]
	}

	geoip {
		source => "clientip"
		target => "geoip"
	}

	date {
		match => ["timestamp", "dd/MMM/YYYY:HH:mm:ss Z"]
	}
}

Yukarıda gördüğünüz filtre konfigürasyonunda grok, mutate, geoip ve date eklentilerini kullandık. Şimdi dilerseniz sırayla bu eklentilerin ne işe yaradıklarını ve konfigürasyondaki işlevlerini görelim.

grok eklentisi, belirli bir yapıya sahip olmayan girdiyi belirtilen patterne uygun olarak parse etmeye yarar. Parse edilen veriyi COMBINEDAPACHELOG gibi ön tanımlı değişken gruplarıyla parse edebileceğiniz gibi GREEDYDATA tipindeki belirli bir veriyi kendi istediğiniz bir değişkene atayabilirsiniz.
Yukarıdaki örnekde grok eklentisi, match parametresinden gönderilen paterne uygun verileri parse ederek ön tanımlı ve/veya paternde tanımlanan extra_fields gibi değişkenlere atamaktadır. COMBINEDAPACHELOG veri tipi, log verisinde yeralan istemci ip adresi, istek yapılan zaman, istek yapılan uç nokta, transfer edilen veri miktarı vb. verileri clientip, timestamp, request, bytes gibi değişkenlere aktarılmasını sağlar. GREEDYDATA tipi ise genel amaçlı bir veri tipidir. Yapısal olmayan ve COMBINEDAPACHELOG tarafından parse edilmeyen diğer veriler GREEDYDATA tipindeki extra_fields değişkenine aktarılır.

Desteklenen diğer grok paternleri için şu github reposunu inceleyebilirsiniz.

mutate eklentisi, işlenen veri sonucunda oluşan alanlarda değişiklik yapmaya yarayan filtre eklentisidir. Yukarıdaki örnekte mutate eklentisi, convert komutuyla COMBINEDAPACHELOG tarafından parse edilip response, bytes ve responsetime gibi alanlara yazılan sayısal verilerin, tam sayı tipine çevirerek (Logstash, yapısal olmayan log girdisindeki veriyi varsayılan olarak string tipinde parse eder.) gerektiğinde sayısal operasyonlara tabi tutulabilir durumda olmalarını sağlar.

geoip eklentisinin bu örnekteki en eğlenceli eklenti olduğunu söyleyebilirim. Kendisi, access logda parse edilen istemci IP adresinin, coğrafi konum bilgisini elde eder.

date eklentisi ise belirli bir alandaki zaman bilgisini parse ederek belirli bir alana yazmak veya logstash in dahili zaman damgası olarak kullanabilmek için kullanılır. Burada, logdan parse edilen tarih/saat bilgisi, kendisine uygun zaman formatı ile eşleştirilerek logstash UTC formatındaki dahili zaman damgası alanının üzerine yazılır. Date filtresi, target komutu ile özellikle farklı bir hedef alan belirtilmediği sürece eşleşen zaman bilgisini varsayılan olarak logstash in dahili zaman damgası alanı olan @timestamp alanına yazar.

Artık logumuzu parse edebilir durumda olduğumuza göre sıra geldi parse edilen veriyi aktaracağımız kaynağı tanımlamaya. Örnek çıktısını konsolda görebilmek adına stdout eklentisini kullanacağız. Ancak başta bahsettiğim gibi şuradan kullanabileceğiniz tüm eklentilerle ilgili detaylı bilgi alabilirsiniz.

İşlenen veri çıktısını konsola basmak için aşağıdaki konfigürasyonu oluşturuyoruz.

output {
	stdout {
		codec => "rubydebug"
	}
}

Burada stdout eklentisi, işlenen verinin konsola basılmasını sağlar. codec olarak belirtilen rubydebug ise awsome_print isimli ruby kütüphanesini kullanarak çıktının okunabilirliğini arttırır. Diğer codec seçenekleri için şu sayfayı inceleyebilirsiniz.

Oluşturduğumuz konfigürasyonu conf.d dizinine kaydettikten sonra artık uygulamayı çalıştırmaya hazırırz. Örnek konfigürasyonumuzun ismi

nginx_access_log.conf

olsun.

$ ./bin/logstash -f ./conf.d/nginx_access_log.conf

Uygulamayı çalıştırdığınızda, logstash size şöyle bir çıktı üretecektir.

...

{
        "message" => "157.55.39.132 - - [20/Mar/2016:06:49:10 -0400] \"GET /cem-karaca-5-nisan-1945-8-subat-2004/ HTTP/1.1\" 200 9825 \"-\" \"Mozilla/5.0 (compatible; bingbot/2.0; +http://www.bing.com/bingbot.htm)\"",
       "@version" => "1",
     "@timestamp" => "2016-03-20T10:49:10.000Z",
           "host" => "king",
       "clientip" => "157.55.39.132",
          "ident" => "-",
           "auth" => "-",
      "timestamp" => "20/Mar/2016:06:49:10 -0400",
           "verb" => "GET",
        "request" => "/cem-karaca-5-nisan-1945-8-subat-2004/",
    "httpversion" => "1.1",
       "response" => 200,
          "bytes" => 9825,
       "referrer" => "\"-\"",
          "agent" => "\"Mozilla/5.0 (compatible; bingbot/2.0; +http://www.bing.com/bingbot.htm)\"",
          "geoip" => {
                    "ip" => "157.55.39.132",
         "country_code2" => "US",
         "country_code3" => "USA",
          "country_name" => "United States",
        "continent_code" => "NA",
              "latitude" => 38.0,
             "longitude" => -97.0,
              "dma_code" => 0,
             "area_code" => 0,
              "location" => [
            [0] -97.0,
            [1] 38.0
        ]
    }
}


...
Share Button

About İbrahim Gündüz

1983 yılında İstanbul’da doğdu. İlkokul yıllarında cobol ve basic le olan tanışması, yazılıma olan ilgisini arttırdı 2005 yılında. Uludağ Üniversitesi Teknik Bilimler Meslek Yüksek Okulu Elektronik bölümünden mezun olan Gündüz, çeşitli alanlarda faaliyet gösteren kurumlarda yazılım geliştirici olarak görev almıştır. Mesleki ilgi alanları, ölçeklenebilir sistemler, uygulama entegrasyonları ve ödeme sistemleridir. Halen Markafoni back end geliştirici olarak çalışmaktadır.

Bir Cevap Yazın

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