Giriş
Modern yazılım geliştirme süreçlerinde, uygulamaların arka planda nasıl çalıştığını izlemek, hataları tespit etmek ve performans darboğazlarını belirlemek kritik bir öneme sahiptir. Bu izleme sürecinin en temel yapı taşı ise loglama (günlük kaydı tutma) işlemleridir. Python programlama dilinde, kod tekrarından kaçınarak ve mevcut fonksiyonların yapısını bozmadan onlara yeni yetenekler kazandırmak için "decorator" (süsleyici) tasarım deseni kullanılır. Python ile decorator yapısı kullanarak fonksiyon loglama nasıl yapılır sorusu, temiz kod (clean code) prensiplerini benimseyen her geliştiricinin yanıtını bilmesi gereken önemli bir konudur.
Bu kapsamlı eğitim rehberinde, Python'da decorator kavramının teorik temelinden başlayarak, adım adım profesyonel bir loglama mekanizmasının nasıl kurulacağını öğreneceksiniz. Basit ekrana yazdırma işlemlerinden, Python'un standart logging kütüphanesini entegre etmeye, performans ölçümü yapmaktan hata yakalama süreçlerini yönetmeye kadar geniş bir yelpazede pratik uygulamalar gerçekleştireceğiz. Bu rehber, orta ve ileri düzey Python geliştiricilerinin projelerinde doğrudan kullanabileceği, üretime hazır (production-ready) çözümler sunmaktadır.
Rehber boyunca yazacağımız tüm kodlar, Python'un güncel standartlarına uygun olarak tasarlanmıştır. Her adımda yazılan kodların ne işe yaradığını, neden belirli tasarım tercihlerini yaptığımızı ve bu yapıları kendi projelerinize nasıl uyarlayabileceğinizi detaylıca ele alacağız. Hazırsanız, Python'un en güçlü özelliklerinden biri olan decorator yapısını kullanarak sistemlerimizi daha izlenebilir kılma yolculuğuna başlayalım.
Gereksinimler ve Ön Hazırlık
Bu eğitimdeki uygulamaları sorunsuz bir şekilde çalıştırabilmek ve konuyu tam anlamıyla kavrayabilmek için bilgisayarınızda belirli bir çalışma ortamının kurulu olması gerekmektedir. Aşağıdaki gereksinimleri karşıladığınızdan emin olunuz:
- Python Sürümü: Bu rehberde kullanılan modern sözdizimi ve kütüphane özellikleri için bilgisayarınızda en az Python 3.10 veya üzeri bir sürümün kurulu olması önerilir. (2026 yılı standartlarında Python 3.12+ kullanımı en iyi pratikleri sunar).
- Geliştirme Ortamı (IDE): Kodları yazmak ve test etmek için VS Code, PyCharm veya sade bir metin düzenleyici kullanabilirsiniz.
- Temel Bilgi Seviyesi: Python'da fonksiyon tanımlama, parametre yönetimi (
*argsve**kwargs) ve temel hata yönetimi (try-except) konularına aşina olmanız beklenmektedir.
Herhangi bir harici kütüphane kurmanıza gerek yoktur. Bu rehberde gerçekleştireceğimiz tüm işlemler Python'un standart kütüphanesinde yer alan yerleşik (built-in) modüller kullanılarak yapılacaktır. Bu durum, uygulamanızın bağımlılıklarını minimumda tutmanıza yardımcı olur.
Python Decorator (Süsleyici) Nedir ve Nasıl Çalışır?
Teknik olarak decorator yapısına geçmeden önce, Python'da fonksiyonların "birinci sınıf vatandaş" (first-class citizens) olduğunu anlamak gerekir. Python'da fonksiyonlar; değişkenlere atanabilir, başka fonksiyonlara argüman olarak gönderilebilir veya bir fonksiyondan değer olarak döndürülebilir. Decorator yapısı, tam olarak bu felsefe üzerine kurulmuştur.
Bir decorator, özünde başka bir fonksiyonu parametre olarak alan, onun davranışını değiştiren veya genişleten ve geriye yeni bir fonksiyon döndüren bir fonksiyondur. Bu işlem, mevcut fonksiyonun kaynak kodunu değiştirmeden ona yeni özellikler eklememizi sağlar. Python'da decorator'lar @decorator_adi sözdizimi ile hedef fonksiyonun hemen üzerine yazılarak uygulanır.
Decorator'ların çalışma mantığını anlamak için arka planda dönen süreci kavramak önemlidir. Bir fonksiyonu süslediğinizde, Python aslında şu işlemi gerçekleştirir:
# Arka plandaki çalışma mantığının temsili gösterimi
hedef_fonksiyon = decorator_fonksiyonu(hedef_fonksiyon)
Bu yapı sayesinde, fonksiyon çağrılmadan hemen önce ve çağrıldıktan hemen sonra araya girerek loglama, yetkilendirme, önbelleğe alma (caching) veya çalışma süresi ölçme gibi işlemleri kolayca gerçekleştirebiliriz.
Adım 1: İlk Loglama Decorator'ını Yazmak (Adım Adım Örnek Kod)
Loglama decorator'ı yazmanın ilk adımı, en basit haliyle bir fonksiyonun ne zaman çağrıldığını ve hangi isimle çağrıldığını konsola yazdıran bir yapı kurmaktır. Bu adımda, iç içe fonksiyon yapısını ve parametrelerin nasıl aktarıldığını göreceğiz.
Aşağıdaki kod bloğunda, basit_loglayici adında bir decorator tanımlıyoruz. Bu decorator, süslenen fonksiyonun adını ve çağrılma anını konsola yazdıracaktır.
from datetime import datetime
def basit_loglayici(fonksiyon):
def sarmalayici(*args, **kwargs):
# Fonksiyon çağrılmadan önce yapılacak işlemler
simdi = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
print(f"[{simdi}] BİLGİ: '{fonksiyon.__name__}' fonksiyonu çağrılıyor...")
# Orijinal fonksiyonun çalıştırılması
sonuc = fonksiyon(*args, **kwargs)
# Fonksiyon çalıştıktan sonra yapılacak işlemler
print(f"[{simdi}] BİLGİ: '{fonksiyon.__name__}' fonksiyonu başarıyla tamamlandı.")
return sonuc
return sarmalayici
# Decorator'ın uygulanması
@basit_loglayici
def toplama_yap(a, b):
return a + b
# Fonksiyonun test edilmesi
if __name__ == "__main__":
hesaplama = toplama_yap(10, 20)
print(f"İşlem Sonucu: {hesaplama}")
Kodun Açıklaması ve Test Edilmesi: Yukarıdaki kodda basit_loglayici fonksiyonu, parametre olarak aldığı fonksiyon nesnesini sarmalayan sarmalayici (wrapper) adında içsel bir fonksiyon tanımlar. *args ve **kwargs ifadeleri, süslenecek fonksiyonun alabileceği her türlü sınırsız konum tabanlı ve anahtar kelime tabanlı parametreyi esnek bir şekilde kabul etmemizi sağlar. Kod çalıştırıldığında konsolda sırasıyla fonksiyonun çağrıldığına dair log mesajı, ardından fonksiyonun kendi çıktısı ve son olarak işlemin tamamlandığına dair log mesajı görüntülenecektir.
Adım 2: functools.wraps ile Meta Verileri Korumak Neden Zorunludur?
Bir fonksiyonu decorator ile süslediğimizde, teknik olarak o fonksiyonu sarmalayan başka bir fonksiyonla değiştirmiş oluruz. Bu durum, orijinal fonksiyonun adı (__name__) ve açıklama satırı (docstring - __doc__) gibi meta verilerinin kaybolmasına yol açar. Bu durum, hata ayıklama (debugging) süreçlerinde ve otomatik dokümantasyon araçlarında ciddi sorunlara neden olur.
Bu sorunu çözmek için Python'un standart kütüphanesinde yer alan functools modülündeki wraps decorator'ını kullanmalıyız. wraps, orijinal fonksiyonun tüm meta verilerini sarmalayıcı fonksiyona kopyalar.
Aşağıdaki örnek kodda, meta veri kaybı sorununu ve functools.wraps kullanarak bu sorunu nasıl çözeceğimizi adım adım görebilirsiniz.
from functools import wraps
def meta_veri_koruyan_loglayici(fonksiyon):
@wraps(fonksiyon) # Orijinal fonksiyonun meta verilerini korur
def sarmalayici(*args, **kwargs):
print(f"Loglama: {fonksiyon.__name__} çalıştırılıyor...")
return fonksiyon(*args, **kwargs)
return sarmalayici
@meta_veri_koruyan_loglayici
def veri_tabanina_kaydet(kullanici_adi):
"""Yeni bir kullanıcıyı veri tabanına kaydeder."""
print(f"Kullanıcı kaydedildi: {kullanici_adi}")
# Meta verilerin kontrol edilmesi
if __name__ == "__main__":
veri_tabanina_kaydet("Ahmet")
# functools.wraps olmasaydı çıktı 'sarmalayici' olurdu
print(f"Fonksiyon Adı: {veri_tabanina_kaydet.__name__}")
# functools.wraps olmasaydı çıktı None olurdu
print(f"Fonksiyon Açıklaması: {veri_tabanina_kaydet.__doc__}")
Kodun Açıklaması ve Test Edilmesi: @wraps(fonksiyon) satırı, sarmalayıcı fonksiyonun üzerine eklenerek veri_tabanina_kaydet fonksiyonunun gerçek adını ve docstring bilgisini korur. Kodun çıktısında fonksiyon adının "veri_tabanina_kaydet" ve açıklamasının da "Yeni bir kullanıcıyı..." şeklinde doğru bir şekilde korunduğunu göreceksiniz. Bu adım, profesyonel projelerde standart bir kural olarak kabul edilir.
Adım 3: Python logging Modülü ile Dosyaya Log Yazma Nasıl Yapılır?
Gerçek dünya senaryolarında log mesajlarını sadece konsola yazdırmak (print kullanmak) yeterli değildir. Logların kalıcı hale getirilmesi, belirli bir formatta tutulması ve dosyalara yazılması gerekir. Bunun için Python'un yerleşik logging modülünü decorator yapımıza entegre etmeliyiz.
Aşağıdaki örnek kodda, log mesajlarını hem konsola hem de dinamik olarak oluşturulan bir uygulama.log dosyasına yazan profesyonel bir decorator yapısı kurulmuştur.
import logging
from functools import wraps
import os
# Logging yapılandırması
logging.basicConfig(
level=logging.INFO,
format='%(asctime)s - %(levelname)s - [%(filename)s:%(lineno)d] - %(message)s',
handlers=[
logging.FileHandler("uygulama.log", encoding="utf-8"),
logging.StreamHandler() # Konsola da yazdırmak için
]
)
logger = logging.getLogger("UygulamaLoglayici")
def profesyonel_loglayici(fonksiyon):
@wraps(fonksiyon)
def sarmalayici(*args, **kwargs):
# Argümanları log mesajına güvenli bir şekilde dahil etme
arg_str = ", ".join([str(a) for a in args])
kwarg_str = ", ".join([f"{k}={v}" for k, v in kwargs.items()])
parametreler = f"Argümanlar: ({arg_str}) {kwarg_str}"
logger.info(f"BAŞLADI: '{fonksiyon.__name__}' çalışıyor. {parametreler}")
try:
sonuc = fonksiyon(*args, **kwargs)
logger.info(f"BİTTİ: '{fonksiyon.__name__}' başarıyla tamamlandı. Dönen Değer: {sonuc}")
return sonuc
except Exception as hata:
logger.error(f"HATA: '{fonksiyon.__name__}' çalışırken hata oluştu. Hata Mesajı: {str(hata)}")
raise hata # Hatanın yukarı fırlatılması uygulamanın akışını bozmaz
return sarmalayici
@profesyonel_loglayici
def odeme_islemi_yap(kullanici_id, miktar):
# Ödeme simülasyonu
if miktar 

Yorumlar (0)
Yorum Yaz