27 Ocak 2022 Perşembe

Dependency Injection ve Dependency Inversion - PYTHON

erhaba,

Bugünkü yazımda Dependency Injection ve Dependency Inversion konularını inceleyip python ile örnek kodlar yazmaya çalışacağım.

Birçok kaynakta karışık bir şekilde anlatılan bu yapıları bakalım herkesin anlayabileceği bir şekle sokabilecek miyiz...

Dependency Inversion konsepti yazılımda S.O.L.I.D prensiplerinde tanıtılmaktadır ve bu kelimenin son harfi olan D ile gösterilmektedir. Dependency Injection ise Dependency Inversion uygulanma tekniklerinden biri olarak tanımlanabilir. Amaç diğer sınıflara bağımlılığı en aza indirecek bir yapı kurmaktır.



Bir memeli sınıfımız olsun. Bu sınıf içinde başka bir hayvan sınıfını kullanıyorsak, burda bir bağımlıktan söz etmek mümkündür. Yani memeli sınıfı hayvan sınıfına bağımlıdır. Bu bağımlılığı azaltabilmek için öncelikle dependency injection uygulanması gerekir. Alttaki kodlarımızda kısaca şunu yapacağız. Hayvan sınıfını da kullanarak bir memeli oluşturacağız. Memeli sınıfından oluşturulan nesne ye metodu aracılığı ile komut verip yürüteceğiz ve durduracağız.

class hayvan():
def yuru(self):
print("Yuru...Yuruyor.")

def dur(self):
print("Dur!...Durdu.")

class memeli():
def __init__(self):
self.hayvan = hayvan()
self.durum = False

def komut_ver(self):
if self.durum:
self.hayvan.yuru()
self.durum = False
else:
self.hayvan.dur()
self.durum = True

kedi = memeli()
kedi.komut_ver()
kedi.komut_ver()
kedi.komut_ver()
kedi.komut_ver()
kedi.komut_ver()
Çıktı :

Dur!...Durdu.
Yuru...Yuruyor.
Dur!...Durdu.
Yuru...Yuruyor.
Dur!...Durdu.

Dependency Injection bağımlılıkların dışardan alınması şeklinde sağlanmaktadır. Şimdi dependency injection ile üstteki kodumuzu alttaki şekilde düzenleyelim.

 
class hayvan():
def yuru(self):
print("Yuru...Yuruyor.")

def dur(self):
print("Dur!...Durdu.")

class memeli():
def __init__(self, memeliHayvan: hayvan):
self.memeliHayvan = memeliHayvan
self.durum = False

def komut_ver(self):
if self.durum:
self.memeliHayvan.yuru()
self.durum = False
else:
self.memeliHayvan.dur()
self.durum = True

kedi = hayvan()
sonic = memeli(kedi)

sonic.komut_ver()
sonic.komut_ver()
sonic.komut_ver()
sonic.komut_ver()
sonic.komut_ver()
Çıktı :

Dur!...Durdu.
Yuru...Yuruyor.
Dur!...Durdu.
Yuru...Yuruyor.
Dur!...Durdu.

Kodun yeni halini incelersek hayvan sınıfından üretilen nesne memeli sınıfına dışarıdan verilmektedir. Yani memeli sınıfı içinde hayvan sınıfı kullanılarak bir nesne üretimi yapılmamaktadır. Bu bağımlılığı dependency injection ile kaldırmış olduk.

Peki işi biraz ileriye götürürsek, memeli sınıfına gönderilecek hayvanları iki ayaklı ve dört ayaklı olarak ikiye ayırıp bunlar için birer ara sınıf oluşturmak istersek bunu nasıl yöneteceğiz. Burada iki ekstra sınıftan bahsediyoruz ama onlarca sınıf olabilir. Peki iki ayaklı ve dört ayaklı şeklinde ayarlayacağımız iki sınıftan üretilen hayvanları memeli sınıfına gönderebilir miyiz ? Yukarıdaki örnekte hayvan sınıfından üretilen hayvan nesnelerini memeli sınıfına gönderecek şekilde ayarlamalarımızı yaptık. Peki iki ayaklı hayvan nesnesi ve dört ayaklı hayvan sınıf nesnelerini memeli sınıfına nasıl gönderebiliriz ? Bunu direkt olarak yapmamız mümkün değildir, yani bu nesneler memeli sınıfı tarafından algılanamayacaktır. Çünkü memeli sınıfı hayvan sınıfı nesnelerini algılamak üzere geliştirildi.

Bunu interface kullanımı yardımı ile çözeriz. iki ayaklı hayvan ve dört ayaklı hayvan sınıfları bu interface'den implement alırsa sorunumuz çözülecektir. Bu durumda hayvan sınıfımız bir interface olacak. Memeli sınıfı hayvan sınıfından nesneleri kabul edecek şekilde ayarlanacak. İki ayaklı hayvan ve dört ayaklı hayvan sınıfları bu interface'den implement alarak bunlardan üretilen nesneler memeli sınıfına gönderilebilecek.

