Skip to main content

Periodic stack-trace sampler for Python performance profiling.

Project description

pysttl

pysttl (Python Sampling Thread Trace Logger) は、Python アプリケーションのパフォーマンスのボトルネックを特定するためのスタックトレース定期サンプラーです。SIGALRM を利用して指定間隔ごとに全スレッドのスタックトレースを取得し、JSON Lines 形式でログファイルに追記します。

得られたログを解析することで、どの関数・どの行で時間を費やしているかを統計的に把握できます (poor-man's profiler の発想)。

動作要件

  • Python 3.11 以上
  • POSIX 系 OS (Linux / macOS) — 内部で signal.SIGALRM を使用するため、Windows では動作しません。
  • start() はメインスレッドからのみ呼び出せます (signal.signal() の制約)。
  • signal.SIGALRM / signal.setitimer(ITIMER_REAL, ...) を内部で利用するため、同じシグナル/タイマーを使う他のコードとは併用できません。

インストール

pip install pysttl

ローカルチェックアウトから直接インストールする場合:

pip install .

開発用の追加依存 (ビルド/PyPI アップロード用) も入れる場合:

pip install -e '.[dev]'

使い方

1. コンテキストマネージャ (推奨)

import pysttl

with pysttl.trace():
    do_heavy_work()

ブロックを抜けると自動的に stop() が呼ばれ、SIGALRM ハンドラと setitimer の状態は呼び出し前に復元されます。trace()PYSTTL_ENABLE を見ません(明示的にプロファイルしたいブロック向け)。

2. 関数 API

環境変数 PYSTTL_ENABLE設定されていて、かつ空でない場合にだけ start() がサンプリングを開始します。未設定なら何もせず、例外も発生しません。アプリに pysttl.start() を常時置き、デバッグ実行時だけ PYSTTL_ENABLE=1 のように付与する使い方を想定しています。

ログファイルの親ディレクトリが無い場合は自動作成します。

サンプリング開始に成功した場合、プロセス終了時に atexitstop() が呼ばれるため、stop() は省略できます。

import pysttl

# 例: PYSTTL_ENABLE=1 python app.py
pysttl.start()
do_heavy_work()

パスや間隔を明示する例:

import pysttl

pysttl.start(log_file_path="/tmp/backtrace.log", interval=1.0)
try:
    do_heavy_work()
finally:
    pysttl.stop()

3. デフォルト値の上書き

log_file_pathinterval のデフォルト値はモジュール属性として公開されており、外部から上書き可能です。start() / trace() は呼び出し時にその時点の値を参照します。

import pysttl

pysttl.DEFAULT_LOG_FILE_PATH = "/var/log/myapp/backtrace.log"
pysttl.DEFAULT_INTERVAL = 0.5  # 500ms 間隔でサンプル

# PYSTTL_ENABLE を付与したデバッグ実行時のみ有効
pysttl.start()

引数を明示的に渡した場合はそちらが優先されます。

出力フォーマット

ログは JSON Lines で書き出されます。1 行 = 1 サンプル = その時点の全スレッドのスタックトレースです。

{
  "threads": [
    {
      "backtrace": [
        "<FrameSummary file '/path/to/main.py', line 14 in main>",
        "<FrameSummary file '/path/to/core.py', line 80 in busy_loop>"
      ],
      "datetime": "2026-05-08T21:00:00.123456",
      "thread_name": "MainThread",
      "thread_ident": 140123456789
    }
  ]
}

backtrace は呼び出し元 → 呼び出し先の順 (root -> leaf) に並んでいます。

解析 CLI

pysttl-parsepysttl が出力した JSON Lines ログを解析し、スタックツリーとステップランキングを出力します。

# ファイルを解析して結果を保存
pysttl-parse < /tmp/backtrace.log > log/tree.txt

# パイプ経由でも利用可能
cat /tmp/backtrace.log | pysttl-parse

出力には以下の2セクションが含まれます。

  • ### Stack trace log analysis tree
  • ### Step load ranking

壊れた JSON 行は警告を stderr に出力し、解析は継続します。

API リファレンス

シンボル 種別 説明
pysttl.start(log_file_path=None, interval=None) 関数 PYSTTL_ENABLE が有効なときのみサンプリング開始。それ以外は no-op(例外なし)。None の引数は対応する DEFAULT_* を参照。
pysttl.stop() 関数 サンプリング停止 + SIGALRM ハンドラ復元。未起動なら no-op。
pysttl.trace(log_file_path=None, interval=None) コンテキストマネージャ サンプリングの開始/停止。PYSTTL_ENABLE は不要。
pysttl.DEFAULT_LOG_FILE_PATH 定数 (str) 既定の出力先。初期値 "/tmp/backtrace.log"
pysttl.DEFAULT_INTERVAL 定数 (float) 既定のサンプリング間隔 [秒]。初期値 1.0
pysttl.PYSTTL_ENABLE_ENV 定数 (str) 参照する環境変数名。値は "PYSTTL_ENABLE"

制限事項

  • signal.SIGALRMpysttl が占有するため、signal.alarm()setitimer(ITIMER_REAL, ...) を別途使用するコードと併用できません。
  • シグナルハンドラ内でファイル I/O (JSON シリアライズ + 追記書き込み) を行うため、I/O が遅い環境では実際の処理スレッドを意図せずブロックする可能性があります。本番常用ではなく調査用途を想定しています。
  • start() が既に有効な状態で再度 start() した場合は no-op です。出力先や間隔を変えるときはいったん stop() してから再度 start() してください。

ビルドと公開

# ビルド (sdist + wheel を dist/ に生成)
python -m build

# 動作確認用に別 venv へインストール
pip install dist/pysttl-*.whl

# PyPI へアップロード (要 ~/.pypirc)
twine upload dist/*

uv ユーザーは uv build / uv publish も利用可能です。

ライセンス

MIT License。詳細は pyproject.toml を参照してください。

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

pysttl-0.1.3.tar.gz (7.7 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

pysttl-0.1.3-py3-none-any.whl (8.7 kB view details)

Uploaded Python 3

File details

Details for the file pysttl-0.1.3.tar.gz.

File metadata

  • Download URL: pysttl-0.1.3.tar.gz
  • Upload date:
  • Size: 7.7 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.9.13 {"installer":{"name":"uv","version":"0.9.13"},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

File hashes

Hashes for pysttl-0.1.3.tar.gz
Algorithm Hash digest
SHA256 a1ff71f2c6313b82ad4a8f7cafe4322a6a68cebb7c9c566df43bed6d44c6a1d2
MD5 1d6d4249806b6907c52aec4525c6b828
BLAKE2b-256 126830aa7005bb1808228d8312687d16d74852fa26c9c4ad53868825b102648c

See more details on using hashes here.

File details

Details for the file pysttl-0.1.3-py3-none-any.whl.

File metadata

  • Download URL: pysttl-0.1.3-py3-none-any.whl
  • Upload date:
  • Size: 8.7 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.9.13 {"installer":{"name":"uv","version":"0.9.13"},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

File hashes

Hashes for pysttl-0.1.3-py3-none-any.whl
Algorithm Hash digest
SHA256 b8de8015e4e8a6c01f021503e85bf6d3671b4e5da63d550b6f7759fa98218bc8
MD5 cfdaebf85cab395183c16a3aa42d9021
BLAKE2b-256 8629d3c92c974e0a74a0e6974bcf4a799417b4529f14c9f22f15cf9fee5ece3b

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page