0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

【Python】loggerに渡した文字列を関数で変更してみた

Posted at

Pythonでちょっと高級なAppを作るときに使用するlogger
loggerに渡した文字列に細工をしたいことありませんか?

今回はloggerにわたす文字列を加工して出力するloggerを作成しました

コード


from logging import LogRecord, Logger, Formatter, StreamHandler, FileHandler, DEBUG, INFO

def change_message(s: str) -> str:
    if s == "\\\n":
        return "\n\n\n\n\n"

    s = s.upper().replace("\n", "\t")

    if "CAT" in s:
        s += "ฅ^•ω•^ฅニャー"
    return s

class OriginalFormatter(Formatter):
    def format(self, record: LogRecord) -> str:
        record.message = change_message(record.getMessage())
        if self.usesTime():
            record.asctime = self.formatTime(record, self.datefmt)
        s = self.formatMessage(record)

        if record.exc_info:
            # Cache the traceback text to avoid converting it multiple times
            # (it's constant anyway)
            if not record.exc_text:
                record.exc_text = self.formatException(record.exc_info)
        if record.exc_text:
            if s[-1:] != "\n":
                s = s + "\n"
            s = s + record.exc_text
        if record.stack_info:
            if s[-1:] != "\n":
                s = s + "\n"
            s = s + self.formatStack(record.stack_info)
        return s

def init_logger(logger: Logger, file_name: str) -> Logger:
    log_format = OriginalFormatter("%(asctime)s %(name)s:%(lineno)s %(funcName)s [%(levelname)s]: %(message)s")

    st = StreamHandler()
    st.setFormatter(log_format)
    st.setLevel(INFO)

    fl = FileHandler(file_name)
    fl.setFormatter(log_format)
    fl.setLevel(DEBUG)

    logger.setLevel(DEBUG)
    logger.addHandler(st)
    logger.addHandler(fl)

    return logger

change_message関数

ここに任意の文字列を加工する関数を書いてください

OriginalFormatterクラス

loggerのFormat関数にchange_message関数をいれています

init_logger関数

ここでOriginalFormatterを用いloggerの設定をしています

お試し

if __name__=="__main__":
    from logging import getLogger
    import traceback
    logger = getLogger(__name__)
    logger = init_logger(logger, "test.log")

    logger.debug("logger debug")
    logger.info("logger info")
    # 2023-08-03 12:22:42,819 __main__:59 <module> [INFO]: LOGGER INFO
    logger.warning("logger warn")
    # 2023-08-03 12:22:42,819 __main__:60 <module> [WARNING]: LOGGER WARN
    logger.error("logger error")
    # 2023-08-03 12:22:42,819 __main__:61 <module> [ERROR]: LOGGER ERROR

loggerの設定と、実際に出力したものです
今回の関数は小文字を大文字にする機能がありますが、適切に変化しています

    try:
        raise("raise!")
    except:
        logger.exception("logger exception", exc_info=True) # traceback に関数を適用しない
        logger.error("except log\n" + traceback.format_exc()) # 適用する

    # 2023-08-03 12:22:42,819 __main__:66 <module> [ERROR]: LOGGER EXCEPTION
    # Traceback (most recent call last):
    #   File "/Users/~~~~~/original_logger.py", line 64, in <module>
    #     raise("raise!")
    # TypeError: exceptions must derive from BaseException
    # 2023-08-03 12:22:42,819 __main__:67 <module> [ERROR]: EXCEPT LOG        TRACEBACK (MOST RECENT CALL LAST):        FILE "/USERS/~~~~~/ORIGINAL_LOGGER.PY", LINE 64, IN <MODULE>       RAISE("RAISE!")     TYPEERROR: EXCEPTIONS MUST DERIVE FROM BASEEXCEPTION

logger.exceptionによって traceback を出力すると、traceback に関数は適用されません
下の方法だと適用されています
ここでも、大文字にする機能と、改行をタブに変換する機能が動作しているのを確認できます

    def test(logger: Logger):
        logger.debug("logger debug in test")
        logger.info("logger info in test")
        logger.warning("logger warn in test")
        logger.error("logger error in test")

        try:
            raise("raise in test!")
        except:
            logger.exception("logger exception in test", exc_info=True)
            logger.error("except log in test\n" + traceback.format_exc())
    
    test(logger)

    # 2023-08-03 12:22:42,820 __main__:71 test [INFO]: LOGGER INFO IN TEST
    # 2023-08-03 12:22:42,820 __main__:72 test [WARNING]: LOGGER WARN IN TEST
    # 2023-08-03 12:22:42,820 __main__:73 test [ERROR]: LOGGER ERROR IN TEST
    # 2023-08-03 12:22:42,820 __main__:78 test [ERROR]: LOGGER EXCEPTION IN TEST
    # Traceback (most recent call last):
    #   File "/Users/~~~~~/original_logger.py", line 76, in test
    #     raise("raise in test!")
    # TypeError: exceptions must derive from BaseException
    # 2023-08-03 12:22:42,820 __main__:79 test [ERROR]: EXCEPT LOG IN TEST    TRACEBACK (MOST RECENT CALL LAST):        FILE "/USERS/~~~~~/ORIGINAL_LOGGER.PY", LINE 76, IN TEST           RAISE("RAISE IN TEST!")     TYPEERROR: EXCEPTIONS MUST DERIVE FROM BASEEXCEPTION

関数内でも適切に動いています

    logger.info("\\\n")
    logger.info("cat")

    # 2023-08-03 12:22:42,820 __main__:83 <module> [INFO]: 





    # 2023-08-03 12:22:42,820 __main__:84 <module> [INFO]: CATฅ^•ω•^ฅニャー

\\\nを改行5回に変換する機能も無事に動いています
cat | CAT という文字列があったとき、末尾にねこを追加する機能も動作しているようですฅ^•ω•^ฅニャー

ファイルハンドラ

今回は省略しますが、FileHandlerでも適切に関数が適用されていました
もし、FileとStreamで別々の関数を適用したい場合は、2つFormatterを用意すればよいと思います

まとめ

これでloggerを便利に活用できます!!

参考文献

Pythonでprintを卒業してログ出力をいい感じにする - Qiita
https://qiita.com/FukuharaYohei/items/92795107032c8c0bfd19
[Tips] Pythonのロガーでユーザーが定義したキーを使って値を出力する方法 | DevelopersIO
https://dev.classmethod.jp/articles/python-logger-kwarg-extra/

0
1
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
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?