Şimdi bu senaryoya göre dependency inversion uygulayalım.

Tekrar özetlersek. Hayvan isimli bir interface olacak. İki ayaklı hayvan ve Dört ayaklı hayvan isimli birer sınıf bu interfaceden implement alacak ve bu sınıflardan üretilecek nesneler memeli sınıfına gönderilerek memeli metodu olan komut_ver() çağırılacak.


from abc import ABC, abstractmethod

class hayvan(ABC):
@abstractmethod
def yuru(self):
pass

@abstractmethod
def dur(self):
pass

class iki_ayakli_hayvan(hayvan):
def yuru(self):
print("İki Ayaklı Yuru...Yuruyor.")

def dur(self):
print("İki Ayaklı Dur!...Durdu.")

class dort_ayakli_hayvan(hayvan):
def yuru(self):
print("Dort Ayaklı Yuru...Yuruyor.")

def dur(self):
print("Dort Ayaklı Dur!...Durdu.")

class memeli():
def __init__(self, memeliHayvan: hayvan):
self.memeliHayvan = memeliHayvan
self.durum = False

def komut_ver(self):
if self.durum:
self.memeliHayvan.yuru()
self.durum = False
else:
self.memeliHayvan.dur()
self.durum = True

kedi = dort_ayakli_hayvan()
sonic = memeli(kedi)

maymun = iki_ayakli_hayvan()
jimny = memeli(maymun)

jimny.komut_ver()
jimny.komut_ver()
jimny.komut_ver()
print()
sonic.komut_ver()
sonic.komut_ver()
sonic.komut_ver()
Çıktımız :

İki Ayaklı Dur!...Durdu.
İki Ayaklı Yuru...Yuruyor.
İki Ayaklı Dur!...Durdu.

Dort Ayaklı Dur!...Durdu.
Dort Ayaklı Yuru...Yuruyor.
Dort Ayaklı Dur!...Durdu.

Evet böylece ilk kodumuza önce dependency injection uygulayarak sınıf bağımlılığından kurtardık. Sonrasında ise daha detaylı bir sınıf yapısı kurarak sınıf çeşitliliğimizi arttırma amacı ile kodumuzu bir interface den implement ederek inşaa ettik. Bu sayede dependency inversion uygulamış olduk. Bunun bir avantajı da artık aynı interfaceden implement eden yeni farklı ara sınıfları kodumuza eklemek ve memeli sınıfına göndermek sureti ile yeni tür nesneler yaratabileceğiz. Örneğin kırkayak adında üçüncü bir sınıfı hızlıca kodumuza ekleyebiliriz. Hemde interface ve memeli sınıflarını değiştirmeden.

Bunu farklı bir örnek tasarımı ile açıklamaya çalışalım. Bir adet Tır sınıfımız olsun, bir adet Uçak sınıfımız olsun, bir adet Otobüs sınıfımız olsun. Bir kargo lojistik firması için yazılım geliştiriyor olalım. Bu 3 sınıfı bir adet Operasyon isimli interface sınıfından implement ederiz. Bu Operasyon sınıfının Taşı isimli bir metodu olacaktır. Dolayısı ile Uçak, Otobüs, Tır sınıflarının da Taşı isimli metodu olacaktır. Bu 3 sınıftan üretilen nesneleri ana sınıfımız olan Kargo sınıfına göndereceğiz.
Kısaca  Operasyon()  ->  ( Uçak() , Otobüs() , Tır() )  ->  Kargo() şeklinde bir yapı olacaktır.
Görebileceğiniz üzere böyle bir yapısı olan kargo firması ilerleyen yıllarda bir gemi alıp gemi kargosu işlerine girerse Gemi() sınıfını sisteme dahil etmek oldukça kolay olacaktır ve bu ekleme diğer sınıfları etkilemeyecektir.

Teşekkürler,
Cem Selmanoğulları 










23 Ocak 2022 Pazar

Python ve Singleton Design Pattern (Singleton Tasarım Örüntüsü)

Merhaba,

Bu yazımda Singleton Design Pattern konusundan bahsederek python diliyle yazılmış bir örneği paylaşmak istiyorum. 

Tasarım örüntülerinde belirli bir problem için belirli bir çözüm sunulmaktadır. Bu sayede tasarım iyileştirilir ve takımın aynı dili konuşması sağlanır. Tasarım örüntüleri belirli bir işi yapmak yada çözüme ulaşmak için en iyi yöntemi sunar. Çatısı belirli yazılım örüntüleri kullanılarak oluşturulan yazılımların ilerleyen süreçlerde büyümesi, bakımının yapılması ve devamlılığının sağlanması daha kolay olacaktır.

