Как добавить логирование в собственные исключения?

Чтобы добавить логирование в собственные исключения, нужно:

  1. Импортировать модуль logging.
  2. Настроить логгер (уровень, формат, обработчик).
  3. В блоке __init__ класса исключения (или в методе, где оно вызывается) использовать logger.error() (или другой уровень) для записи информации об исключении. Можно передать сообщение об ошибке и данные, которые помогли определить исключение.
    
      import logging

      logging.basicConfig(level=logging.ERROR, format='%(asctime)s - %(levelname)s - %(message)s')

      class MyCustomError(Exception):
          def __init__(self, message, data=None):
              super().__init__(message)
              self.data = data
              logging.error(f"MyCustomError: {message}, Data: {data}")


      try:
          # Код, который может вызвать исключение
          raise MyCustomError("Произошла ошибка", data={"value": 123})
      except MyCustomError as e:
          print(f"Обработано исключение: {e}")

    
  

Добавление логирования в собственные исключения позволяет отслеживать возникновение этих исключений, получать дополнительную информацию о контексте их возникновения и упрощает отладку.

Вот несколько способов реализации логирования в собственных исключениях:

  1. Логирование в конструкторе исключения:
  2. Самый простой способ – добавить логирование непосредственно в конструктор класса исключения. В этом случае, при создании экземпляра исключения, будет сразу же записано соответствующее сообщение в лог.

    
     import logging
    
     logging.basicConfig(level=logging.ERROR, filename='exception.log', filemode='w', format='%(asctime)s - %(levelname)s - %(message)s')
    
     class CustomException(Exception):
      def __init__(self, message, details=None):
       super().__init__(message)
       self.message = message
       self.details = details
       logging.error(f"CustomException: {message}, Details: {details}") # Логирование при создании исключения
    
     try:
      # Код, который может вызвать исключение
      raise CustomException("Произошла ошибка", details={"user_id": 123, "operation": "delete"})
     except CustomException as e:
      print(f"Обработка исключения: {e.message}")
      # Дополнительная обработка исключения
       

    Плюсы: Простота реализации, логирование происходит непосредственно при создании исключения.

    Минусы: Логирование происходит даже если исключение перехвачено и обработано без необходимости логирования. Захламление лога может быть нежелательным.

  3. Логирование в блоке `except`:
  4. Вместо логирования в конструкторе исключения, можно логировать только в блоке `except`, когда исключение фактически поймано и обрабатывается. Это более контролируемый подход.

    
     import logging
    
     logging.basicConfig(level=logging.ERROR, filename='exception.log', filemode='w', format='%(asctime)s - %(levelname)s - %(message)s')
    
     class CustomException(Exception):
      def __init__(self, message, details=None):
       super().__init__(message)
       self.message = message
       self.details = details
    
     try:
      # Код, который может вызвать исключение
      raise CustomException("Произошла ошибка", details={"user_id": 123, "operation": "delete"})
     except CustomException as e:
      logging.error(f"CustomException: {e.message}, Details: {e.details}") # Логирование в блоке except
      print(f"Обработка исключения: {e.message}")
      # Дополнительная обработка исключения
       

    Плюсы: Логирование происходит только когда исключение обрабатывается, что позволяет избежать ненужных записей в логе.

    Минусы: Требует добавления логирования в каждый блок `except`, где обрабатывается данное исключение.

  5. Создание метода для логирования в исключении:
  6. Можно создать специальный метод в классе исключения, который будет отвечать за логирование. Это позволяет инкапсулировать логику логирования внутри класса исключения и повторно использовать ее.

    
     import logging
    
     logging.basicConfig(level=logging.ERROR, filename='exception.log', filemode='w', format='%(asctime)s - %(levelname)s - %(message)s')
    
     class CustomException(Exception):
      def __init__(self, message, details=None):
       super().__init__(message)
       self.message = message
       self.details = details
    
      def log_exception(self):
       logging.error(f"CustomException: {self.message}, Details: {self.details}")
    
     try:
      # Код, который может вызвать исключение
      raise CustomException("Произошла ошибка", details={"user_id": 123, "operation": "delete"})
     except CustomException as e:
      e.log_exception() # Вызов метода логирования
      print(f"Обработка исключения: {e.message}")
      # Дополнительная обработка исключения
       

    Плюсы: Инкапсуляция логики логирования, повторное использование, упрощение изменения логики логирования в будущем.

    Минусы: Требует добавления вызова метода логирования в каждый блок `except`.

Дополнительные рекомендации:

  • Используйте уровень логирования, соответствующий серьезности исключения (например, `ERROR`, `WARNING`).
  • Добавляйте в логируемое сообщение как можно больше полезной информации о контексте возникновения исключения (например, значения переменных, идентификаторы пользователей, время).
  • Рассмотрите возможность использования структурированного логирования (например, с помощью библиотеки `structlog`), чтобы упростить анализ логов.

Выбор конкретного подхода зависит от ваших потребностей и предпочтений. Важно, чтобы логирование было консистентным и предоставляло достаточно информации для диагностики проблем.

0