Skip to content

Commit

Permalink
Release v0.2.0
Browse files Browse the repository at this point in the history
- TUI feature support
  - Added `tui.py` using `curses` for terminal-based UI.
  - Supports Page Up, Page Down, Home, and End keys for scrolling through trace data.
 - Argument handling for traced scripts:
  - `pyftrace` now supports passing additional arguments to traced scripts in both CLI and TUI modes.
- Cross-platform testing on GitHub Actions
- Swapped short options for `verbose` and `version` flags:
  - `verbose` now uses `-v` (lowercase), and `version` uses `-V` (uppercase).
- Function call parsing logic updated for Windows to handle backslashes in paths.
  • Loading branch information
kangtegong committed Nov 12, 2024
1 parent 4fa0bea commit 0fbdc10
Show file tree
Hide file tree
Showing 9 changed files with 535 additions and 154 deletions.
22 changes: 22 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,27 @@
# Changelog

## [0.2.0] - 2024-11-11

### Added
- TUI support start!
- Added `tui.py` using `curses` for terminal-based UI.
- Supports Page Up, Page Down, Home, and End keys for scrolling through trace data.
- New example script `examples/recursives.py` for testing deep trace depth in TUI.
- Argument handling for traced scripts:
- `pyftrace` now supports passing additional arguments to traced scripts in both CLI and TUI modes.
- Cross-platform testing on GitHub Actions:
- Added workflows for testing on Ubuntu, Windows, and macOS.

### Changed
- Swapped short options for `verbose` and `version` flags:
- `verbose` now uses `-v` (lowercase), and `version` uses `-V` (uppercase).
- Documentation updates:
- README workflow status badges.
- README Installation instructions for Windows users (noting `windows-curses`).

### Fixed
- Function call parsing logic updated for Windows to handle backslashes in paths.

## [0.1.2] - 2024-11-01

### Added
Expand Down
295 changes: 295 additions & 0 deletions README-ko.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,295 @@
# pyftrace

## Introduction

**pyftrace**는 Python 스크립트 내에서 함수 호출을 모니터링할 수 있는 경량 Python 함수 추적 도구입니다. Python 3.12의 `sys.monitoring`을 활용하여 Python 이벤트를 모니터링하고, 모니터링 결과를 기반으로 함수 호출/리턴을 추적합니다. pyftrace를 사용하면 여러 모듈에 걸친 함수 호출을 추적할 수 있고, 호출 계층 구조를 시각적으로 나타낼 수 있으며, 추적 결과 보고서를 생성할 수 있습니다.

![pyftrace-demo](assets/pyftrace-demo.gif)

pyftrace의 주요 기능:

- **함수 호출/반환 추적**: Python 스크립트 및 임포트된 모듈 내의 함수 호출/반환을 모니터링합니다.
- **내장 함수 추적**: `--verbose` 옵션을 사용하여 `print`와 같은 내장 함수를 선택적으로 추적할 수 있습니다.
- **다중 모듈 추적**: 여러 파일에 걸친 함수 추적을 지원합니다.
- **실행 보고서**: `--report` 옵션을 사용하여 함수 실행 시간 및 호출 횟수를 상세히 기록한 보고서를 생성합니다.
- **경로 추적**: `--path` 옵션을 사용하여 추적된 Python 파일의 경로를 추적합니다.
- **TUI 모드**: `tui` 명령을 사용하여 텍스트 사용자 인터페이스(TUI) 모드에서 pyftrace를 실행할 수 있습니다.

```
$ pyftrace --help
usage: pyftrace [options] [tui] script [script_args ...]
pyftrace: Python function tracing tool.
positional arguments:
script Path to the script to run and trace. Specify 'tui' before the script path to run in TUI mode.
options:
-h, --help show this help message and exit
-V, --version Show the version of pyftrace and exit
-v, --verbose Enable built-in and third-party function tracing
-p, --path Show file paths in tracing output
-r, --report Generate a report of function execution times
```

## 사용법

### 요구 사항