Her tasarım örüntüsünün bir ihtiyaçtan yada bir sorunu çözme amacından ortaya çıktığını söyleyebiliriz. Singleton da bunlardan biridir. Creational Design Pattern (Yaratımsal Tasarım Örüntüsü) grubuna dahildir.



Bu tasarım örüntüsü çalışma zamanında yanlızca 1 obje yaratılmasını garanti eder. İkinci bir obje yaratılamayacaktır ve sadece bu obje çağırılıp kullanılacaktır. Kısaca tüm uygulama için bu sınıftan yanlızca bir nesne olacaktır. Bu nesneye ihtiyaç olduğunda her yerde aynı tek örnek çağırılacaktır. Böylece bir instance'a kontrollü erişim sağlayabiliriz. Singleton'da bir obje sadece ona ihtiyaç duyduğumuzda yaratılır. 

Bir sınıftan bir nesne oluşturabilirsiniz ve bu nesneyi program içinde değişik yerlerde defalarca kullanmak isteyebilirsiniz. Örneğin bir veritabanı bağlantı nesnesini bir kere oluşturup her veritabanı işlemi gerektiğinde bu nesneyi kullanabilirsiniz. Eğer burada Singleton deseni ile geliştirme yaptıysanız aynı veritabanı bağlantı sınıfından ikinci bir nesne üretilemeyecek ve her seferinde istek yapıldığında ilk yaratılan nesne örneği gelecek ve kullanılacaktır. Ayrıca bir nesneyi global bir değişkende tutmak da sıkıntılıdır, çünkü kodun herhangi bir yerinde o değişkenin üzerine yazılarak tüm kodun çökme ihtimali vardır. Singleton nesneyi global bir değişkene atamadan global bir şekilde istediğimiz yerde çağırıp kullanabilmemize izin verir. Böylece global bir kullanım sunarken başka bir kodun nesne üzerine yazması da engellenmiş olur. Kod Singleton'un statik metoduna erişebiliyorsa bu metod her çağırıldığında aynı nesne örneğinin getirilmesi sağlanacaktır.

Burada önemli noktalardan birisi de şudur. Singleton ile global değişkenler üzerinde daha sıkı bir kontrol sahibi olmuş oluruz. Singleton sınıfının kendisi dışında hiçbir kod parçası nesne örneğini değiştiremez.

Biraz da kodlar üzerinden anlamaya çalışalım. Öncelikle bir sınıf oluşturup bu sınıf ile sadece bir adet nesne üretilmesini garanti edecek basit bir kod parçacığı yazmak istiyorum.


class Singleton:
__instance = None

def __init__(self):
""" Virtually private constructor. """
if Singleton.__instance != None:
raise Exception("This class is a singleton!")
else:
Singleton.__instance = self

singObj1 = Singleton()
print(singObj1)

Yukarıdaki kodda sınıf üzerinden bir nesne yaratıyoruz. Nesne yaratıldığında sınıf içindeki __instance değişkenini kontrol ederek daha önce bu sınıftan bir nesne yaratılıp yaratılmadığını kontrol ediyoruz. Eğer daha önce nesne yaratılmadıysa nesnemiz yaratılıyor ve sınıf içindeki __instance değişkenine nesnemiz atanıyor. Ekrana bastırdığımızda da alttaki şekilde hatasız bir şekilde nesnenin yaratıldığını görüyoruz.

<__main__.Singleton object at 0x0000024535C47C10>

Şimdi alttaki şekilde ikinci bir obje yaratmaya çalışalım.


class Singleton:
__instance = None

def __init__(self):
""" Virtually private constructor. """
if Singleton.__instance != None:
raise Exception("This class is a singleton!")
else:
Singleton.__instance = self

singObj1 = Singleton()
print(singObj1)
singObj2 = Singleton()
print(singObj2)

İlk nesnenin yaratılmasına kadar herşey aynı. Artık sınıf içindeki __instance değişkenine nesnemiz atanmış durumda. İkinci kes bu sınıftan nesne üretmeye çalıştığımızda ise yine __init__ içindeki kontrol yapılacaktır. Bu sefer __instance değeri None olmayacaktır. Bu sebeple "This class is a singleton!" şeklinde bir exception fırlatacaktır. Burda dikkat ederseniz nesneyi global bir değişkende tuttuk.

Exception: This class is a singleton!

Bu örneği temel mantığı anlamanız için yaptık. Şimdi biraz daha kapsamlı bir örnek paylaşmak istiyorum. Bu örnekte singleton sınıfından bir nesne üreteceğiz ve global bir değişkene bu nesneyi atamadan her istediğimizde sınıfın metodu ile çağıracağız. Böylece nesneyi global değişkende tutarak çağırmanın getireceği risklerden de kurtulmuş olacağız. Birçok yerde paylaşılan standart bir örneği olduğu gibi paylaşarak açıklamak istiyorum.


