“Debugging is twice as hard as writing the code in the first place. Therefore, if you write the code as cleverly as possible, you are, by definition, not smart enough to debug it.” - Brian Kernighan
📌 Նկարագիր Մեր առաջին սովորած ֆունկցիան՝ print-ը։ Շատ լավ օրեր ենք անցկացրել իրա հետ, բայց հիմա ժամանակն ա անցնել իրա պռոֆեսինոլ տարբերակին՝ logging-ին։ Սովորում ենք ՝ 1. ոնց նշել logging-ի մակարդակը 2. մեր ուզած ձևով ֆոռմատավորել log-երը 3. գրել log-երը ֆայլի մեջ, ինչպես նաև կոնսոլում 4. json ֆորմատով պահել լոգերը 5. exception-ներ log անել
Հետո անցնում ենք Command Line Interface(CLI)-եր սարքելու գրադարաններին։ CLI-ների շնորհիվ ա որ կարանք գրենք ուղղակի pip install panir ու ինքը գնա ավտոմատ քաշի բերի մեր ուզած գրադարանը, ոչ թե մենք բացենք կոդը որտեղ install հրամանը օգտագործվում ա ու կոդի մեջ նշենք որ արգումենտ որպես մեր գրադարանի անունը գնա։ Սովորում ենք՝ 1. Argparse-ը (ներկառուցված գրադարան) 2. Fire (ֆունկցիաներին CLI-ով դիմելու համար 1-2 տողանոց լուծում) 3. Click (դեկորատորներով աշախտող ուժեղ գրադարն) 4. Typer (FastAPI-ենց գրադարանը type hint-երի վրա հիմնված)
import logginglogger = logging.getLogger('file_console_logger')logger.setLevel(logging.DEBUG) # another way to set the level# Create file handlerfile_handler = logging.FileHandler('app.log', mode="a") # a is defaultfile_handler.setLevel(logging.INFO)# Create formatterformatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')file_handler.setFormatter(formatter)# Add handlers to loggerlogger.addHandler(file_handler)
def divide_numbers(a, b):"""Division with comprehensive logging""" logger.info(f"Starting division: {a} ÷ {b}")try: result = a / b logger.info(f"Division successful. Result: {result}")return resultexceptZeroDivisionError: logger.error("Division by zero error!")returnNoneexceptExceptionas e: logger.critical(f"Unexpected error: {e}")returnNone# Test the functionresult1 = divide_numbers(10, 3)result2 = divide_numbers(509, 0)# Show that logs go to both console and fileprint(f"\nResults: {result1}, {result2}")print("Check 'app.log' file for logged messages")
2025-07-20 10:50:40,415 - file_console_logger - INFO - Starting division: 10 ÷ 3
2025-07-20 10:50:40,416 - file_console_logger - INFO - Division successful. Result: 3.3333333333333335
2025-07-20 10:50:40,417 - file_console_logger - INFO - Starting division: 509 ÷ 0
2025-07-20 10:50:40,418 - file_console_logger - ERROR - Division by zero error!
Results: 3.3333333333333335, None
Check 'app.log' file for logged messages
Logging to console as well
import logginglogger = logging.getLogger('file_console_logger')logger.setLevel(logging.DEBUG) # another way to set the level# Create file handlerfile_handler = logging.FileHandler('app.log', mode="a") # a is defaultfile_handler.setLevel(logging.INFO)# Create formatterformatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')file_handler.setFormatter(formatter)# Add handlers to loggerlogger.addHandler(file_handler)
Console handler
# add console handlerconsole_handler = logging.StreamHandler()console_handler.setLevel(logging.INFO)console_handler.setFormatter(formatter) # Use the same formatter# Add handlers to loggerlogger.addHandler(console_handler)
# Test the functionresult1 = divide_numbers(10, 2)result2 = divide_numbers(10, 0)# Show that logs go to both console and fileprint(f"\nResults: {result1}, {result2}")print("Check 'app.log' file for logged messages")
2025-07-20 10:50:49,475 - file_console_logger - INFO - Starting division: 10 ÷ 2
2025-07-20 10:50:49,475 - file_console_logger - INFO - Starting division: 10 ÷ 2
2025-07-20 10:50:49,479 - file_console_logger - INFO - Division successful. Result: 5.0
2025-07-20 10:50:49,479 - file_console_logger - INFO - Division successful. Result: 5.0
2025-07-20 10:50:49,482 - file_console_logger - INFO - Starting division: 10 ÷ 0
2025-07-20 10:50:49,482 - file_console_logger - INFO - Starting division: 10 ÷ 0
2025-07-20 10:50:49,485 - file_console_logger - ERROR - Division by zero error!
2025-07-20 10:50:49,485 - file_console_logger - ERROR - Division by zero error!
Results: 5.0, None
Check 'app.log' file for logged messages
# Example class with loggingclass Calculator:def__init__(self):self.logger = logging.getLogger(f'{__name__}.Calculator')self.logger.info("Calculator instance created")def add(self, a, b):self.logger.debug(f"Adding: {a} + {b}") result = a + bself.logger.info(f"Addition result: {result}")return resultdef multiply(self, a, b):self.logger.debug(f"Multiplying: {a} × {b}") result = a * bself.logger.info(f"Multiplication result: {result}")return resultdef divide(self, a, b):self.logger.debug(f"Dividing: {a} ÷ {b}")try: result = a / bself.logger.info(f"Division result: {result}")return resultexceptZeroDivisionError:self.logger.error("Division by zero attempted")returnNone# Test the Calculator with loggingcalc = Calculator()calc.add(5, 3)calc.multiply(4, 7)calc.divide(10, 2)calc.divide(10, 0) # This will generate an error logadvanced_logger.info("Calculator operations completed")
Division by zero attempted
Division by zero attempted
Division by zero attempted
python-json-logger
!uv pip install python-json-logger
Using Python 3.10.18 environment at: C:\Users\hayk_\.conda\envs\lectures
Audited 1 package in 21ms
import sysimport loggingfrom pythonjsonlogger import jsonlogger logger = logging.getLogger(__name__)stdout_handler = logging.StreamHandler(stream=sys.stdout)# format with JSONformat_output = jsonlogger.JsonFormatter('%(levelname)s : %(name)s : %(message)s : %(asctime)s')stdout_handler.setFormatter(format_output)logger.addHandler(stdout_handler)logger.error("This is an error message")logger.critical("This is a critical message")
{"levelname": "ERROR", "name": "__main__", "message": "This is an error message", "asctime": "2025-07-20 11:00:44,850"}
{"levelname": "CRITICAL", "name": "__main__", "message": "This is a critical message", "asctime": "2025-07-20 11:00:44,851"}
import sysimport loggingfrom pythonjsonlogger import jsonloggerlogger = logging.getLogger(__name__)logger.setLevel(logging.INFO)stdout_handler = logging.StreamHandler(stream=sys.stdout)## Create a file handlerfileHandler = logging.FileHandler("app_with_json.log") # <-format_output = jsonlogger.JsonFormatter('%(levelname)s : %(name)s : %(message)s : %(asctime)s')stdout_handler.setFormatter(format_output)fileHandler.setFormatter(format_output) # <-logger.addHandler(stdout_handler)## the file handle handlerlogger.addHandler(fileHandler) # <-logger.error("This is an error message")logger.critical("This is a critical message")
{"levelname": "ERROR", "name": "__main__", "message": "This is an error message", "asctime": "2025-07-20 11:01:06,254"}
{"levelname": "CRITICAL", "name": "__main__", "message": "This is a critical message", "asctime": "2025-07-20 11:01:06,256"}
ERROR:root:division by zero
Traceback (most recent call last):
File "C:\Users\hayk_\AppData\Local\Temp\ipykernel_6588\1569123368.py", line 3, in <module>
print(509/0)
ZeroDivisionError: division by zero