- **Python 버전**: pyftrace는 Python 3.12 이상이 필요합니다. Python 3.12에 도입된 새로운 `sys.monitoring` 모듈을 사용하기 때문입니다.

```bash
$ pyftrace [options] /path/to/python/script.py
```

### 설치

```
$ git clone https://github.com/kangtegong/pyftrace.git
$ cd pyftrace
$ pip install -e .
```

또는

```
$ pip install pyftrace
```

> note: 윈도우에서는 windows-curses 설치 필요

### 기본 옵션

- `--report` 또는 `-r`: 스크립트 실행이 끝난 후 함수 실행 시간 및 호출 횟수 보고서를 생성합니다.
- `--verbose` 또는 `-v`: 내장 함수(print, len 등)의 추적을 활성화합니다. 이 옵션 없이 사용될 경우 pyftrace는 사용자 정의 함수만 추적합니다.
- `--path` 또는 `-p`: 추적 출력에 파일 경로를 포함합니다.
- `--help` 또는 `-h`: pyftrace 및 해당 옵션에 대한 도움말 정보를 표시합니다.
- `--version` 또는 `-V`: pyftrace 버전을 출력합니다.

## TUI

pyftrace를 TUI(텍스트 사용자 인터페이스) 모드에서 실행하려면 스크립트 경로 앞에 tui 명령을 사용하세요.

```bash
pyftrace [options] tui path/to/your_script.py
```

### 주요 키

- `` 또는 ``: 한 줄씩 위아래로 스크롤합니다.
- `PgUp` 또는 `PgDn`: 한 페이지씩 위아래로 스크롤합니다.
- `Home` 또는 `End`: 추적의 시작 또는 끝으로 이동합니다.
- `` 또는 ``: 좌우로 수평 스크롤합니다.
- `q`: TUI 모드를 종료합니다.

![tui-demo](assets/tui-demo.gif)

## 예제

examples/ 디렉토리에는 pyftrace를 사용하여 추적할 수 있는 다양한 Python 파일이 포함되어 있습니다.

아래 예제에서는 여러 파일에 걸친 `main_script.py``module_a.py``module_b.py`의 함수를 추적하는 모습이 담겨 있습니다.

```python
# module_a.py
1 def function_a():
2 print("Function A is called.")
3 return "ret_a"
```

```python
# module_b.py
1 def function_b():
2 print("Function B is called.")
3 return "ret_b"
```

```python
# main_script.py
1 from module_a import function_a
2 from module_b import function_b
3
4 def main():
5 result_a = function_a()
6 result_b = function_b()
7 print(f"Results: {result_a}, {result_b}")
8
9 if __name__ == "__main__":
10 main()
```

### 기본 추적

내장 함수나 파일 경로를 포함하지 않고 main_script.py의 함수 호출을 추적하려면:

```
$ pyftrace examples/module_trace/main_script.py
```

출력 결과:
```
Running script: examples/module_trace/main_script.py
Called main from line 10
Called function_a from line 5
Function A is called.
Returning function_a-> ret_a
Called function_b from line 6
Function B is called.
Returning function_b-> ret_b
Results: ret_a, ret_b
Returning main-> None
Returning <module>-> None
```

### `--verbose`로 내장 함수 추적

```
$ pyftrace --verbose examples/module_trace/main_script.py
```

출력 결과:
```
Running script: examples/module_trace/main_script.py
Called main from line 10
Called function_a from line 5
Called print from line 2
Function A is called.
Returning print
Returning function_a-> ret_a
Called function_b from line 6
Called print from line 2
Function B is called.
Returning print
Returning function_b-> ret_b
Called print from line 7
Results: ret_a, ret_b
Returning print
Returning main-> None
Returning <module>-> None
```

### `--path`로 파일 경로 추적

```
$ pyftrace --path examples/module_trace/main_script.py
```

이 경우, 함수가 호출될 때 pyftrace는 함수 추적 결과를 다음 형식으로 출력됩니다:

```
Called {function} @ {defined file path}:{defined line} from {called file path}:{called line}
```