class SingletonMeta(type):
"""
The Singleton class can be implemented in different ways in Python. Some
possible methods include: base class, decorator, metaclass. We will use the
metaclass because it is best suited for this purpose.
"""

_instances = {}

def __call__(cls, *args, **kwargs):
"""
Possible changes to the value of the `__init__` argument do not affect
the returned instance.
"""
if cls not in cls._instances:
instance = super().__call__(*args, **kwargs)
cls._instances[cls] = instance
return cls._instances[cls]


class Singleton(metaclass=SingletonMeta):
def some_business_logic(self):
"""
Finally, any singleton should define some business logic, which can be
executed on its instance.
"""
# ...


if __name__ == "__main__":
# The client code.

s1 = Singleton()
s2 = Singleton()
print(s1)
print(s2)

if id(s1) == id(s2):
print("Singleton works, both variables contain the same instance.")
else:
print("Singleton failed, variables contain different instances.")

Bu kod örneğimizde sınıfımız içinde __call__ metodunun kullanıldığını göreceksiniz. Bu metod sınıfımızdan üretilecek nesne örneğinin istenildiği bir anda bir fonksiyon gibi çağırılarak getirilebilmesini sağlar.

Yani Singleton sınıfımızdan üretilecek nesne örneğini Singleton() ile defalarca çağırabiliriz ve her seferinde aynı nesne örneği gelecektir ve ikinci bir nesne oluşturulmayacaktır. Bu tamda Singleton Design Pattern'de istediğimiz şey.

Yine burada _instances isimli bir değişkenimiz var. Bu değişken sınıf ilk nesneyi ürettiğinde oluşturulan nesne örneğini tutacak ve her çağırıldığında aynı örneği verecektir. Kontrol __call__ metodu içinde yapılacak eğer daha önce nesne üretilmediyse nesne üretilecek ve ikinci kes nesne üretilmesine izin verilmeyecektir.

Koda bakarsanız s1 ve s2 de iki kere bu sınıf nesnesi çağırılmış. Peki her seferinde aynı nesne mi gelmiş ? Evet. Aşağıdaki çıktıya baktığınızda aynı nesne örneğinin geldiğini göreceksiniz. Singleton() çağrısını yüzlerce kez de yapsak artık hep aynı nesne örneği gelecektir.

<__main__.Singleton object at 0x000002B5D5F4FF70>

<__main__.Singleton object at 0x000002B5D5F4FF70>

Singleton works, both variables contain the same instance.


Teşekkürler,

Cem Selmanoğulları

22 Ocak 2022 Cumartesi

Grafana nedir ? Veri görselleştirme. Dashboard oluşturma.

Merhaba,

Bugün son yılların popüler opensource uygulamalarından biri olan ve Grafana Labs tarafından sunulan Grafana'dan bahsetmek istiyorum. Bu yazımda Grafana'yı tanıtmaya yönelik giriş seviyesi bilgiler vermeye çalışacağım. Daha sonraki yazılarımda ise daha derinlemesine inceleme ile ürün yönetimine dair konulara değinerek detaylı dashboardlar oluşturmayı planlıyorum.

"Dashboard anything. Observe everything."

Web tabanlı veri görselleştirme ve raporlama uygulaması olarak özetleyebileceğimiz bu güçlü uygulama pekçok büyük firma tarafından kullanılmaktadır. Şirketler altyapılarını izlemek ve operasyonel verimliliklerini arttırmak için Grafana'yı kullanmaktadır. Verilerin toplanması, yönetilmesi ve görüntülenmesini otomatikleştirdiği için izleme ve analizi oldukça kolaylaştırır. Bölüm ve takım yöneticileri, analistler, mühendisler karar verme mekanizmalarında Grafana'dan sıklıkla yararlanmaktadır. Anlık durum tespiti ve ileriye dönük planlamaların yapılması anlamında doğru verilere ulaşılıp doğru kararlar verilmesinde oldukça etkin bir rol oynamaktadır. Güvenlik analizi ekipleri tarafından da kullanılabilen Grafana kullanıcıların dijital ayak izlerinin takibi konusunda da fayda sağlamaktadır. Birçok veritabanı ile entegre olup veri çekebilen uygulama gerçekten gözalıcı grafikler, tablolar ve dashboardlar oluşturabilmektedir. Grafana ile verileriniz nerede olursa olsun sorgulama, ölçme, görselleştirme ve raporlama işlerinizi yapabilirsiniz. Operasyonel ölçümleriniz ile ilgili grafik ve raporlar oluşturabilirsiniz. İşin içine Telegraf ve InfluxDB araçlarını da kattığınızda Grafana sistemini oldukça güçlü ve yönetimi kolay bir izleme sistemine çevirmeniz de mümkün.


