0
2

More than 1 year has passed since last update.

ログをデコレーターで記述する

Last updated at Posted at 2023-07-30

関数内にログをベタベタ書くと見づらいのでデコレータで
外に吐き出しました。(結果的に一層長くなりましたが...)
もっと短く書けないか考え中です。

以下、足し算・引き算の例です。

import logging
import sys
import functools

class CalculatorLogger:
    def __init__(self, logger_name):
        self.logger = logging.getLogger(logger_name)
        self.logger.setLevel(logging.INFO)

        # ログが重複しないように、既存のハンドラーがあれば削除
        if self.logger.hasHandlers():
            self.logger.handlers.clear()

        formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(funcName)s:%(lineno)d - %(message)s')

        # ログをコンソールに出力するハンドラーを追加
        console_handler = logging.StreamHandler()
        console_handler.setLevel(logging.INFO)
        console_handler.setFormatter(formatter)
        self.logger.addHandler(console_handler)

class Calculator:
    def __init__(self):
        self._result = 0
        self.logger = CalculatorLogger(__name__)

    # デコレーター: 関数の説明をログに含める
    def log_description(description):
        def decorator(func):
            @functools.wraps(func)
            def wrapper(self, *args, **kwargs):
                self.logger.logger.info(f'{func.__name__}: {description} 関数が呼び出されました。')
                result = func(self, *args, **kwargs)
                self.logger.logger.info(f'{func.__name__}: {description} 関数の実行が終了しました。')
                return result
            return wrapper
        return decorator

    # デコレーター: プロパティ変数の更新前後の値をログに残す
    def log_property_change(prop):
        def decorator(func):
            @functools.wraps(func)
            def wrapper(self, value):
                old_value = getattr(self, prop)
                func(self, value)
                new_value = getattr(self, prop)
                if old_value != new_value:  # 更新がある場合のみログ出力
                    self.logger.logger.info(f'{func.__name__}: {prop} 変数が更新されました。変更前: {old_value}, 変更後: {new_value}')
                setattr(self, prop, new_value)  # プロパティの値を更新
            return wrapper
        return decorator

    # 整数チェック
    def is_integer(value):
        try:
            int(value)
            return True
        except ValueError:
            return False

    # 足し算
    @log_description('足し算')
    @log_property_change('_result')
    def add(self, value):
        if not Calculator.is_integer(value):
            self.logger.logger.error('整数以外の値が指定されました。')
            sys.exit(1)
        self._result += int(value)

    # 引き算
    @log_description('引き算')
    @log_property_change('_result')
    def subtract(self, value):
        if not Calculator.is_integer(value):
            self.logger.logger.error('整数以外の値が指定されました。')
            sys.exit(1)
        self._result -= int(value)

    # プロパティ変数のゲッター
    @property
    def result(self):
        return self._result

# クラスのインスタンス化
calc = Calculator()

# 足し算と引き算のログ出力付き操作
calc.add(5)
calc.subtract(2)

# プロパティ変数のログ出力
print(calc.result)  # 現在の計算結果を表示

# エラーチェック:整数以外の引数
calc.add("abc")

0
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
2