|
| 1 | +# pyftrace |
| 2 | + |
| 3 | +## Introduction |
| 4 | + |
| 5 | +**pyftrace**는 Python 스크립트 내에서 함수 호출을 모니터링할 수 있는 경량 Python 함수 추적 도구입니다. Python 3.12의 `sys.monitoring`을 활용하여 Python 이벤트를 모니터링하고, 모니터링 결과를 기반으로 함수 호출/리턴을 추적합니다. pyftrace를 사용하면 여러 모듈에 걸친 함수 호출을 추적할 수 있고, 호출 계층 구조를 시각적으로 나타낼 수 있으며, 추적 결과 보고서를 생성할 수 있습니다. |
| 6 | + |
| 7 | + |
| 8 | + |
| 9 | +pyftrace의 주요 기능: |
| 10 | + |
| 11 | +- **함수 호출/반환 추적**: Python 스크립트 및 임포트된 모듈 내의 함수 호출/반환을 모니터링합니다. |
| 12 | +- **내장 함수 추적**: `--verbose` 옵션을 사용하여 `print`와 같은 내장 함수를 선택적으로 추적할 수 있습니다. |
| 13 | +- **다중 모듈 추적**: 여러 파일에 걸친 함수 추적을 지원합니다. |
| 14 | +- **실행 보고서**: `--report` 옵션을 사용하여 함수 실행 시간 및 호출 횟수를 상세히 기록한 보고서를 생성합니다. |
| 15 | +- **경로 추적**: `--path` 옵션을 사용하여 추적된 Python 파일의 경로를 추적합니다. |
| 16 | +- **TUI 모드**: `tui` 명령을 사용하여 텍스트 사용자 인터페이스(TUI) 모드에서 pyftrace를 실행할 수 있습니다. |
| 17 | + |
| 18 | +``` |
| 19 | +$ pyftrace --help |
| 20 | +usage: pyftrace [options] [tui] script [script_args ...] |
| 21 | +
|
| 22 | +pyftrace: Python function tracing tool. |
| 23 | +
|
| 24 | +positional arguments: |
| 25 | + script Path to the script to run and trace. Specify 'tui' before the script path to run in TUI mode. |
| 26 | +
|
| 27 | +options: |
| 28 | + -h, --help show this help message and exit |
| 29 | + -V, --version Show the version of pyftrace and exit |
| 30 | + -v, --verbose Enable built-in and third-party function tracing |
| 31 | + -p, --path Show file paths in tracing output |
| 32 | + -r, --report Generate a report of function execution times |
| 33 | +``` |
| 34 | + |
| 35 | +## 사용법 |
| 36 | + |
| 37 | +### 요구 사항 |
| 38 | + |
| 39 | +- **Python 버전**: pyftrace는 Python 3.12 이상이 필요합니다. Python 3.12에 도입된 새로운 `sys.monitoring` 모듈을 사용하기 때문입니다. |
| 40 | + |
| 41 | +```bash |
| 42 | +$ pyftrace [options] /path/to/python/script.py |
| 43 | +``` |
| 44 | + |
| 45 | +### 설치 |
| 46 | + |
| 47 | +``` |
| 48 | +$ git clone https://github.com/kangtegong/pyftrace.git |
| 49 | +$ cd pyftrace |
| 50 | +$ pip install -e . |
| 51 | +``` |
| 52 | + |
| 53 | +또는 |
| 54 | + |
| 55 | +``` |
| 56 | +$ pip install pyftrace |
| 57 | +``` |
| 58 | + |
| 59 | +> note: 윈도우에서는 windows-curses 설치 필요 |
| 60 | +
|
| 61 | + |
| 62 | +### 기본 옵션 |
| 63 | + |
| 64 | +- `--report` 또는 `-r`: 스크립트 실행이 끝난 후 함수 실행 시간 및 호출 횟수 보고서를 생성합니다. |
| 65 | +- `--verbose` 또는 `-v`: 내장 함수(print, len 등)의 추적을 활성화합니다. 이 옵션 없이 사용될 경우 pyftrace는 사용자 정의 함수만 추적합니다. |
| 66 | +- `--path` 또는 `-p`: 추적 출력에 파일 경로를 포함합니다. |
| 67 | +- `--help` 또는 `-h`: pyftrace 및 해당 옵션에 대한 도움말 정보를 표시합니다. |
| 68 | +- `--version` 또는 `-V`: pyftrace 버전을 출력합니다. |
| 69 | + |
| 70 | +## TUI |
| 71 | + |
| 72 | +pyftrace를 TUI(텍스트 사용자 인터페이스) 모드에서 실행하려면 스크립트 경로 앞에 tui 명령을 사용하세요. |
| 73 | + |
| 74 | +```bash |
| 75 | +pyftrace [options] tui path/to/your_script.py |
| 76 | +``` |
| 77 | + |
| 78 | +### 주요 키 |
| 79 | + |
| 80 | +- `↑` 또는 `↓`: 한 줄씩 위아래로 스크롤합니다. |
| 81 | +- `PgUp` 또는 `PgDn`: 한 페이지씩 위아래로 스크롤합니다. |
| 82 | +- `Home` 또는 `End`: 추적의 시작 또는 끝으로 이동합니다. |
| 83 | +- `←` 또는 `→`: 좌우로 수평 스크롤합니다. |
| 84 | +- `q`: TUI 모드를 종료합니다. |
| 85 | + |
| 86 | + |
| 87 | + |
| 88 | +## 예제 |
| 89 | + |
| 90 | +examples/ 디렉토리에는 pyftrace를 사용하여 추적할 수 있는 다양한 Python 파일이 포함되어 있습니다. |
| 91 | + |
| 92 | +아래 예제에서는 여러 파일에 걸친 `main_script.py`는 `module_a.py`와 `module_b.py`의 함수를 추적하는 모습이 담겨 있습니다. |
| 93 | + |
| 94 | +```python |
| 95 | +# module_a.py |
| 96 | + 1 def function_a(): |
| 97 | + 2 print("Function A is called.") |
| 98 | + 3 return "ret_a" |
| 99 | +``` |
| 100 | + |
| 101 | +```python |
| 102 | +# module_b.py |
| 103 | + 1 def function_b(): |
| 104 | + 2 print("Function B is called.") |
| 105 | + 3 return "ret_b" |
| 106 | +``` |
| 107 | + |
| 108 | +```python |
| 109 | +# main_script.py |
| 110 | + 1 from module_a import function_a |
| 111 | + 2 from module_b import function_b |
| 112 | + 3 |
| 113 | + 4 def main(): |
| 114 | + 5 result_a = function_a() |
| 115 | + 6 result_b = function_b() |
| 116 | + 7 print(f"Results: {result_a}, {result_b}") |
| 117 | + 8 |
| 118 | + 9 if __name__ == "__main__": |
| 119 | + 10 main() |
| 120 | +``` |
| 121 | + |
| 122 | +### 기본 추적 |
| 123 | + |
| 124 | +내장 함수나 파일 경로를 포함하지 않고 main_script.py의 함수 호출을 추적하려면: |
| 125 | + |
| 126 | +``` |
| 127 | +$ pyftrace examples/module_trace/main_script.py |
| 128 | +``` |
| 129 | + |
| 130 | +출력 결과: |
| 131 | +``` |
| 132 | +Running script: examples/module_trace/main_script.py |
| 133 | +Called main from line 10 |
| 134 | + Called function_a from line 5 |
| 135 | +Function A is called. |
| 136 | + Returning function_a-> ret_a |
| 137 | + Called function_b from line 6 |
| 138 | +Function B is called. |
| 139 | + Returning function_b-> ret_b |
| 140 | +Results: ret_a, ret_b |
| 141 | +Returning main-> None |
| 142 | +Returning <module>-> None |
| 143 | +``` |
| 144 | + |
| 145 | +### `--verbose`로 내장 함수 추적 |
| 146 | + |
| 147 | +``` |
| 148 | +$ pyftrace --verbose examples/module_trace/main_script.py |
| 149 | +``` |
| 150 | + |
| 151 | +출력 결과: |
| 152 | +``` |
| 153 | +Running script: examples/module_trace/main_script.py |
| 154 | +Called main from line 10 |
| 155 | + Called function_a from line 5 |
| 156 | + Called print from line 2 |
| 157 | +Function A is called. |
| 158 | + Returning print |
| 159 | + Returning function_a-> ret_a |
| 160 | + Called function_b from line 6 |
| 161 | + Called print from line 2 |
| 162 | +Function B is called. |
| 163 | + Returning print |
| 164 | + Returning function_b-> ret_b |
| 165 | + Called print from line 7 |
| 166 | +Results: ret_a, ret_b |
| 167 | + Returning print |
| 168 | +Returning main-> None |
| 169 | +Returning <module>-> None |
| 170 | +``` |
| 171 | + |
| 172 | +### `--path`로 파일 경로 추적 |
| 173 | + |
| 174 | +``` |
| 175 | +$ pyftrace --path examples/module_trace/main_script.py |
| 176 | +``` |
| 177 | + |
| 178 | +이 경우, 함수가 호출될 때 pyftrace는 함수 추적 결과를 다음 형식으로 출력됩니다: |
| 179 | + |
| 180 | +``` |
| 181 | +Called {function} @ {defined file path}:{defined line} from {called file path}:{called line} |
| 182 | +``` |
| 183 | + |
| 184 | +- `{function}`: name of the function being called |
| 185 | +- `{defined file path}`: file path where the function is defined (enabled with `--path` option) |
| 186 | +- `{defined line}`" line number in the defined file |
| 187 | +- `{called line}` line number in the calling file |
| 188 | +- `{called file path}` path to the file that contains the calling function (enabled with `--path` option) |
| 189 | + |
| 190 | + |
| 191 | +출력 결과: |
| 192 | +``` |
| 193 | +Running script: examples/module_trace/main_script.py |
| 194 | +Called main@examples/module_trace/main_script.py:4 from examples/module_trace/main_script.py:10 |
| 195 | + Called function_a@examples/module_trace/module_a.py:1 from examples/module_trace/main_script.py:5 |
| 196 | +Function A is called. |
| 197 | + Returning function_a-> ret_a @ examples/module_trace/module_a.py |
| 198 | + Called function_b@examples/module_trace/module_b.py:1 from examples/module_trace/main_script.py:6 |
| 199 | +Function B is called. |
| 200 | + Returning function_b-> ret_b @ examples/module_trace/module_b.py |
| 201 | +Results: ret_a, ret_b |
| 202 | +Returning main-> None @ examples/module_trace/main_script.py |
| 203 | +Returning <module>-> None @ examples/module_trace/main_script.py |
| 204 | +``` |
| 205 | + |
| 206 | +### 실행 보고서 생성 |
| 207 | + |
| 208 | +함수 실행 시간 및 호출 횟수의 요약 보고서를 생성하려면: |
| 209 | + |
| 210 | +``` |
| 211 | +$ pyftrace --report examples/module_trace/main_script.py |
| 212 | +``` |
| 213 | + |
| 214 | +출력 결과: |
| 215 | +``` |
| 216 | +Running script: examples/module_trace/main_script.py |
| 217 | +Function A is called. |
| 218 | +Function B is called. |
| 219 | +Results: ret_a, ret_b |
| 220 | +
|
| 221 | +Function Name | Total Execution Time | Call Count |
| 222 | +--------------------------------------------------------- |
| 223 | +main | 0.000082 seconds | 1 |
| 224 | +function_a | 0.000022 seconds | 1 |
| 225 | +function_b | 0.000008 seconds | 1 |
| 226 | +``` |
| 227 | + |
| 228 | +### `--verbose`와 `--path` 결합 |
| 229 | + |
| 230 | +내장 함수를 추적하고 파일 경로를 포함하려면: |
| 231 | + |
| 232 | +``` |
| 233 | +$ pyftrace --verbose --path examples/module_trace/main_script.py |
| 234 | +$ pyftrace -vp examples/module_trace/main_script.py |
| 235 | +``` |
| 236 | + |
| 237 | +출력 결과: |
| 238 | +``` |
| 239 | +Running script: examples/module_trace/main_script.py |
| 240 | +Called main@examples/module_trace/main_script.py:4 from examples/module_trace/main_script.py:10 |
| 241 | + Called function_a@examples/module_trace/module_a.py:1 from examples/module_trace/main_script.py:5 |
| 242 | + Called print@builtins from examples/module_trace/module_a.py:2 |
| 243 | +Function A is called. |
| 244 | + Returning print @ examples/module_trace/module_a.py |
| 245 | + Returning function_a-> ret_a @ examples/module_trace/module_a.py |
| 246 | + Called function_b@examples/module_trace/module_b.py:1 from examples/module_trace/main_script.py:6 |
| 247 | + Called print@builtins from examples/module_trace/module_b.py:2 |
| 248 | +Function B is called. |
| 249 | + Returning print @ examples/module_trace/module_b.py |
| 250 | + Returning function_b-> ret_b @ examples/module_trace/module_b.py |
| 251 | + Called print@builtins from examples/module_trace/main_script.py:7 |
| 252 | +Results: ret_a, ret_b |
| 253 | + Returning print @ examples/module_trace/main_script.py |
| 254 | +Returning main-> None @ examples/module_trace/main_script.py |
| 255 | +Returning <module>-> None @ examples/module_trace/main_script.py |
| 256 | +``` |
| 257 | + |
| 258 | +### `--verbose`와 `--report` 결합 |
| 259 | + |
| 260 | +``` |
| 261 | +$ pyftrace --verbose --report examples/module_trace/main_script.py |
| 262 | +$ pyftrace -vr examples/module_trace/main_script.py |
| 263 | +``` |
| 264 | + |
| 265 | +출력 결과: |
| 266 | +``` |
| 267 | +Running script: examples/module_trace/main_script.py |
| 268 | +Function A is called. |
| 269 | +Function B is called. |
| 270 | +Results: ret_a, ret_b |
| 271 | +
|
| 272 | +Function Name | Total Execution Time | Call Count |
| 273 | +--------------------------------------------------------- |
| 274 | +main | 0.000127 seconds | 1 |
| 275 | +print | 0.000041 seconds | 3 |
| 276 | +function_a | 0.000021 seconds | 1 |
| 277 | +function_b | 0.000016 seconds | 1 |
| 278 | +``` |
| 279 | + |
| 280 | + |
| 281 | +### 참고 |
| 282 | +simple-pyftrace.py는 Pycon Korea 2024 발표를 위한 간소화된 pyftrace 스크립트입니다. 약 100줄의 코드로 구성되어 있지만 기능이 제한적입니다. |
| 283 | + |
| 284 | +## LICENESE |
| 285 | + |
| 286 | +MIT |
| 287 | + |
| 288 | +자세한 정보는 [LICENSE](./LICENSE)를 참조하세요. |
| 289 | + |
| 290 | +## See Also |
| 291 | + |
| 292 | +pyftrace에 영감을 준 프로젝트: |
| 293 | + |
| 294 | +- [ftrace](https://www.kernel.org/doc/Documentation/trace/ftrace.txt): 리눅스 커널을 위한 내부 함수 추적 도구. |
| 295 | +- [uftrace](https://github.com/namhyung/uftrace): C, C++, Rust 및 Python 프로그램용 함수 호출 추적 도구. |
0 commit comments