Grafana sistemi Linux, Windows ve MacOS üzerinde çalıştırılabilmektedir. Grafana ile fiziksel ve sanal sunucu ve ağ sistemleri ile ilgili çeşitli dashboardlar oluşturabilirsiniz, raporlamalar yapabilirsiniz. Sunucular ve ağınızı izleyebilirsiniz. Cloud üzerindeki birçok servisi takip edebilirsiniz. Çeşitli uygulamaları ve loglarını takip edebilirsiniz. Anlık durum yada geriye dönük verileri izleyebileceğiniz grafikler ile trendlere bakabilirsiniz. Zaman bazlı kıyaslamalar ve trendleri izleyebileceğiniz grafikler yaratabilirsiniz. Sistemlerin performans verilerini raporlayabilirsiniz. Kapasite planlamalarınızı takip edip geriye dönük grafikler ile raporlamalar yapabilir kapasite ve kullanım trendlerini izleyebilirsiniz. Envanter bilgilerinizi takip edebilirsiniz.  

Grafana ile dakikalar içinde profesyonel dashboardlar hazırlamanız mümkün. Tabi bunun için biraz SQL bilginizin de olması gerekiyor. 

Çekilecek veriler için SQL sorguları yazmanız gerekiyor. Ama bu gözünüzü korkutmasın, çok temel SQL sorguları ile harika dashboardlar ortaya çıkarabiliyorsunuz.



Alttaki dashboard bir sunucu ile ilgili çeşitli metrikleri görselleştirmektedir.


Bir dashboard alttaki şekilde bağımsız panellerden oluşmaktadır.



Her bir panel ayrı bir SQL sorgusu sonucu oluşan verilerden görselleştirilmektedir.

Yukarıdaki MEM panelinin detayına baktığımızda alttaki şekilde iki SQL cümlesi ile oluşturulduğunu göreceksiniz.


SQL cümlesini manuel yazmak istemeyenler için ise basitleştirilmiş bir editör de sunulmaktadır.


Alttaki örnekte SQL Serverdan çekilecek veriler için yazılmış bir SQL sorgusu görmektesiniz.


Verileri panelde Time Series, yani zamana bağlı değişen grafik şeklinde gösterebildiğimiz gibi tablo olarak da çekilen verilerin ham hali ile de gösterebiliriz. 
Altta grafikle gösterilen verilerin tablo ile gösterimini görmektesiniz.


Yine altta tablo formatında bir panel görmekteyiz.


Grafana'nın sağladığı çeşitli visualization seçenekleri ile yapacağınız görselleştirmeler hayallerinize kalmış. 
Birkaç farklı visualization örneğini altta paylaşmak isterim.







Visualization seçeneklerini alttaki şekilde listeleyebiliriz.

Verileri CSV dosyası olarak indirmeniz de mümkündür.


Ayrıca herhangi bir paneli "Share" özelliği sayesinde paylaşabilirsiniz. "Share Panel" çeşitli paylaşım opsiyonları sunmaktadır.


Direkt olarak panel link url sini paylaşmanın yanısıra panelin imaj olarak oluşturulmuş resim dosyasına da ulaşmak mümkündür. 
Bunun yanısıra "Snapshot" paylaşımı ile panelin o anki hali public olarak bir link ile paylaşılacaktır. 
Bu link adresini bilen herkes bu panelin o anki görüntüsüne erişebilecektir. 

Embed özelliği sayesinde ise panel bir iframe olarak Grafana sistemi dışında başka bir web sitesinin 

kodları içine gömülebilmekte ve diğer sitelerde görüntülenebilmektedir. 

Bu işlem bildiğimiz HTML için iframe gömme işlemi ile aynıdır.


Grafana sistemi anlık ve geriye dönük olarak verileri, trend grafiklerini ve tabloları gösterebilmektedir. 
Ayrıca belli bir zaman aralığı içinde panel ve dashboardlar özelleştirilebilmektedir.


Ayrıca "Cycle View Mode" özelliği ile dashboardlar bir ekrana yansıtılarak belli periyodlarda döngüsel olarak gösterilebilmektedir.

Dashboardlar üzerinde gösterilen veriler detaylı olarak filtrelenebilmektedir. 

Oluşturulacak filtre değişkenleri birbirleri ile ilişkilendirilerek anlık olarak dashboardlar üzerindeki verileri filtrelemek mümkündür.


Filtreleme işlemleri için Dashboard ayarları içinde Variables kısmında değişken tanımlamaları yapılabilmektedir. 
Her bir değişken diğer değişken ile ilişkilendirilebilirken kendine ait bir SQL sorgusu ile eşleşmektedir.


500 tane sunucunuz ve her sunucu üzerinde 3 adet network interface iniz olduğu bir senaryoda sadece operasyon bölümüne ait sunucuların dashboard üzerinde gösterilmesini sağlayabilirsiniz. Yada sadece belli sunucuların sadece eth1 network interface kullanımlarının dashboard üzerinde gösterimi sağlanabilir.

