0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

【備忘録】関数の実行終了を通知するデコレータを作った

0
Last updated at Posted at 2025-11-30

はじめに

大規模なデータ分析やLLMのチューニングなどを行う際にプログラムの実行時間は何十時間にも及ぶことがある。byobutmuxなどで実行していると実行の完了に気づけなかったり、予期しないエラーで実行が停止している場合があった。
そこで、プログラムの実行やエラーをdiscordやteams等の普段使っているツールに通知するデコレータを作成し、自作のライブラリ化した。

あくまでも個人で使用するツールの開発備忘録です。もっと良い実装や汎用性の高い実装なども考えられます。

作ったもの

以下のように利用できるデコレータを作成した。 target_functionの実行が完了するかエラーが発生した場合に引数で指定したツールに通知を飛ばす実装である。


@monitoring(platform="teams", webhook_url=WEBHOOK_URL)
def target_function():
    ...

実行完了時に以下のような通知を受け取ることができる。
image.png

デコレータ本体は以下のように実装している。platformごとに送信処理を分けることで必要に応じて様々なプラットフォームを追加することができる。(現在はdiscordとteamsに対応)

import traceback
import time
import requests
from functools import wraps
from typing import Callable, Literal

def monitoring(platform: Literal["discord", "teams"], webhook_url: str) -> Callable:
    """
    関数の実行時間の計測と実行・失敗状況を監視するデコレータ。
    処理終了時およびエラー時に指定されたプラットフォームへ通知を送信する。
    Args:
        platform: 通知先のプラットフォーム. "discord" または "teams" を指定。
        webhook_url: 通知先のWebhook URL.
    Example:
        ```python
        @monitoring(platform="discord", webhook_url="~~~discord_webhook_url~~~")
        def hoge_function():
            ...

        ```

        ```python
        @monitoring(platform="teams", webhook_url="~~~teams_webhook_url~~~")
        def hoge_function():
            ...

        ```

    """
    def _send_discord_message(message: str):
        requests.post(webhook_url, json={"content": message})

    def _send_teams_message(message: str):
        payload = {
            "type": "message",
            "attachments": [
                {
                    "contentType": "application/vnd.microsoft.card.adaptive",
                    "contentUrl": None,
                    "content": {
                        "$schema": "http://adaptivecards.io/schemas/adaptive-card.json",
                        "type": "AdaptiveCard",
                        "version": "1.4",
                        "body": [
                            {
                                "type": "TextBlock",
                                "text": message,
                                "wrap": True,
                            }
                        ],
                    },
                }
            ],
        }
        requests.post(webhook_url, json=payload)

    _send_message_exporter = {
        "discord": _send_discord_message,
        "teams": _send_teams_message,
    }
    
    def decorator(func: Callable) -> Callable:
        @wraps(func)
        def wrapper(*args, **kwargs):
            start_time = time.time()
            try:
                result = func(*args, **kwargs)
                elapsed_time = time.time() - start_time

                hours = int(elapsed_time // 3600)
                minutes = int((elapsed_time % 3600) // 60)
                seconds = int(elapsed_time % 60)
                time_str = f"{hours}時間{minutes}{seconds}"

                message = f"✅ 実行が正常に完了しました\n関数: {func.__name__}\n実行時間: {time_str} ({elapsed_time:.2f}秒)"
                _send_message_exporter[platform](message)

                return result
            except Exception as e:
                elapsed_time = time.time() - start_time

                traceback_str = ''.join(traceback.format_exception(e))
                print(traceback_str)

                hours = int(elapsed_time // 3600)
                minutes = int((elapsed_time % 3600) // 60)
                seconds = int(elapsed_time % 60)
                time_str = f"{hours}時間{minutes}{seconds}"

                message = f"❌ エラーが発生しました: {e}\n関数: {func.__name__}\n実行時間: {time_str} ({elapsed_time:.2f}秒)\nスタックトレース:\n{traceback_str}"
                _send_message_exporter[platform](message)

                raise e
        return wrapper
    return decorator

 

また、github上にライブラリとして公開することによって以下のコマンドで追加することができるようにした。

pip install git+https://you22fy/my_python_utils

今後の展望として、slack, Line等の複数のプラットフォームを追加することを検討している。

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

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?