Python-এ error handling ও logging: পরিষ্কারভাবে ব্যর্থ হোন

নির্দিষ্ট error ধরুন, নিজের exception-এ মুড়ুন ও কী ঘটেছে log করুন। exception chaining ও log level-সহ পরীক্ষিত উদাহরণ।

একটি log প্যানেলে সতর্কচিহ্ন দেওয়া একটি ব্যর্থ লাইন

প্রোগ্রাম ব্যর্থ হয়: ফাইল হারায়, নেটওয়ার্ক পড়ে যায়, input ভুল হয়। ভালো error handling ঠিক করে তখন প্রোগ্রাম কী করবে, আর ভালো logging লেখে কী ঘটেছিল যাতে পরে সারানো যায়। নিচের code ও output প্রকাশের আগে Python 3-এ চালানো।

exception-এর নিয়ম

  1. নির্দিষ্ট error ধরুন, সব নয়। except FileNotFoundError পরিষ্কার; except Exception bug লুকায়, আর খালি except: Ctrl+C-ও ধরে।
  2. যেখানে কাজের কিছু করতে পারেন সেখানে ধরুন: আবার চেষ্টা, default ব্যবহার, বার্তা দেখানো। নইলে ওপরে যেতে দিন।
  3. নিম্নস্তরের error নিজের exception-এ মুড়ুন raise ... from e দিয়ে। caller অর্থবহ error পায়, আর আসলটি কারণ হিসেবে থাকে।
  4. except: pass দিয়ে কখনও error চুপ করাবেন না।
  5. with দিয়ে পরিষ্কার করুন (ফাইল, lock, connection), কিছু ব্যর্থ হলেও resource বন্ধ হয়।

log level

Level কীসের জন্য
DEBUG ডেভেলপারের খুঁটিনাটি, production-এ বন্ধ
INFO স্বাভাবিক ঘটনা (সেবা চালু হলো)
WARNING অদ্ভুত কিছু, তবে চলেছে
ERROR একটি কাজ ব্যর্থ
CRITICAL প্রোগ্রাম আর চলতে পারে না

start-up-এ একবার level ঠিক করুন। তার নিচের বার্তা বাদ পড়ে।

পরীক্ষিত উদাহরণ

import json, logging, sys

class ConfigError(Exception):
    """Raised when the configuration file is unusable."""

def load_config(path):
    try:
        with open(path) as f:
            return json.load(f)
    except FileNotFoundError as e:
        raise ConfigError(f"config file not found: {path}") from e
    except json.JSONDecodeError as e:
        raise ConfigError(f"config is not valid JSON: {e.msg} at line {e.lineno}") from e

logging.basicConfig(stream=sys.stdout, level=logging.INFO, format="%(levelname)s %(name)s: %(message)s")
log = logging.getLogger("app")

def main(path):
    try:
        cfg = load_config(path)
    except ConfigError as e:
        log.error("cannot start: %s", e)
        log.debug("this debug line is hidden at INFO level")
        return 1
    log.info("started with %d settings", len(cfg))
    return 0

def risky():
    try:
        1 / 0
    except ZeroDivisionError:
        log.exception("calculation failed")     # logs the message and the traceback
INFO app: started with 2 settings
exit 0
ERROR app: cannot start: config is not valid JSON: Illegal trailing comma before end of object at line 1
exit 1
ERROR app: cannot start: config file not found: missing.json
exit 1
ERROR app: calculation failed
Traceback (most recent call last):
  File "app.py", line 30, in risky
    1 / 0
    ~~^~~
ZeroDivisionError: division by zero

কী ঘটল:

  • ভালো ফাইল স্বাভাবিকভাবে চালু হয়ে INFO-তে log করেছে।
  • খারাপ ও হারানো ফাইল দুটোই একটি পরিষ্কার ConfigError হয়েছে, যা এক জায়গায় ধরে ERROR log ও exit code ফেরানো হয়।
  • DEBUG লাইন আসেনি, কারণ level INFO ছিল।
  • except ব্লকের ভেতরে log.exception বার্তা ও traceback লিখেছে।

ভালো logging-এর অভ্যাস

  • প্রসঙ্গসহ ঘটনা log করুন: order id, user id, ফাইলের নাম। শুধু "ব্যর্থ" কাজে লাগে না।
  • lazy formatting ব্যবহার করুন, log.error("cannot start: %s", e), string জোড়া নয়।
  • গোপন কিছু log করবেন না: পাসওয়ার্ড, token, কার্ড নম্বর বা পুরো ব্যক্তিগত তথ্য।
  • error একবার log করুন, যেখানে সামলানো হয়, প্রতি স্তরে নয়।
  • container-এ log standard output-এ পাঠান, প্ল্যাটফর্মকে জড়ো করতে দিন।

সাধারণ ভুল

  • except Exception: pass, বা এত বড় করে ধরা যে আসল bug মিলিয়ে যায়।
  • error-এর জন্য None বা -1 ফেরানো, যা caller যাচাই করতে ভুলবে।
  • প্রতি স্তরে log করে আবার raise, একই error দশবার তৈরি।
  • একটি try ব্লকে অনেক কিছু রাখা, ফলে কোন লাইন ব্যর্থ বোঝা যায় না।
  • সেবায় diagnostic-এ print। level, timestamp ও routing হারান।

মূল কথা: যেখানে কাজ করতে পারেন সেখানে নির্দিষ্ট exception ধরুন, raise ... from দিয়ে মুড়ুন, আর সঠিক level ও যথেষ্ট প্রসঙ্গসহ log করুন, traceback-এর জন্য log.exception সহ।


Programming roadmaps সিরিজ, পর্ব ৩ (ভালো Python লেখা): 4 নম্বর (মোট 5)। আগের লেখা: Python-এ async/await: asyncio সময়সহ ব্যাখ্যা.

আরও পড়ুন

Python-এ regular expression: ফাঁদসহ ব্যবহারিক গাইড

Regular expression লেখা খুঁজে নতুন রূপ দেয়। group, greedy বনাম lazy, বাংলাদেশি মোবাইল নম্বর যাচাই ও যে backtracking ফাঁদ server জমিয়ে দিতে পারে তা শিখুন।

প্রোগ্রামিং•২ মিনিটে পড়া