Grafana sisteminde alarm oluşturmak da mümkündür. Belli kriterlere göre alarmlar oluşturulup kriterler gerçekleştiğinde yada belli eşikler geçildiğinde sistemin alarm üreterek mesaj göndermesi sağlanmaktadır.


Tablo ve grafik verilerinde yine treshold belirlenerek alarm durumlarının görsele yansıtılması da mümkündür.



Grafana sistemi kullanıcı ve kullanıcı grupları yönetimi ve yetkilendirilmesi konusunda da oldukça yeterli özellikler sunmaktadır. Ldap entegrasyonu yapılabilmektedir. Dashboardları oluşturacağınız kullanıcı ve takımlara göre yetkilendirerek kimlerin göreceği yada düzenleyebileceği konularında özelleştirebilirsiniz. Ayrıca dashboarları bir klasör yapsında gruplayarak yetkilendirmeleri dashboard grupları üzerinde de uygulayabilirsiniz. Ayrıca organizasyon bazlı ana ayrımlar yapmak da mümkündür. 

Grafana'nın en güzel özelliklerinden birisi ise grafana.com üzerinden daha önce hazırlanmış dashboardları import edebiliyor olmanızdır. Yani herhangi bir geliştirme yapmadan ve SQL sorgusu yazmadan size uygun hazır dashboardları ücretsiz olarak saniyeler içinde devreye alabilirsiniz.


Grafana.com üzerinden ID sini alacağınız dashboardı hemen import edip kullanmaya başlayabilirsiniz.

Örnek vermek gerekirse yüzlerce linux makine ile ilgili onlarca bilginin görselleştirildiği bir dashboardı hızlıca sisteminizde devreye alabilirsiniz. Dashboard ve panel dizaynı ile uğraşmanıza gerek olmadan.

Grafana sistemi dışarıdan web sayfalarının da dashboard panel olarak sisteme eklenmesine izin vermektedir. Buda Grafana sistemi daha da genişletebilmenize imkan vermektedir. Bir projede müşterimiz bazı scriptleri çalıştırarak çıktıları olan grafikleri Grafana üzerinde bir dashboard olarak görüntülemek istediğini belirtmişti. Normal şartlarda Grafana'da bu tarz bir tetikleyerek grafik oluşturma yapısı yok. Fakat dışarıda oluşturduğumuz bir web sayfası formatını Grafana formatına yakın bir formatta hazırlayarak sisteme entegre ederek müşterinin isteğini gerçekleştirme şansımız olmuştu.

Sıkça sorulan sorulardan biri ise Grafana üzerindeki grafik ve tablo panelleri kullanarak sıfırdan yeni bir web sitesi tasarımı yapabilir miyiz? Kendi web şablon tasarımlarını kullanmak isteyen bazı firmalardan bu şekilde istekler gelebiliyor. Teknik olarak yapılması mümkün fakat Grafana'nın kullanıcı yetkilendirme sistemini devre dışı bırakmış oluyorsunuz. Yeni oluşturacağınız web sitesinde kendi kullanıcı yetkilendirmelerinizi yaptıktan sonra neden olmasın. Paneller iframe olarak dışarıya aktarılabiliyor. Bu şekilde yeni oluşturacağınız web sitesinin içine hertürlü gömmeniz mümkün. Tabi burada Grafana tarafında bir güvenlik açığı olur mu sorusu da akla gelmektedir. Çünkü panelleri dışarıya açabilmek için anonymous kullanıcı otantikasyonunu açmanız anlamına gelmektedir. Buda Grafana'yı herkese açtığınız anlamına gelmektedir. Bunu aşmanın yolu ise Grafana sunucusu ile yeni web sitesini oluşturacağınız sunucu arasında point to point bir iletişim kurmak ve Grafana'ın web portuna sadece bu web sunucusunun erişebilmesini sağlamak. Böylece kullanıcılar yeni web sitesine erişirken Grafana sunucusuna erişemeyecek fakat Grafana'daki panelleri yeni web sunucusu görüntüleyerek kullanıcılara iletebilecektir. Bu şekilde Grafana'dan tamamen farklı bir web uygulaması hazırlanabilir ve sistemi kullananlar arka planda Grafana'nın olduğunun farkında bile olmayacaktır.

Grafana backend bir HTTP API hizmeti de sunmaktadır. Böylece farklı araçlar ile entegrasyon yada otomasyon işleri bu API aracılığı ile kolaylıkla yapılabilmektedir. Dashboard oluşturma, kaydetme, kullanıcı yaratma, takım yaratma ve yönetme, data source update, alarmların alınması, playlist oluşturulması, silinmesi, snapshot alınması ve silinmesi gibi işlemleri bu API aracılığı ile yapabilmekteyiz.

