{"id":15056885,"url":"https://github.com/lbirchler/pyflow","last_synced_at":"2026-01-04T01:38:25.219Z","repository":{"id":255613574,"uuid":"852564553","full_name":"lbirchler/pyflow","owner":"lbirchler","description":"BCC based tool to trace function call/return hierarchy of Python scripts and processes","archived":false,"fork":false,"pushed_at":"2024-09-05T03:05:00.000Z","size":12,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-03-18T08:21:23.576Z","etag":null,"topics":["bcc","debugging","ebpf","tracing"],"latest_commit_sha":null,"homepage":"","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/lbirchler.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2024-09-05T02:58:33.000Z","updated_at":"2024-09-05T03:13:38.000Z","dependencies_parsed_at":null,"dependency_job_id":"e6ce39ed-b20b-445c-872f-d9a733306e6e","html_url":"https://github.com/lbirchler/pyflow","commit_stats":null,"previous_names":["lbirchler/pyflow"],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lbirchler%2Fpyflow","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lbirchler%2Fpyflow/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lbirchler%2Fpyflow/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lbirchler%2Fpyflow/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/lbirchler","download_url":"https://codeload.github.com/lbirchler/pyflow/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":254567253,"owners_count":22092738,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["bcc","debugging","ebpf","tracing"],"created_at":"2024-09-24T21:57:42.513Z","updated_at":"2026-01-04T01:38:25.177Z","avatar_url":"https://github.com/lbirchler.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"# pyflow\n---\n\nBCC based tool to trace function call/return hierarchy of Python scripts and processes.\n\nInitially created to debug packages that ship with PYC-only files.\n\n## Requirements\n- [BCC](https://github.com/iovisor/bcc/blob/master/INSTALL.md)\n\n## Usage\n```\nusage: pyflow.py [-h] [-p PID] [-c CMD] [-f [FILES ...]] [-F [FUNCS ...]] [-t TMP_DIR] [-v]\n\nTrace function call/return hierarchy of Python scripts and processes.\n\noptions:\n  -h, --help            show this help message and exit\n  -p PID, --pid PID     Process ID to trace.\n  -c CMD, --cmd CMD     Command to execute and trace. Enclose in quotes if the command has multiple arguments.\n  -f [FILES ...], --files [FILES ...]\n                        Filename filters. Only trace functions in these files. Relative paths are allowed.\n  -F [FUNCS ...], --funcs [FUNCS ...]\n                        Function filters. Only trace these function calls.\n  -t TMP_DIR, --tmp-dir TMP_DIR\n                        Temporary script directory. Only used when tracing a command (--cmd).\n  -v, --verbose         Verbose mode. Multiple -v options increase the verbosity. The maximum is 3.\n\nexamples:\n  ./pyflow.py -p 1001                           Trace all files and functions in process 1001\n  ./pyflow.py -f /usr/lib/python3.10/socket.py  Only trace functions in socket.py\n  ./pyflow.py -F get_request accept daemon      Trace get_request, accept and daemon functions\n  ./pyflow.py -c \"python3 script.py\"            Run script.py and trace all files and functions\n```\n\n## Examples\n\n### Trace Process\n\nTrace all files and functions in process 695285:\n```\n$ python3 -m http.server 9000 \u0026\u003e /dev/null \u0026\n[1] 695285\n$ sudo ./pyflow.py -p 695285\nTracing function calls in process 695285... Ctrl-C to quit.\nTIME            CPU PID     TID     FILE:FUNC:LINE\n14:54:52.847071 7   695285  695285  \u003c=  /usr/lib/python3.10/selectors.py:select:429\n14:54:52.847452 7   695285  695285  =\u003e  /usr/lib/python3.10/socketserver.py:service_actions:254\n14:54:52.847629 7   695285  695285  \u003c=  /usr/lib/python3.10/socketserver.py:service_actions:260\n14:54:52.847780 7   695285  695285  =\u003e  /usr/lib/python3.10/selectors.py:select:403\n14:54:53.347216 7   695285  695285  \u003c=  /usr/lib/python3.10/selectors.py:select:429\n14:54:53.347467 7   695285  695285  =\u003e  /usr/lib/python3.10/socketserver.py:service_actions:254\n14:54:53.347705 7   695285  695285  \u003c=  /usr/lib/python3.10/socketserver.py:service_actions:260\n14:54:53.347942 7   695285  695285  =\u003e  /usr/lib/python3.10/selectors.py:select:403\n14:54:53.847788 7   695285  695285  \u003c=  /usr/lib/python3.10/selectors.py:select:429\n14:54:53.848038 7   695285  695285  =\u003e  /usr/lib/python3.10/socketserver.py:service_actions:254\n14:54:53.848291 7   695285  695285  \u003c=  /usr/lib/python3.10/socketserver.py:service_actions:260\n14:54:53.848531 7   695285  695285  =\u003e  /usr/lib/python3.10/selectors.py:select:403\n14:54:54.348438 7   695285  695285  \u003c=  /usr/lib/python3.10/selectors.py:select:429\n14:54:54.348701 7   695285  695285  =\u003e  /usr/lib/python3.10/socketserver.py:service_actions:254\n14:54:54.348927 7   695285  695285  \u003c=  /usr/lib/python3.10/socketserver.py:service_actions:260\n14:54:54.349155 7   695285  695285  =\u003e  /usr/lib/python3.10/selectors.py:select:403\n14:54:54.849104 7   695285  695285  \u003c=  /usr/lib/python3.10/selectors.py:select:429\n```\n\n### Trace Command\n\nRun `tests/script.py` and trace all files and functions:\n```\n$ sudo ./pyflow.py -c \"python3 tests/script.py\"\nTracing function calls in process 847740... Ctrl-C to quit.\nTIME            CPU PID     TID     FILE:FUNC:LINE\n13:47:49.674749 11  847740  847740  \u003c=  tests/script.py:function_1:4\n13:47:50.675832 11  847740  847740  \u003c=  tests/script.py:function_2:5\n13:47:50.676016 11  847740  847740  =\u003e  tests/script.py:function_3:6\n13:47:50.676141 11  847740  847740    =\u003e  tests/script.py:function_1:4\n13:47:51.676644 11  847740  847740    \u003c=  tests/script.py:function_1:4\n13:47:51.676779 11  847740  847740    =\u003e  tests/script.py:function_2:5\n13:47:51.676892 11  847740  847740      =\u003e  tests/script.py:function_1:4\n13:47:52.677831 11  847740  847740      \u003c=  tests/script.py:function_1:4\n13:47:53.678781 11  847740  847740    \u003c=  tests/script.py:function_2:5\n13:47:54.679947 11  847740  847740  \u003c=  tests/script.py:function_3:6\n13:47:54.680116 11  847740  847740  \u003c=  tests/script.py:main:8\n13:47:54.680230 11  847740  847740  \u003c=  tests/script.py:\u003cmodule\u003e:11\n```\n\nRun `tests/server.pyc` and trace all files and functions:\n```\n$ sudo ./pyflow.py -c \"python3 tests/server.pyc\"\nTracing function calls in process 696116... Ctrl-C to quit.\nTIME            CPU PID     TID     FILE:FUNC:LINE\n14:59:10.842217 8   696116  696116    \u003c=  /usr/lib/python3.10/socketserver.py:get_request:499\n14:59:10.842499 8   696116  696116    =\u003e  /usr/lib/python3.10/socketserver.py:verify_request:333\n14:59:10.842762 8   696116  696116    \u003c=  /usr/lib/python3.10/socketserver.py:verify_request:339\n14:59:10.843026 8   696116  696116    =\u003e  /usr/lib/python3.10/socketserver.py:process_request:341\n14:59:10.843304 8   696116  696116      =\u003e  /usr/lib/python3.10/socketserver.py:finish_request:358\n14:59:10.843573 8   696116  696116        =\u003e  /usr/lib/python3.10/socketserver.py:__init__:741\n14:59:10.843854 8   696116  696116          =\u003e  /usr/lib/python3.10/socketserver.py:setup:751\n14:59:10.844119 8   696116  696116          \u003c=  /usr/lib/python3.10/socketserver.py:setup:752\n14:59:10.844276 8   696116  696116          =\u003e  tests/server.py:handle:22\n14:59:10.844415 8   696116  696116            =\u003e  tests/server.py:encrypt:14\n14:59:10.844549 8   696116  696116              =\u003e  tests/server.py:generate_key:10\n14:59:10.844684 8   696116  696116                =\u003e  tests/server.py:current_time:7\n14:59:10.844819 8   696116  696116                \u003c=  tests/server.py:current_time:8\n14:59:10.844941 8   696116  696116              \u003c=  tests/server.py:generate_key:12\n```\n\n### Filters\n\nTracing a script or process without any filters will produce a lot of output. Multiple filename and/or function filters can be provided to limit the amount of output.\n\nOnly trace functions in `socket.py` and `threading.py` in process 696517:\n```\n$ sudo ./pyflow.py -p 696517 -f /usr/lib/python3.10/socket.py /usr/lib/python3.10/threading.py\nTracing function calls in process 696517... Ctrl-C to quit.\nTIME            CPU PID     TID     FILE:FUNC:LINE\n15:03:07.945656 4   696517  696517  =\u003e  /usr/lib/python3.10/socket.py:accept:286\n15:03:07.945910 4   696517  696517    =\u003e  /usr/lib/python3.10/socket.py:family:514\n15:03:07.946066 4   696517  696517      =\u003e  /usr/lib/python3.10/socket.py:_intenum_converter:99\n15:03:07.946216 4   696517  696517      \u003c=  /usr/lib/python3.10/socket.py:_intenum_converter:105\n15:03:07.946414 4   696517  696517    \u003c=  /usr/lib/python3.10/socket.py:family:518\n15:03:07.946565 4   696517  696517    =\u003e  /usr/lib/python3.10/socket.py:type:520\n15:03:07.946712 4   696517  696517      =\u003e  /usr/lib/python3.10/socket.py:_intenum_converter:99\n15:03:07.946857 4   696517  696517      \u003c=  /usr/lib/python3.10/socket.py:_intenum_converter:105\n15:03:07.947002 4   696517  696517    \u003c=  /usr/lib/python3.10/socket.py:type:524\n15:03:07.947157 4   696517  696517    =\u003e  /usr/lib/python3.10/socket.py:__init__:220\n15:03:07.947303 4   696517  696517    \u003c=  /usr/lib/python3.10/socket.py:__init__:234\n15:03:07.947441 4   696517  696517  \u003c=  /usr/lib/python3.10/socket.py:accept:300\n15:03:07.947544 4   696517  696517  =\u003e  /usr/lib/python3.10/threading.py:__init__:827\n15:03:07.947638 4   696517  696517    =\u003e  /usr/lib/python3.10/threading.py:_newname:782\n```\n\nOnly trace `accept`, `get_request`, and `daemon` calls in process 696517:\n```\n$ sudo ./pyflow.py -p 696517 -F accept get_request daemon\nTracing function calls in process 696517... Ctrl-C to quit.\nTIME            CPU PID     TID     FILE:FUNC:LINE\n15:05:12.087987 4   696517  696517  =\u003e  /usr/lib/python3.10/socketserver.py:get_request:493\n15:05:12.088274 4   696517  696517    =\u003e  /usr/lib/python3.10/socket.py:accept:286\n15:05:12.088441 4   696517  696517    \u003c=  /usr/lib/python3.10/socket.py:accept:300\n15:05:12.088599 4   696517  696517  \u003c=  /usr/lib/python3.10/socketserver.py:get_request:499\n15:05:12.088754 4   696517  696517  =\u003e  /usr/lib/python3.10/threading.py:daemon:1183\n15:05:12.088906 4   696517  696517  \u003c=  /usr/lib/python3.10/threading.py:daemon:1196\n15:05:12.089055 4   696517  696517  =\u003e  /usr/lib/python3.10/threading.py:daemon:1198\n15:05:12.089204 4   696517  696517  \u003c=  /usr/lib/python3.10/threading.py:daemon:1204\n15:05:12.089352 4   696517  696517  =\u003e  /usr/lib/python3.10/threading.py:daemon:1183\n15:05:12.089500 4   696517  696517  \u003c=  /usr/lib/python3.10/threading.py:daemon:1196\n15:05:12.089824 2   696517  696903  =\u003e  /usr/lib/python3.10/threading.py:daemon:1183\n15:05:12.089984 2   696517  696903  \u003c=  /usr/lib/python3.10/threading.py:daemon:1196\n15:05:14.536164 5   696517  696517  =\u003e  /usr/lib/python3.10/socketserver.py:get_request:493\n15:05:14.536485 5   696517  696517    =\u003e  /usr/lib/python3.10/socket.py:accept:286\n```\n\n**Resources**\n- [Instrumenting CPython with DTrace and SystemTap](https://docs.python.org/3/howto/instrumentation.html)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Flbirchler%2Fpyflow","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Flbirchler%2Fpyflow","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Flbirchler%2Fpyflow/lists"}