Python için Logging

Umut Boz
5 min readJun 17, 2020

Yazılımcı’nın alet çantasında 🧰 bulunması gereken bir araç olan logging’den bahsedeceğim.

Peki Log nedir ki?

Log için kısaca kayıt diyebiliriz. Yazmış olduğumuz kod parçası, bir script olabilir ya da kodlar bir amaca hizmet eden operasyonlar bütünü olabilir. Yazmış olduğumuz kodlar, kullanıcı ile bir şekilde iletişime geçiyorsa, ki bu son kullanıcı ya da bir çılgın developer’da olabilir. Belkide kendiniz 🧑‍💻.

Oluşturduğumuz çıktılar herhangi bir şekilde dışarıdan parametre alabilir. Bu parametre (argüman) sonucunda operasyonunuz yürütülecektir. Çok doğaldır, bütünüyle gerçekleşebilecek ihtimalleri ön göremeyebiliriz, ki ön gördüğümüz ihtimal dahilindeki süreçlerde aksaklıklar da yaşanabilir. Bunun içindir ki, operasyonun amacına uygun olarak süreçleri kayıt altına almak ya da operasyonda var olacak problemleri gözlemlemek isteriz.

Nasıl Log’lama yapabilirim?

Örneklemi Python proglama dili üzerinde devam edeceğiz. En basitinden bir Logger nesnesi oluştururuz.

class Logger:
"""This class now shares all its attributes among its various instances"""

# This essentially makes the singleton objects an object-oriented global variable
def __init__(self):
pass

def e(self, message):
print ("\x1b[6;30;41m" + message + "\x1b[0m")

def i(self, message):
print ("\x1b[7;37;40m" + message + "\x1b[0m")

def s(self, message):
print ("\x1b[6;30;42m" + message + "\x1b[0m")

Logger nesnemizi uygulamada kritik noktalarda ilgili seviyelerde (level) konumlandırırız.

Log = Logger()
Log.e("ben bir hata mesajı olarak kendime kırmızıyı seçtim")

Level, önemli bir durum çünkü süreçlerimizi belirli kategorik seviyelerde ayrıştırmak için önemli bir kavramdır.

Örneğin, kullanıcıdan bir url parametresi beklersiniz, ve bu url için server çevrimdışı olabilir. Bu hatamızı kırmızı olarak error olarak gösteririz, ya da sadece tüm operasyonu kullanıcı görmek istiyordur, bu akışı Log.i(“işlem gerçekleşiyor”) ile beyaz bir renk ile, uyarıları (warnings) sarı olarak gösterebiliriz, başarılı sonuçları(success) Log.s(“image indirme işlemi başarıyla gerçekleşti”). Ve bu seviyeleri kendi operasyonlarınıza dilediğiniz gibi özelleştirebilirsiniz.

Logging

Ve sebebi ziyaretimiz olan Logging. Çocuğumuz bir tanecik olan programımıza sizi istiyoruz.

Logging Python için bir loglama yapabildiğimiz kütüphanedir. Ve Logging’i uygulamalarımıza kolayca dahil edebiliriz. Logging aynı zamanda Python için yerleşik bir araçtır, varsayılan bir python ortamınızda mevcuttur.

Logging yapısında temel olarak seviyeler(levels) bulunmaktadır.

Yukarıdaki yapının hiyerarşik olarak kurgulandığını düşünebiliriz. Burada seviyeleri gerçekleşecek durumların ciddiyet sıralaması olarak düşünebiliriz.

DEBUG: Sorunların teşhisi için debugging gibi düşünebiliriz. Ayrıntılı bilgilere ihtiyacımız vardır.

INFO: Beklenen çıktılarımızdır.

WARNING: Yazılım hala çalışıyordur ama uyarı çanları çalmaktadır.

ERROR: Yazılım ciddi bir sorunla karşılaştı ve görevini yerine getiremedi.

CRITICAL: Programın işlevini yerine getiremeyecek bir sorunla karşılaşmasıdır.

Temel anlamda bu seviyeler verilerimizi etkilerine göre filtrelemek için vardır.

Logging Uygulama

Özlü sözlerin özelleştirerek gösterimini sağladığımız bir uygulamamız var. Bu uygulama üzerinde logging deneyimini yaşayalım.

Yukarıdaki kod bloğunda özlü sözler ve söyleyenleri ile birlikte dictionary bir yapıda memory’de saklıyoruz. Daha sonra parametrik olarak oluşturduğumuz fonksiyon ile gösterimi özelleştiriyoruz.

import logging as log

Logging paketini log olarak kullanmak üzere dahil ettik. Log kütüphanesini kod bloğunda özlü sözü söyleyen olmadığı durumda WARNING seviyesi ile toplam kullanılan kapasite durumunu ise INFO seviyesi uyguluyoruz. Kodumuzu çalıştırdığımızda aşağıdaki gibi bir çıktı alıyoruz.