Grafana sistemi çeşitli pluginlerin kullanımı ile daha da yetenekli hale gelmektedir. CloudWatch, Elasticsearch, Google Cloud, Graphite, Jaeger, Microsoft SQL Server, MySQL, OpenTSDB, Prometheus, Tempo, Zipkin gibi pekçok datasource kullanımını mümkün kılmaktadır. Bunlar dışında alttaki data sourcelar konusunda pluginler ile desteğe sahiptir.





Grafana uygulamasını kendi sunucularınıza kurabilir yada Grafana Cloud hizmetinden faydalanabilirsiniz.

AWS tarafında Amazon'un sunduğu Amazon Managed Grafana servisi de son günlerin popüler servislerinden biri haline gelmiş durumda. AWS tarafından 2 tür lisans sağlanmakta. Editör ve Görüntüleyici lisansları. AWS fiyat listelerine baktığımızda 20 Editör ve 30 görüntüleyici lisansı için aylık olarak alttaki şekilde bir hesap çıkarıldığını görüyoruz.

Monthly Charges = 20 * $9.00 (Editor license) + 30 * $5.00 (Viewer license) = $330.00



Alttaki görsellerde AWS tarafındaki Grafana ekranlarından örnekleri görebilirsiniz.



Grafana kullanan bazı firmalara Siemens, Salesforce, SNYK, Dell, Tripadvisor, TomTom, JPMorgan, Dapper, Citi, Roblox, Unity, Redis, Wix, Booking.com, DigitalOcean, Stackoverflow, Ebay, Tinder, Verizon, Bloomberg, PayPal kuruluşlarını örnek verebiliriz.


Grafana docker imajını indirmek için TIKLAYIN.


Grafana'yı hemen denemek için Demo sayfasına gidebilirsiniz.

https://play.grafana.org/

 



Teşekkürler,

Cem Selmanoğulları





Python ile InfluxDB operasyon scripti

Merhaba,

Bugün InfluxDB ile ilgili çeşitli işlemleri yapabileceğiniz bir python script paylaşmak istiyorum.

Alttaki script ile InfluxDB üzerinde veritabanı yaratabilir, measurement yaratabilir, veri ekleyebilir, veritabanları ve measurementları listeletebilir, var olan bir measurement ı başka bir measurementa taşıyabilirsiniz. Henüz temel birtakım işlemleri yapan scriptimizi önümüzdeki süreçte daha da geliştirip InfluxDB ile alakalı birçok işlemi yapan bir araç haline getirmeyi planlamaktayım.

   


from influxdb import DataFrameClient, InfluxDBClient
from pandas import DataFrame
import pandas as pd
import numpy as np


class InfluxMain:

def __init__(self, host, port, user, password, dbname):
self.host, self.port = host, port
self.user, self.password = user, password
self.dbname = dbname
self.client = DataFrameClient(host, port, user, password, dbname)
self.__create_database__(dbname) # Creates if db does not exist

def __create_database__(self, db):
try:
print("Creating DB: " + db)
self.client.create_database(db)
except Exception as e:
print(e)

def insert_data(self, data, measurement, tag_columns):
self.__write_to_database__(data, measurement, tag_columns)

def drop_measurement(self, measurement):
print("Dropping measurement: " + measurement)
self.client.drop_measurement(measurement)

def __write_to_database__(self, data, measurement, tag_columns, protocol="line"):
try:
print("Create Measurement: " + measurement)
self.client.write_points(data, measurement, tag_columns=tag_columns, protocol=protocol, batch_size=10000)
print("Done!")
except Exception as e:
traceback.print_exc()


class InfluxAnalyser:

def __init__(self, host, port, user, password, dbname):
self.host, self.port = host, port
self.user, self.password = user, password
self.dbname = dbname
self.influxdb_client = InfluxDBClient(host, port, user, password, dbname)

def close_connection(self):
self.influxdb_client.close()

def get_databases(self, print_to_screen):
try:
df_databases = DataFrame(self.influxdb_client.query("SHOW DATABASES").get_points())
if print_to_screen == True:
print("\n| INFLUX DATABASES |\n")
for i in range(len(df_databases)): print("DB-" + str(i + 1), "> ", df_databases['name'].loc[i])
return df_databases
except Exception as e:
print(e)

def show_measurements(self):
try:
df_databases = self.get_databases(False)
for i in range(len(df_databases)):
db_name = df_databases['name'].loc[i]
print("\nDATABASE : " + db_name + "\n")
df_measurements = DataFrame(self.influxdb_client.query("show measurements on " + db_name).get_points())
print("Measurements >")
print(df_measurements)
except Exception as e:
print(e)

def migrate_measurement(self, source, target, influx, tag_columns, influx_index):
select = "select * from " + source
df = DataFrame(self.influxdb_client.query(select).get_points())
df['Index_Time'] = pd.to_datetime(df[influx_index])
df.set_index('Index_Time', inplace=True)
influx.insert_data(df, target, tag_columns)