- `{function}`: name of the function being called
- `{defined file path}`: file path where the function is defined (enabled with `--path` option)
- `{defined line}`" line number in the defined file
- `{called line}` line number in the calling file
- `{called file path}` path to the file that contains the calling function (enabled with `--path` option)


출력 결과:
```
Running script: examples/module_trace/main_script.py
Called main@examples/module_trace/main_script.py:4 from examples/module_trace/main_script.py:10
Called function_a@examples/module_trace/module_a.py:1 from examples/module_trace/main_script.py:5
Function A is called.
Returning function_a-> ret_a @ examples/module_trace/module_a.py
Called function_b@examples/module_trace/module_b.py:1 from examples/module_trace/main_script.py:6
Function B is called.
Returning function_b-> ret_b @ examples/module_trace/module_b.py
Results: ret_a, ret_b
Returning main-> None @ examples/module_trace/main_script.py
Returning <module>-> None @ examples/module_trace/main_script.py
```

### 실행 보고서 생성

함수 실행 시간 및 호출 횟수의 요약 보고서를 생성하려면:

```
$ pyftrace --report examples/module_trace/main_script.py
```

출력 결과:
```
Running script: examples/module_trace/main_script.py
Function A is called.
Function B is called.
Results: ret_a, ret_b
Function Name | Total Execution Time | Call Count
---------------------------------------------------------
main | 0.000082 seconds | 1
function_a | 0.000022 seconds | 1
function_b | 0.000008 seconds | 1
```

### `--verbose``--path` 결합

내장 함수를 추적하고 파일 경로를 포함하려면:

```
$ pyftrace --verbose --path examples/module_trace/main_script.py
$ pyftrace -vp examples/module_trace/main_script.py
```

출력 결과:
```
Running script: examples/module_trace/main_script.py
Called main@examples/module_trace/main_script.py:4 from examples/module_trace/main_script.py:10
Called function_a@examples/module_trace/module_a.py:1 from examples/module_trace/main_script.py:5
Called print@builtins from examples/module_trace/module_a.py:2
Function A is called.
Returning print @ examples/module_trace/module_a.py
Returning function_a-> ret_a @ examples/module_trace/module_a.py
Called function_b@examples/module_trace/module_b.py:1 from examples/module_trace/main_script.py:6
Called print@builtins from examples/module_trace/module_b.py:2
Function B is called.
Returning print @ examples/module_trace/module_b.py
Returning function_b-> ret_b @ examples/module_trace/module_b.py
Called print@builtins from examples/module_trace/main_script.py:7
Results: ret_a, ret_b
Returning print @ examples/module_trace/main_script.py
Returning main-> None @ examples/module_trace/main_script.py
Returning <module>-> None @ examples/module_trace/main_script.py
```

### `--verbose``--report` 결합

```
$ pyftrace --verbose --report examples/module_trace/main_script.py
$ pyftrace -vr examples/module_trace/main_script.py
```

출력 결과:
```
Running script: examples/module_trace/main_script.py
Function A is called.
Function B is called.
Results: ret_a, ret_b
Function Name | Total Execution Time | Call Count
---------------------------------------------------------
main | 0.000127 seconds | 1
print | 0.000041 seconds | 3
function_a | 0.000021 seconds | 1
function_b | 0.000016 seconds | 1
```


### 참고
simple-pyftrace.py는 Pycon Korea 2024 발표를 위한 간소화된 pyftrace 스크립트입니다. 약 100줄의 코드로 구성되어 있지만 기능이 제한적입니다.

## LICENESE

MIT

자세한 정보는 [LICENSE](./LICENSE)를 참조하세요.

## See Also

pyftrace에 영감을 준 프로젝트:

- [ftrace](https://www.kernel.org/doc/Documentation/trace/ftrace.txt): 리눅스 커널을 위한 내부 함수 추적 도구.
- [uftrace](https://github.com/namhyung/uftrace): C, C++, Rust 및 Python 프로그램용 함수 호출 추적 도구.
Loading

0 comments on commit 0fbdc10

Please sign in to comment.