Beklediğimiz gibi özlü sözün söyleyeni bulunmadığında WARNING olarak çıktımızı aldık fakat INFO olarak işaretlediğimiz log’u gözlemleyemedik. Bunun sebebi varsayılan seviye (default level) WARNING olduğundan daha aşağıda bulunan INFO seviyesi çalışmayacaktır. Bunun için varsayılan root level’i INFO’ya çevirebiliriz.

Hatırlarsanız yukarıdaki INFO seviyesi integer olarak 20, WARNING ise 30. Aslında varsayılan değer olan 30'dan düşük bir seviye gösterimi yapılamaz anlamına gelir.

import logging as log
log.getLogger().setLevel(log.INFO)

Log seviyesini INFO’ya çektikten sonra aşağıdaki gibi INFO seviyesinde olan kayıtlarımızı gösterebiliriz.

Kayıt Günlüklerini Dosya’da Saklamak

Kayıtlarımızı dosya üzerinde saklamak istersen aşağıdaki gibi bir yapılandırma yapmamız yeterli olacaktır.

log.basicConfig(filename='kayit_gunlugu.log', level=log.INFO)

Buna göre script’imiz yukarıdaki duruma göre 2 kez çalıştığında kayıt_gunlugu.log dosyasında veriler kayıtlar aşağıdaki gibi görünecektir.

Görüldüğü üzere log’lar başarılı bir şekilde tutulmuş durumda fakat hangi kayıtın ne zaman gerçekleştiği konusunda fikir sahibi olamıyoruz. Bunun için ufak bir log kayıt formatı ekliyoruz.

import logging as log

log.basicConfig(filename='kayit_gunlugu.log', level=log.INFO,format='%(asctime)s %(message)s')

Bundan sonrasında çalıştırdığımız her log işlemi tarih ve mesaj olarak aşağıdaki gibi tutulacaktır.

Farklı modüllerim var? Log dosyasında nasıl ayrıştıracağım?

Tek bir python dosyasında çalıştığımız için kayıtlarımızın hangi modülden kaynaklandığı konusunda tereddütümüz yok. Ama daha kapsamlı birden fazla modül içeren proje üzerinde çalışıyor olsaydık, haliyle birden fazla python dosyasında çalışıyor olurduk. Bu durumda log’larda bulunan verilerin hangi modülden beslendiği konusunda bir ayrım yapmamız ve kayıtları modül bilgisi ile tutmamız daha doğru olacaktır. Bunun için tek bir dosya üzerinde ‘kayit_gunlugu.log’, a_project_module1, a_project_module2 gibi başlıklar ekleyebiliriz.

a.py dosyası için a_project_module1 :

import logging

logging.basicConfig(filename='kayit_gunlugu.log', level=logging.INFO, format='%(asctime)s - %(name)s - %(levelname)s - %(message)s')
logger = logging.getLogger("a_project.module1")

bundan sonra operasyonlar için logging.getLogger(“a_project.module1”) fonksiyonu üzerinden oluşturduğumuz logger nesnesi ile warning, info gibi log kayıt işlemlerini kullanacağız.

logger.warning(“unable to find the said : “ + dictionary.get(saying_key))

Yukarıda log formatını biraz daha özelleştirdik.

b.py dosyası için a_project_module2 :

import logging

logger = logging.getLogger("a_project.module2")
log_formatter = logging.Formatter("%(asctime)s - %(name)s - %(levelname)s - %(message)s'")
file_handler = logging.FileHandler("app_log.log")
file_handler.setLevel(logging.INFO)
file_handler.setFormatter(log_formatter)
logger.addHandler(file_handler)

product_prices = [19, 29, 39]

for i in product_prices:
if i >= 30:
print(i/2)
logger.warning("30'u geçen ürün fiyatları : " + str(i))
else:
print(i*0)

2 farklı python dosyasından beslenecek log’larımızı aynı format’la tek bir log dosyasında toplamış olduk buna göre aşağıdaki gibi daha anlaşılır bir log file elde etmiş olduk.

format: time — module name — levelname —message

Uygulamalarımızda kontrolümüz dışında gerçekleşebilecek çeşitli sorunlar meydana gelebilir. Logging yöntemiyle ters giden ya da sonradan izlemek istediğiniz işlemlere izler yerleştirebilirsiniz. Daha sonrasında işler ters gittiğinde neyin neden sebep olduğu konusunda ipuçlarını takip edebiliriz.

Socratica ablamızın dediği gibi

En iyisini umut et, en kötüsüne göre planla!

import logging
?logging
Type: module
String form: <module ‘logging’ from ‘/anaconda3/envs/p36/lib/python3.6/logging/__init__.py’>
File: /anaconda3/envs/p36/lib/python3.6/logging/__init__.py
Docstring:
Logging package for Python. Based on PEP 282 and comments thereto in
comp.lang.python.
Copyright © 2001–2016 Vinay Sajip. All Rights Reserved.
To use, simply ‘import logging’ and log away!

--

--