if __name__ == "__main__":
host, port = "localhost", 8086
user, password = "", ""
database = "TestDB"
measurement = "TestMeasurement"

influx = InfluxMain(host, port, user, password, database) # Create DB if not exists, initiate connection object
# influx.drop_measurement(measurement)

# Test data : Dataframe with Python Dataframe
df = pd.DataFrame(columns=['Name', 'City', 'Market_Type', 'Par_Val', 'Core_Val'])
dfrow = {'Name': 'Mert', 'City': 'ist', 'Market_Type': 'marmar', 'Par_Val': '23443234', 'Core_Val': '7567567',
'Start_Time': '2021-01-01 00:10:33'}
df = df.append(dfrow, ignore_index=True)
df['Index_Time'] = pd.to_datetime(df['Start_Time'])
df.set_index('Index_Time', inplace=True) # Setting index time for influxdb measurement

tag_columns = ['Name', 'City', 'Market_Type'] # Define tag column names. Fields come with data.
influx.insert_data(df, measurement, tag_columns) # Create measurement if not exists, and add data

analyser = InfluxAnalyser(host, port, user, password, database)
analyser.get_databases(True)
analyser.show_measurements()
source, target, dbname = "TestMeasurement", "NewMeasurement", "TestDB"
influx_index = "Start_Time" # Influx DB table index time
analyser.migrate_measurement(source, target, influx, tag_columns, influx_index) # Read from source, write to target
analyser.close_connection()

20 Ocak 2022 Perşembe

Python metod ve fonksiyonları - Python Methods and Functions

Merhaba,

Sıklıkla karıştırılabilen bir konuya açıklık getirmek isterim. Python yazılım dilinde fonksiyon ve metod konseptleri farklı şeyleri ifade etmektedir. 

Metodlar sınıfların bir parçasıdır ve sınıf ile oluşturulan objenin durumunu değiştirebilir. Fonksiyonlar ise sınıflardan bağımsız tek başına çalışan ve çağrılabilen yapılardır. Bir objenin parçası değildirler.

Örnek ile açıklamak gerekirse.

class Toplam:
    def __init__(self, a, b):
        self.a = a
        self.b = b
    # Metod Ornegi
    def islem(self):
        return self.a + self.b

#Fonksiyon Ornegi
def topla(a, b):
    return a + b

Toplam sınıfı içinde tanımlı islem() bir metoddur. Sınıf dışında tanımlı topla() ise bir fonksiyondur.







Teşekkürler,

Cem Selmanoğulları

17 Ocak 2022 Pazartesi

Python yazılım dilinde Dekoratör (Decorator) kullanımı

Merhaba,

Bugün Python yazılım dilinde Decorator kullanımına bir örnek paylaşmak istiyorum. Kısaca diğer fonksiyonları yada sınıfları geliştirip modifiye etmeye yarayan python objeleri şeklinde tanımlayabiliriz. 

Örnek vermek gerekirse, bir fonksiyonumuz olsun. Bu fonksiyon bir string döndürüyor olsun. Bu döndürülen stringin büyük harfle başlamasını istiyoruz. Bunu direkt fonksiyon içinde yapmamız mümkün, ama biz bunu her yazdığımız fonksiyon içinde tekrar tekrar yapacak mıyız ?  İşte bunun için her ihtiyacımız olduğunda decorator fonksiyonunu çağırarak bu işi yapmasını sağlayabiliriz. Alttaki örnekte capitalizer isimli bir decorator fonksiyonumuz var. birde string dönen fonksiyonumuz var. @capitilizer referansını stringer fonksiyonunun başına yazdığımızda artık capitilizer fonksiyonu bir nevi stringer fonksiyonunu sarmalayarak geliştirip dönen değeri büyük harfle başlayacak şekilde geliştirecektir.

def capitalizer(func):
def wrapper(string):
innerfunc = func(string)
capitalized = innerfunc.capitalize()
return capitalized
return wrapper

@capitalizer
def stringer(string):
return string

print(stringer("tHiS is a DeCORator EXAmple"))

Çıktı :  This is a decorator example


Bir başka örneği ise Python Django Framework üzerinden verebiliriz. Django otantikasyon sistemi view fonksiyonları ile birlikte kullanabileceğimiz bir @login_required dekoratörü sunmaktadır. Bu dekoratörün refere edildiği view eğer sisteme login olunduysa gösterilecek olunmadıysa gösterilmeyecektir.

Alttaki örnekte @login_required dekoratörünün nasıl uygulandığını görebilirsiniz. Login olmayanlara my_view gösterilmeyecektir.


from django.contrib.auth.decorators import login_required

@login_required
def my_view(request):
    ...






Teşekkürler,

Cem Selmanoğulları