logging — level, handler, formatter, haqiqiy loyihada qanday ishlatiladi
Muammodan boshlaylik
Telegram bot serverda ishlayapti. Kechasi foydalanuvchi yozdi: "Bot javob bermayapti". Siz kodga print lar qo'shgansiz:
print("bu yerga keldi")
print(user)
print("xato bo'ldi")
Muammolar:
- Server da
printhech qayerga yozilmagan — terminal yopiq edi - Qaysi vaqtda bo'lgani noma'lum
- Qaysi xabar muhim (xato), qaysisi — oddiy (debug) — farqi yo'q
- Production da debug xabarlarini o'chirish uchun — har bir
printni qo'lda olib tashlash
logging nima?
logging — standart kutubxonadagi log yozish tizimi:
- Har bir xabarda vaqt, daraja, modul
- Darajalar — muhimligiga qarab filtrlash
- Bir vaqtda konsolga, faylga, tashqi xizmatga yozish
- Kodni o'zgartirmasdan — sozlama bilan boshqarish
Hayotiy o'xshatma
Kema jurnali. Kapitan har bir muhim hodisani vaqti bilan yozadi: "06:00 — portdan chiqdik" (INFO), "11:30 — shamol kuchaydi" (WARNING), "14:15 — dvigatel to'xtadi" (ERROR). Tekshiruvchi faqat jiddiy hodisalarni ko'rmoqchi bo'lsa — WARNING dan yuqorisini o'qiydi. Jurnal kema cho'kkan taqdirda ham saqlanib qoladi (faylga yozilgan).
Darajalar
| Daraja | Qiymat | Qachon |
|---|---|---|
DEBUG |
10 | Dasturchi uchun tafsilotlar: o'zgaruvchilar qiymati |
INFO |
20 | Oddiy hodisalar: "server ishga tushdi", "buyurtma yaratildi" |
WARNING |
30 | G'alati, lekin ishlayapti: "API sekin javob berdi" |
ERROR |
40 | Xato — amal bajarilmadi |
CRITICAL |
50 | Dastur ishlay olmaydi |
Belgilangan darajadan past xabarlar e'tiborsiz qoldiriladi. Standart daraja — WARNING.
Tez boshlash — basicConfig
import logging
logging.basicConfig(
level=logging.INFO,
format="%(asctime)s %(levelname)-8s %(name)s: %(message)s",
datefmt="%Y-%m-%d %H:%M:%S",
)
logging.debug("Bu ko'rinmaydi — DEBUG < INFO")
logging.info("Bot ishga tushdi")
logging.warning("API javobi 3 soniya kechikdi")
logging.error("Buyurtmani saqlab bo'lmadi")
2026-11-08 10:00:00 INFO root: Bot ishga tushdi
2026-11-08 10:00:01 WARNING root: API javobi 3 soniya kechikdi
2026-11-08 10:00:02 ERROR root: Buyurtmani saqlab bo'lmadi
basicConfig — dasturning eng boshida, bir marta.
Har bir modulga o'z logger i
# dokon/tolov.py
import logging
logger = logging.getLogger(__name__) # "dokon.tolov"
def tolash(buyurtma_id, summa):
logger.info("To'lov boshlandi: buyurtma=%s summa=%s", buyurtma_id, summa)
try:
natija = provayder_api(summa)
except ConnectionError:
logger.exception("To'lov provayderiga ulanib bo'lmadi: buyurtma=%s", buyurtma_id)
raise
logger.info("To'lov muvaffaqiyatli: buyurtma=%s", buyurtma_id)
return natija
logging.getLogger(__name__)— modul nomi bilan logger: logda xabar qaysi fayldan kelgani ko'rinadi- Modullarda
logging.info(...)(root logger) emas — o'zloggeringiz
Parametrlar — %s bilan
logger.info("Foydalanuvchi %s kirdi", user_id) # ✅
logger.info(f"Foydalanuvchi {user_id} kirdi") # ishlaydi, lekin
%s uslubida satr faqat xabar haqiqatan yozilganda formatlanadi. logger.debug(f"... {ogir_hisob()}") — DEBUG o'chiq bo'lsa ham f-string hisoblanadi.
logger.exception — traceback bilan
try:
1 / 0
except ZeroDivisionError:
logger.exception("Hisoblashda xato") # ERROR darajasi + to'liq traceback
except blokida xatoni log qilishning eng yaxshi usuli — sabab va qator raqami saqlanadi (31-dars).
Handler va Formatter
Log tizimi uch qismdan iborat:
Logger ──xabar──▶ Handler(lar) ──▶ qayerga: konsol, fayl, email, tashqi xizmat
│
Formatter — qanday ko'rinishda
import logging
from logging.handlers import RotatingFileHandler
logger = logging.getLogger("bot")
logger.setLevel(logging.DEBUG)
formatter = logging.Formatter(
"%(asctime)s %(levelname)s [%(name)s:%(lineno)d] %(message)s"
)
# konsolga — INFO va yuqori
konsol = logging.StreamHandler()
konsol.setLevel(logging.INFO)
konsol.setFormatter(formatter)
# faylga — hammasi, 5 MB dan oshsa yangi fayl, 3 ta eski fayl saqlanadi
fayl = RotatingFileHandler("bot.log", maxBytes=5_000_000, backupCount=3, encoding="utf-8")
fayl.setLevel(logging.DEBUG)
fayl.setFormatter(formatter)
logger.addHandler(konsol)
logger.addHandler(fayl)
| Handler | Qayerga |
|---|---|
StreamHandler |
Konsol (stderr) |
FileHandler |
Fayl |
RotatingFileHandler |
Fayl, hajm bo'yicha aylantiriladi |
TimedRotatingFileHandler |
Fayl, vaqt bo'yicha (har kuni) |
SMTPHandler |
[!TIP] Oddiy
FileHandlerbilan log fayli oylar davomida o'sib, diskni to'ldirishi mumkin. Har doimRotatingFileHandleryokiTimedRotatingFileHandlerishlating. Docker va zamonaviy serverlarda esa ko'pincha faylga emas, stdout ga yoziladi — loglarni platforma yig'adi.
Format maydonlari
| Maydon | Ma'nosi |
|---|---|
%(asctime)s |
Vaqt |
%(levelname)s |
Daraja |
%(name)s |
Logger nomi (modul) |
%(message)s |
Xabar |
%(filename)s, %(lineno)d |
Fayl va qator |
%(funcName)s |
Funksiya |
Haqiqiy loyihada — dictConfig
Sozlamani bitta joyda, kod sifatida:
# loyiha/log_sozlama.py
import logging.config
import os
def sozla():
logging.config.dictConfig({
"version": 1,
"disable_existing_loggers": False,
"formatters": {
"oddiy": {"format": "%(asctime)s %(levelname)s %(name)s: %(message)s"},
},
"handlers": {
"konsol": {"class": "logging.StreamHandler", "formatter": "oddiy"},
"fayl": {
"class": "logging.handlers.RotatingFileHandler",
"filename": "app.log",
"maxBytes": 5_000_000,
"backupCount": 5,
"encoding": "utf-8",
"formatter": "oddiy",
},
},
"root": {
"level": os.getenv("LOG_LEVEL", "INFO"),
"handlers": ["konsol", "fayl"],
},
"loggers": {
"urllib3": {"level": "WARNING"}, # shovqinli kutubxonani jim qilish
},
})
# main.py
from loyiha.log_sozlama import sozla
import logging
def main():
sozla()
logging.getLogger(__name__).info("Ilova ishga tushdi")
if __name__ == "__main__":
main()
- Sozlash — faqat kirish nuqtasida (
main), modullarda — faqatgetLogger(__name__) - Daraja — muhit o'zgaruvchisidan: development da
DEBUG, production daINFO
Nimani log qilish va nimani qilmaslik
✅ Log qiling:
- Ilova ishga tushishi va to'xtashi
- Muhim biznes hodisalar: buyurtma, to'lov, ro'yxatdan o'tish (ID lar bilan)
- Tashqi xizmatlarga so'rovlar xatolari va sekin javoblar
- Barcha kutilmagan xatolar —
logger.exception
❌ Log qilmang:
- Parollar, tokenlar, karta raqamlari, to'liq shaxsiy ma'lumotlar
- Har bir sikl iteratsiyasi (INFO darajasida) — log fayli keraksiz ma'lumotga to'ladi
[!WARNING] Loglar ko'p odam va tizimlarga ko'rinadi va uzoq saqlanadi.
logger.info("Kirish: %s", request_data)— agarrequest_datada parol bo'lsa, u log faylida ochiq qoladi. Faqat kerakli, maxfiy bo'lmagan maydonlarni yozing.
Tez-tez uchraydigan xatolar
Hech narsa chiqmaydi:
logging.info("Salom") # ❌ ko'rinmaydi — standart daraja WARNING
basicConfig(level=logging.INFO).
basicConfig ni kech chaqirish — undan oldin biror log yozilgan bo'lsa, basicConfig ishlamaydi. Dastur boshida.
Handler ni har chaqiruvda qo'shish:
def ol_logger():
logger = logging.getLogger("app")
logger.addHandler(logging.StreamHandler()) # ❌ har chaqiruvda yana bitta — xabarlar ko'payadi
return logger
Sozlash — bir marta.
except da logger.error(e) — traceback yo'qoladi; logger.exception(...).
Xulosa
logging — vaqt, daraja va manba bilan boshqariladigan log yozish tizimi.
Eslab qoling:
- Darajalar:
DEBUG<INFO<WARNING<ERROR<CRITICAL; standart —WARNING basicConfig(level=..., format=...)— boshida, bir marta- Har modulda —
logger = logging.getLogger(__name__) logger.info("... %s", x); xatolar —logger.exception(...)(traceback bilan)- Handler — qayerga (konsol, aylantiriladigan fayl); Formatter — qanday
- Loyihada —
dictConfig, daraja muhit o'zgaruvchisidan - Maxfiy ma'lumotlarni log qilmang
Kurs yakunlandi
Tabriklaymiz — Python kursini tugatdingiz! Siz o'zgaruvchilar va sikllardan boshlab ma'lumot turlari, funksiyalar, dekoratorlar, OOP, xatolar va fayllar, standart kutubxona va ilg'or mavzular — generatorlar, type hints, dataclasses va logging gacha bo'lgan yo'lni bosib o'tdingiz.
Keyingi qadamlar:
- O'z loyihangizni yarating: Telegram bot, fayllarni saralovchi skript, hisobot generatori
- Web dasturlash — Django yoki FastAPI
- Ma'lumotlar tahlili — pandas, numpy
- Ma'lumotlar bazasi — PostgreSQL yoki MySQL kurslari