iDeviceTail 0.1.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- idevicetail-0.1.0/LICENSE +27 -0
- idevicetail-0.1.0/MANIFEST.in +8 -0
- idevicetail-0.1.0/PKG-INFO +130 -0
- idevicetail-0.1.0/README.md +89 -0
- idevicetail-0.1.0/desktop/iDeviceTail.egg-info/PKG-INFO +130 -0
- idevicetail-0.1.0/desktop/iDeviceTail.egg-info/SOURCES.txt +57 -0
- idevicetail-0.1.0/desktop/iDeviceTail.egg-info/dependency_links.txt +1 -0
- idevicetail-0.1.0/desktop/iDeviceTail.egg-info/entry_points.txt +2 -0
- idevicetail-0.1.0/desktop/iDeviceTail.egg-info/requires.txt +13 -0
- idevicetail-0.1.0/desktop/iDeviceTail.egg-info/top_level.txt +1 -0
- idevicetail-0.1.0/desktop/idevicetail/__init__.py +15 -0
- idevicetail-0.1.0/desktop/idevicetail/__main__.py +4 -0
- idevicetail-0.1.0/desktop/idevicetail/bus.py +89 -0
- idevicetail-0.1.0/desktop/idevicetail/cli.py +426 -0
- idevicetail-0.1.0/desktop/idevicetail/config.py +72 -0
- idevicetail-0.1.0/desktop/idevicetail/device_names.py +94 -0
- idevicetail-0.1.0/desktop/idevicetail/discovery.py +209 -0
- idevicetail-0.1.0/desktop/idevicetail/engine_agent.py +245 -0
- idevicetail-0.1.0/desktop/idevicetail/engine_device.py +425 -0
- idevicetail-0.1.0/desktop/idevicetail/exporter.py +92 -0
- idevicetail-0.1.0/desktop/idevicetail/filesink.py +135 -0
- idevicetail-0.1.0/desktop/idevicetail/manager.py +457 -0
- idevicetail-0.1.0/desktop/idevicetail/models.py +150 -0
- idevicetail-0.1.0/desktop/idevicetail/normalize.py +365 -0
- idevicetail-0.1.0/desktop/idevicetail/server.py +574 -0
- idevicetail-0.1.0/desktop/idevicetail/store.py +236 -0
- idevicetail-0.1.0/desktop/idevicetail/web/app.js +341 -0
- idevicetail-0.1.0/desktop/idevicetail/web/index.html +111 -0
- idevicetail-0.1.0/desktop/idevicetail/web/styles.css +146 -0
- idevicetail-0.1.0/docs/ARCHITECTURE.md +110 -0
- idevicetail-0.1.0/docs/COMPATIBILITY.md +52 -0
- idevicetail-0.1.0/docs/FEASIBILITY.md +177 -0
- idevicetail-0.1.0/docs/GUIDE.md +453 -0
- idevicetail-0.1.0/docs/PROTOCOL.md +117 -0
- idevicetail-0.1.0/docs/SETUP-DESKTOP.md +93 -0
- idevicetail-0.1.0/docs/SETUP-iOS.md +101 -0
- idevicetail-0.1.0/docs/TESTPLAN.md +49 -0
- idevicetail-0.1.0/docs/TROUBLESHOOTING.md +92 -0
- idevicetail-0.1.0/ios/IDeviceTailAgent/Sources/AgentModel.swift +68 -0
- idevicetail-0.1.0/ios/IDeviceTailAgent/Sources/ContentView.swift +79 -0
- idevicetail-0.1.0/ios/IDeviceTailAgent/Sources/IDeviceTailAgentApp.swift +13 -0
- idevicetail-0.1.0/ios/IDeviceTailAgent/Sources/Info.plist +35 -0
- idevicetail-0.1.0/ios/IDeviceTailAgent/project.yml +33 -0
- idevicetail-0.1.0/ios/IDeviceTailKit/Package.swift +25 -0
- idevicetail-0.1.0/ios/IDeviceTailKit/Sources/IDeviceTailKit/FrameCodec.swift +42 -0
- idevicetail-0.1.0/ios/IDeviceTailKit/Sources/IDeviceTailKit/HostBrowser.swift +45 -0
- idevicetail-0.1.0/ios/IDeviceTailKit/Sources/IDeviceTailKit/LogForwarder.swift +166 -0
- idevicetail-0.1.0/ios/IDeviceTailKit/Sources/IDeviceTailKit/LogRecord.swift +75 -0
- idevicetail-0.1.0/ios/IDeviceTailKit/Sources/IDeviceTailKit/LogStreamClient.swift +212 -0
- idevicetail-0.1.0/ios/IDeviceTailKit/Sources/IDeviceTailKit/OSLogStoreReader.swift +91 -0
- idevicetail-0.1.0/ios/IDeviceTailKit/Tests/IDeviceTailKitTests/FrameCodecTests.swift +43 -0
- idevicetail-0.1.0/ios/IDeviceTailKit/Tests/IDeviceTailKitTests/LogRecordTests.swift +39 -0
- idevicetail-0.1.0/ios/README.md +46 -0
- idevicetail-0.1.0/pyproject.toml +69 -0
- idevicetail-0.1.0/scripts/provision-device.ps1 +24 -0
- idevicetail-0.1.0/scripts/run.ps1 +23 -0
- idevicetail-0.1.0/scripts/setup-desktop.ps1 +35 -0
- idevicetail-0.1.0/scripts/setup-desktop.sh +24 -0
- idevicetail-0.1.0/setup.cfg +4 -0
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 iDeviceTail contributors
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
22
|
+
|
|
23
|
+
---
|
|
24
|
+
|
|
25
|
+
NOTE: This project optionally invokes `pymobiledevice3` (https://github.com/doronz88/pymobiledevice3),
|
|
26
|
+
which is licensed GPL-3.0. iDeviceTail calls it as a separate process via its public CLI and does not
|
|
27
|
+
link or embed its code. Installing that dependency is the user's choice and subject to its own license.
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
include LICENSE README.md
|
|
2
|
+
recursive-include desktop/idevicetail/web *.html *.js *.css
|
|
3
|
+
recursive-include docs *.md
|
|
4
|
+
recursive-include ios *.swift *.plist *.yml Package.swift README.md
|
|
5
|
+
graft scripts
|
|
6
|
+
global-exclude __pycache__ *.py[cod] *.sqlite *.sqlite-* .DS_Store
|
|
7
|
+
prune data
|
|
8
|
+
prune .venv
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: iDeviceTail
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Wireless log collection from your own iOS/iPadOS devices — system logs via pymobiledevice3 + an app-log agent, in one live web viewer. No cable.
|
|
5
|
+
Author: Rushabh Shah
|
|
6
|
+
License: MIT
|
|
7
|
+
Project-URL: Homepage, https://github.com/Rushabh5000/iDeviceTail
|
|
8
|
+
Project-URL: Repository, https://github.com/Rushabh5000/iDeviceTail
|
|
9
|
+
Project-URL: Documentation, https://github.com/Rushabh5000/iDeviceTail/tree/main/docs
|
|
10
|
+
Project-URL: Issues, https://github.com/Rushabh5000/iDeviceTail/issues
|
|
11
|
+
Keywords: ios,ipados,iphone,ipad,logs,syslog,console,oslog,os_log,logging,pymobiledevice3,wireless,developer-tools,debugging,crash-reports,sysdiagnose,bonjour
|
|
12
|
+
Classifier: Development Status :: 4 - Beta
|
|
13
|
+
Classifier: Environment :: Console
|
|
14
|
+
Classifier: Environment :: Web Environment
|
|
15
|
+
Classifier: Intended Audience :: Developers
|
|
16
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
17
|
+
Classifier: Operating System :: OS Independent
|
|
18
|
+
Classifier: Programming Language :: Python :: 3
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
20
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
21
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
22
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
23
|
+
Classifier: Topic :: Software Development :: Debuggers
|
|
24
|
+
Classifier: Topic :: System :: Logging
|
|
25
|
+
Classifier: Topic :: System :: Monitoring
|
|
26
|
+
Requires-Python: >=3.10
|
|
27
|
+
Description-Content-Type: text/markdown
|
|
28
|
+
License-File: LICENSE
|
|
29
|
+
Requires-Dist: aiohttp<4,>=3.9
|
|
30
|
+
Requires-Dist: zeroconf>=0.132
|
|
31
|
+
Requires-Dist: aiosqlite>=0.19
|
|
32
|
+
Provides-Extra: device
|
|
33
|
+
Requires-Dist: pymobiledevice3>=4.14; extra == "device"
|
|
34
|
+
Provides-Extra: dev
|
|
35
|
+
Requires-Dist: pytest>=8; extra == "dev"
|
|
36
|
+
Requires-Dist: pytest-asyncio>=0.23; extra == "dev"
|
|
37
|
+
Requires-Dist: ruff>=0.5; extra == "dev"
|
|
38
|
+
Requires-Dist: build>=1; extra == "dev"
|
|
39
|
+
Requires-Dist: twine>=5; extra == "dev"
|
|
40
|
+
Dynamic: license-file
|
|
41
|
+
|
|
42
|
+
# iDeviceTail — wireless iOS/iPadOS log collection
|
|
43
|
+
|
|
44
|
+
[](https://github.com/Rushabh5000/iDeviceTail/actions/workflows/ci.yml)
|
|
45
|
+
[](LICENSE)
|
|
46
|
+
[](pyproject.toml)
|
|
47
|
+
|
|
48
|
+
<!-- Add the PyPI badges after the first `v*` tag publishes the package:
|
|
49
|
+
[](https://pypi.org/project/idevicetail/)
|
|
50
|
+
[](https://pypi.org/project/idevicetail/) -->
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
Collect and view logs from **your own** iPhones/iPads over Wi‑Fi, with **no cable during normal
|
|
54
|
+
operation**. One desktop app (Python, cross‑platform) fuses two capture engines into a single
|
|
55
|
+
live viewer:
|
|
56
|
+
|
|
57
|
+
| Engine | What it gets | Cable ever? | iOS setup | Works on |
|
|
58
|
+
|--------|--------------|-------------|-----------|----------|
|
|
59
|
+
| **A — Device engine** (`pymobiledevice3`) | Real **system logs** (all processes), crash reports, sysdiagnose | **One‑time USB pair + Trust**, then wireless | Enable Wi‑Fi sync + Developer Mode | macOS = full · Windows/Linux = full for iOS ≤ 17.3, partial (syslog only) for iOS 17.4+ over Wi‑Fi |
|
|
60
|
+
| **B — Agent engine** (Swift app + SDK) | The **agent app's own logs** + logs of any app that links `IDeviceTailKit` | **Never** (cable only to sideload the app once on Windows) | Install the app, tap Start | Any stock iOS, no pairing, no Developer Mode |
|
|
61
|
+
|
|
62
|
+
> **Read [`docs/FEASIBILITY.md`](docs/FEASIBILITY.md) first.** iOS does **not** give third‑party
|
|
63
|
+
> software the system‑log firehose. Engine A uses Apple's *supported* device‑debug channel
|
|
64
|
+
> (lockdown `syslog_relay` / `os_trace_relay`, the same one Console.app and `log stream` use) and
|
|
65
|
+
> therefore inherits Apple's pairing + Developer Mode requirements. Engine B is 100% App‑sandbox
|
|
66
|
+
> legal but only sees its own process. The tool ships both and merges them.
|
|
67
|
+
|
|
68
|
+
> 📖 **Full step‑by‑step setup + run guide (phone *and* desktop): [`docs/GUIDE.md`](docs/GUIDE.md).**
|
|
69
|
+
|
|
70
|
+
## Quick start
|
|
71
|
+
|
|
72
|
+
**Windows:** double‑click **`start.bat`**. First run makes a venv, installs, launches the
|
|
73
|
+
server and opens the web UI. That's the only "command".
|
|
74
|
+
|
|
75
|
+
**macOS/Linux (or manual):**
|
|
76
|
+
```bash
|
|
77
|
+
python -m venv .venv && . .venv/bin/activate # Windows: .venv\Scripts\activate
|
|
78
|
+
pip install -e ".[device]" # from a checkout
|
|
79
|
+
# or: pip install "idevicetail[device]" # from PyPI
|
|
80
|
+
python -m idevicetail serve # opens http://localhost:3017 in your browser
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
> **Use Python 3.10–3.13** (not 3.14 yet — `pymobiledevice3`'s C‑ext deps have no 3.14 wheels).
|
|
84
|
+
> The app‑log agent (Engine B) works on any 3.10+.
|
|
85
|
+
|
|
86
|
+
**Everything else is buttons in the browser** — no more commands:
|
|
87
|
+
|
|
88
|
+
| In the UI | Does |
|
|
89
|
+
|---|---|
|
|
90
|
+
| device card → **▶ Start** / **os_trace** | begin/stop a wireless system‑log stream (Engine A) |
|
|
91
|
+
| toolbar **Keyword filter + OK**, level/process/subsystem/source pickers | live filtering of a huge stream |
|
|
92
|
+
| **⬇ Export view** | save the currently filtered lines |
|
|
93
|
+
| **📂 Open file** | open / reveal / download the always‑on "real‑time file" (`data/sessions/realtime-*.log` + `.ndjson`) |
|
|
94
|
+
| **🗑 Clear** / **Pause** / **follow** | manage the view |
|
|
95
|
+
| device card → **Setup** | one‑time USB provisioning (Pair · Wi‑Fi sync · Developer Mode) without touching a terminal |
|
|
96
|
+
| device card → **Crashes** / **Sysdiag** | pull crash reports / trigger a sysdiagnose |
|
|
97
|
+
|
|
98
|
+
A CLI still exists for scripting (`idevicetail discover | stream | crash-pull | export …`) but you never need it for normal use.
|
|
99
|
+
|
|
100
|
+
## Repository layout
|
|
101
|
+
|
|
102
|
+
```
|
|
103
|
+
iDeviceTail/
|
|
104
|
+
├── docs/ Feasibility report, architecture, protocol, compatibility, setup, troubleshooting, test plan
|
|
105
|
+
├── desktop/
|
|
106
|
+
│ ├── idevicetail/ Python package: discovery, engines, normalizer, bus, store, aiohttp server, CLI
|
|
107
|
+
│ │ └── web/ Static log‑viewer UI (no build step)
|
|
108
|
+
│ └── tests/ pytest: parsing, framing, dedup, store
|
|
109
|
+
├── ios/
|
|
110
|
+
│ ├── IDeviceTailKit/ Swift Package: OSLogStore reader, Bonjour, framed TCP client, reconnect
|
|
111
|
+
│ └── IDeviceTailAgent/ SwiftUI app that hosts the SDK (XcodeGen project)
|
|
112
|
+
├── scripts/ setup / run / pairing helpers (PowerShell + sh)
|
|
113
|
+
├── start.bat / stop.bat / hub.json project-hub integration
|
|
114
|
+
└── pyproject.toml
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
## Platform support
|
|
118
|
+
|
|
119
|
+
```
|
|
120
|
+
macOS: Full (Engine A wireless incl. iOS 17.4+ firehose via remoted; Engine B; wireless app install)
|
|
121
|
+
Windows: Partial (Engine A: full ≤ iOS 17.3 over Wi-Fi, syslog-only for 17.4+ over Wi-Fi; Engine B full)
|
|
122
|
+
Linux: Partial (same as Windows)
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
See [`docs/COMPATIBILITY.md`](docs/COMPATIBILITY.md) for the capability matrix.
|
|
126
|
+
|
|
127
|
+
## License
|
|
128
|
+
|
|
129
|
+
MIT (this project). Engine A shells out to **pymobiledevice3** (GPL‑3.0) as a separate process;
|
|
130
|
+
it is an optional dependency you install yourself.
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
# iDeviceTail — wireless iOS/iPadOS log collection
|
|
2
|
+
|
|
3
|
+
[](https://github.com/Rushabh5000/iDeviceTail/actions/workflows/ci.yml)
|
|
4
|
+
[](LICENSE)
|
|
5
|
+
[](pyproject.toml)
|
|
6
|
+
|
|
7
|
+
<!-- Add the PyPI badges after the first `v*` tag publishes the package:
|
|
8
|
+
[](https://pypi.org/project/idevicetail/)
|
|
9
|
+
[](https://pypi.org/project/idevicetail/) -->
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
Collect and view logs from **your own** iPhones/iPads over Wi‑Fi, with **no cable during normal
|
|
13
|
+
operation**. One desktop app (Python, cross‑platform) fuses two capture engines into a single
|
|
14
|
+
live viewer:
|
|
15
|
+
|
|
16
|
+
| Engine | What it gets | Cable ever? | iOS setup | Works on |
|
|
17
|
+
|--------|--------------|-------------|-----------|----------|
|
|
18
|
+
| **A — Device engine** (`pymobiledevice3`) | Real **system logs** (all processes), crash reports, sysdiagnose | **One‑time USB pair + Trust**, then wireless | Enable Wi‑Fi sync + Developer Mode | macOS = full · Windows/Linux = full for iOS ≤ 17.3, partial (syslog only) for iOS 17.4+ over Wi‑Fi |
|
|
19
|
+
| **B — Agent engine** (Swift app + SDK) | The **agent app's own logs** + logs of any app that links `IDeviceTailKit` | **Never** (cable only to sideload the app once on Windows) | Install the app, tap Start | Any stock iOS, no pairing, no Developer Mode |
|
|
20
|
+
|
|
21
|
+
> **Read [`docs/FEASIBILITY.md`](docs/FEASIBILITY.md) first.** iOS does **not** give third‑party
|
|
22
|
+
> software the system‑log firehose. Engine A uses Apple's *supported* device‑debug channel
|
|
23
|
+
> (lockdown `syslog_relay` / `os_trace_relay`, the same one Console.app and `log stream` use) and
|
|
24
|
+
> therefore inherits Apple's pairing + Developer Mode requirements. Engine B is 100% App‑sandbox
|
|
25
|
+
> legal but only sees its own process. The tool ships both and merges them.
|
|
26
|
+
|
|
27
|
+
> 📖 **Full step‑by‑step setup + run guide (phone *and* desktop): [`docs/GUIDE.md`](docs/GUIDE.md).**
|
|
28
|
+
|
|
29
|
+
## Quick start
|
|
30
|
+
|
|
31
|
+
**Windows:** double‑click **`start.bat`**. First run makes a venv, installs, launches the
|
|
32
|
+
server and opens the web UI. That's the only "command".
|
|
33
|
+
|
|
34
|
+
**macOS/Linux (or manual):**
|
|
35
|
+
```bash
|
|
36
|
+
python -m venv .venv && . .venv/bin/activate # Windows: .venv\Scripts\activate
|
|
37
|
+
pip install -e ".[device]" # from a checkout
|
|
38
|
+
# or: pip install "idevicetail[device]" # from PyPI
|
|
39
|
+
python -m idevicetail serve # opens http://localhost:3017 in your browser
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
> **Use Python 3.10–3.13** (not 3.14 yet — `pymobiledevice3`'s C‑ext deps have no 3.14 wheels).
|
|
43
|
+
> The app‑log agent (Engine B) works on any 3.10+.
|
|
44
|
+
|
|
45
|
+
**Everything else is buttons in the browser** — no more commands:
|
|
46
|
+
|
|
47
|
+
| In the UI | Does |
|
|
48
|
+
|---|---|
|
|
49
|
+
| device card → **▶ Start** / **os_trace** | begin/stop a wireless system‑log stream (Engine A) |
|
|
50
|
+
| toolbar **Keyword filter + OK**, level/process/subsystem/source pickers | live filtering of a huge stream |
|
|
51
|
+
| **⬇ Export view** | save the currently filtered lines |
|
|
52
|
+
| **📂 Open file** | open / reveal / download the always‑on "real‑time file" (`data/sessions/realtime-*.log` + `.ndjson`) |
|
|
53
|
+
| **🗑 Clear** / **Pause** / **follow** | manage the view |
|
|
54
|
+
| device card → **Setup** | one‑time USB provisioning (Pair · Wi‑Fi sync · Developer Mode) without touching a terminal |
|
|
55
|
+
| device card → **Crashes** / **Sysdiag** | pull crash reports / trigger a sysdiagnose |
|
|
56
|
+
|
|
57
|
+
A CLI still exists for scripting (`idevicetail discover | stream | crash-pull | export …`) but you never need it for normal use.
|
|
58
|
+
|
|
59
|
+
## Repository layout
|
|
60
|
+
|
|
61
|
+
```
|
|
62
|
+
iDeviceTail/
|
|
63
|
+
├── docs/ Feasibility report, architecture, protocol, compatibility, setup, troubleshooting, test plan
|
|
64
|
+
├── desktop/
|
|
65
|
+
│ ├── idevicetail/ Python package: discovery, engines, normalizer, bus, store, aiohttp server, CLI
|
|
66
|
+
│ │ └── web/ Static log‑viewer UI (no build step)
|
|
67
|
+
│ └── tests/ pytest: parsing, framing, dedup, store
|
|
68
|
+
├── ios/
|
|
69
|
+
│ ├── IDeviceTailKit/ Swift Package: OSLogStore reader, Bonjour, framed TCP client, reconnect
|
|
70
|
+
│ └── IDeviceTailAgent/ SwiftUI app that hosts the SDK (XcodeGen project)
|
|
71
|
+
├── scripts/ setup / run / pairing helpers (PowerShell + sh)
|
|
72
|
+
├── start.bat / stop.bat / hub.json project-hub integration
|
|
73
|
+
└── pyproject.toml
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
## Platform support
|
|
77
|
+
|
|
78
|
+
```
|
|
79
|
+
macOS: Full (Engine A wireless incl. iOS 17.4+ firehose via remoted; Engine B; wireless app install)
|
|
80
|
+
Windows: Partial (Engine A: full ≤ iOS 17.3 over Wi-Fi, syslog-only for 17.4+ over Wi-Fi; Engine B full)
|
|
81
|
+
Linux: Partial (same as Windows)
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
See [`docs/COMPATIBILITY.md`](docs/COMPATIBILITY.md) for the capability matrix.
|
|
85
|
+
|
|
86
|
+
## License
|
|
87
|
+
|
|
88
|
+
MIT (this project). Engine A shells out to **pymobiledevice3** (GPL‑3.0) as a separate process;
|
|
89
|
+
it is an optional dependency you install yourself.
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: iDeviceTail
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Wireless log collection from your own iOS/iPadOS devices — system logs via pymobiledevice3 + an app-log agent, in one live web viewer. No cable.
|
|
5
|
+
Author: Rushabh Shah
|
|
6
|
+
License: MIT
|
|
7
|
+
Project-URL: Homepage, https://github.com/Rushabh5000/iDeviceTail
|
|
8
|
+
Project-URL: Repository, https://github.com/Rushabh5000/iDeviceTail
|
|
9
|
+
Project-URL: Documentation, https://github.com/Rushabh5000/iDeviceTail/tree/main/docs
|
|
10
|
+
Project-URL: Issues, https://github.com/Rushabh5000/iDeviceTail/issues
|
|
11
|
+
Keywords: ios,ipados,iphone,ipad,logs,syslog,console,oslog,os_log,logging,pymobiledevice3,wireless,developer-tools,debugging,crash-reports,sysdiagnose,bonjour
|
|
12
|
+
Classifier: Development Status :: 4 - Beta
|
|
13
|
+
Classifier: Environment :: Console
|
|
14
|
+
Classifier: Environment :: Web Environment
|
|
15
|
+
Classifier: Intended Audience :: Developers
|
|
16
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
17
|
+
Classifier: Operating System :: OS Independent
|
|
18
|
+
Classifier: Programming Language :: Python :: 3
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
20
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
21
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
22
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
23
|
+
Classifier: Topic :: Software Development :: Debuggers
|
|
24
|
+
Classifier: Topic :: System :: Logging
|
|
25
|
+
Classifier: Topic :: System :: Monitoring
|
|
26
|
+
Requires-Python: >=3.10
|
|
27
|
+
Description-Content-Type: text/markdown
|
|
28
|
+
License-File: LICENSE
|
|
29
|
+
Requires-Dist: aiohttp<4,>=3.9
|
|
30
|
+
Requires-Dist: zeroconf>=0.132
|
|
31
|
+
Requires-Dist: aiosqlite>=0.19
|
|
32
|
+
Provides-Extra: device
|
|
33
|
+
Requires-Dist: pymobiledevice3>=4.14; extra == "device"
|
|
34
|
+
Provides-Extra: dev
|
|
35
|
+
Requires-Dist: pytest>=8; extra == "dev"
|
|
36
|
+
Requires-Dist: pytest-asyncio>=0.23; extra == "dev"
|
|
37
|
+
Requires-Dist: ruff>=0.5; extra == "dev"
|
|
38
|
+
Requires-Dist: build>=1; extra == "dev"
|
|
39
|
+
Requires-Dist: twine>=5; extra == "dev"
|
|
40
|
+
Dynamic: license-file
|
|
41
|
+
|
|
42
|
+
# iDeviceTail — wireless iOS/iPadOS log collection
|
|
43
|
+
|
|
44
|
+
[](https://github.com/Rushabh5000/iDeviceTail/actions/workflows/ci.yml)
|
|
45
|
+
[](LICENSE)
|
|
46
|
+
[](pyproject.toml)
|
|
47
|
+
|
|
48
|
+
<!-- Add the PyPI badges after the first `v*` tag publishes the package:
|
|
49
|
+
[](https://pypi.org/project/idevicetail/)
|
|
50
|
+
[](https://pypi.org/project/idevicetail/) -->
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
Collect and view logs from **your own** iPhones/iPads over Wi‑Fi, with **no cable during normal
|
|
54
|
+
operation**. One desktop app (Python, cross‑platform) fuses two capture engines into a single
|
|
55
|
+
live viewer:
|
|
56
|
+
|
|
57
|
+
| Engine | What it gets | Cable ever? | iOS setup | Works on |
|
|
58
|
+
|--------|--------------|-------------|-----------|----------|
|
|
59
|
+
| **A — Device engine** (`pymobiledevice3`) | Real **system logs** (all processes), crash reports, sysdiagnose | **One‑time USB pair + Trust**, then wireless | Enable Wi‑Fi sync + Developer Mode | macOS = full · Windows/Linux = full for iOS ≤ 17.3, partial (syslog only) for iOS 17.4+ over Wi‑Fi |
|
|
60
|
+
| **B — Agent engine** (Swift app + SDK) | The **agent app's own logs** + logs of any app that links `IDeviceTailKit` | **Never** (cable only to sideload the app once on Windows) | Install the app, tap Start | Any stock iOS, no pairing, no Developer Mode |
|
|
61
|
+
|
|
62
|
+
> **Read [`docs/FEASIBILITY.md`](docs/FEASIBILITY.md) first.** iOS does **not** give third‑party
|
|
63
|
+
> software the system‑log firehose. Engine A uses Apple's *supported* device‑debug channel
|
|
64
|
+
> (lockdown `syslog_relay` / `os_trace_relay`, the same one Console.app and `log stream` use) and
|
|
65
|
+
> therefore inherits Apple's pairing + Developer Mode requirements. Engine B is 100% App‑sandbox
|
|
66
|
+
> legal but only sees its own process. The tool ships both and merges them.
|
|
67
|
+
|
|
68
|
+
> 📖 **Full step‑by‑step setup + run guide (phone *and* desktop): [`docs/GUIDE.md`](docs/GUIDE.md).**
|
|
69
|
+
|
|
70
|
+
## Quick start
|
|
71
|
+
|
|
72
|
+
**Windows:** double‑click **`start.bat`**. First run makes a venv, installs, launches the
|
|
73
|
+
server and opens the web UI. That's the only "command".
|
|
74
|
+
|
|
75
|
+
**macOS/Linux (or manual):**
|
|
76
|
+
```bash
|
|
77
|
+
python -m venv .venv && . .venv/bin/activate # Windows: .venv\Scripts\activate
|
|
78
|
+
pip install -e ".[device]" # from a checkout
|
|
79
|
+
# or: pip install "idevicetail[device]" # from PyPI
|
|
80
|
+
python -m idevicetail serve # opens http://localhost:3017 in your browser
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
> **Use Python 3.10–3.13** (not 3.14 yet — `pymobiledevice3`'s C‑ext deps have no 3.14 wheels).
|
|
84
|
+
> The app‑log agent (Engine B) works on any 3.10+.
|
|
85
|
+
|
|
86
|
+
**Everything else is buttons in the browser** — no more commands:
|
|
87
|
+
|
|
88
|
+
| In the UI | Does |
|
|
89
|
+
|---|---|
|
|
90
|
+
| device card → **▶ Start** / **os_trace** | begin/stop a wireless system‑log stream (Engine A) |
|
|
91
|
+
| toolbar **Keyword filter + OK**, level/process/subsystem/source pickers | live filtering of a huge stream |
|
|
92
|
+
| **⬇ Export view** | save the currently filtered lines |
|
|
93
|
+
| **📂 Open file** | open / reveal / download the always‑on "real‑time file" (`data/sessions/realtime-*.log` + `.ndjson`) |
|
|
94
|
+
| **🗑 Clear** / **Pause** / **follow** | manage the view |
|
|
95
|
+
| device card → **Setup** | one‑time USB provisioning (Pair · Wi‑Fi sync · Developer Mode) without touching a terminal |
|
|
96
|
+
| device card → **Crashes** / **Sysdiag** | pull crash reports / trigger a sysdiagnose |
|
|
97
|
+
|
|
98
|
+
A CLI still exists for scripting (`idevicetail discover | stream | crash-pull | export …`) but you never need it for normal use.
|
|
99
|
+
|
|
100
|
+
## Repository layout
|
|
101
|
+
|
|
102
|
+
```
|
|
103
|
+
iDeviceTail/
|
|
104
|
+
├── docs/ Feasibility report, architecture, protocol, compatibility, setup, troubleshooting, test plan
|
|
105
|
+
├── desktop/
|
|
106
|
+
│ ├── idevicetail/ Python package: discovery, engines, normalizer, bus, store, aiohttp server, CLI
|
|
107
|
+
│ │ └── web/ Static log‑viewer UI (no build step)
|
|
108
|
+
│ └── tests/ pytest: parsing, framing, dedup, store
|
|
109
|
+
├── ios/
|
|
110
|
+
│ ├── IDeviceTailKit/ Swift Package: OSLogStore reader, Bonjour, framed TCP client, reconnect
|
|
111
|
+
│ └── IDeviceTailAgent/ SwiftUI app that hosts the SDK (XcodeGen project)
|
|
112
|
+
├── scripts/ setup / run / pairing helpers (PowerShell + sh)
|
|
113
|
+
├── start.bat / stop.bat / hub.json project-hub integration
|
|
114
|
+
└── pyproject.toml
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
## Platform support
|
|
118
|
+
|
|
119
|
+
```
|
|
120
|
+
macOS: Full (Engine A wireless incl. iOS 17.4+ firehose via remoted; Engine B; wireless app install)
|
|
121
|
+
Windows: Partial (Engine A: full ≤ iOS 17.3 over Wi-Fi, syslog-only for 17.4+ over Wi-Fi; Engine B full)
|
|
122
|
+
Linux: Partial (same as Windows)
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
See [`docs/COMPATIBILITY.md`](docs/COMPATIBILITY.md) for the capability matrix.
|
|
126
|
+
|
|
127
|
+
## License
|
|
128
|
+
|
|
129
|
+
MIT (this project). Engine A shells out to **pymobiledevice3** (GPL‑3.0) as a separate process;
|
|
130
|
+
it is an optional dependency you install yourself.
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
LICENSE
|
|
2
|
+
MANIFEST.in
|
|
3
|
+
README.md
|
|
4
|
+
pyproject.toml
|
|
5
|
+
desktop/iDeviceTail.egg-info/PKG-INFO
|
|
6
|
+
desktop/iDeviceTail.egg-info/SOURCES.txt
|
|
7
|
+
desktop/iDeviceTail.egg-info/dependency_links.txt
|
|
8
|
+
desktop/iDeviceTail.egg-info/entry_points.txt
|
|
9
|
+
desktop/iDeviceTail.egg-info/requires.txt
|
|
10
|
+
desktop/iDeviceTail.egg-info/top_level.txt
|
|
11
|
+
desktop/idevicetail/__init__.py
|
|
12
|
+
desktop/idevicetail/__main__.py
|
|
13
|
+
desktop/idevicetail/bus.py
|
|
14
|
+
desktop/idevicetail/cli.py
|
|
15
|
+
desktop/idevicetail/config.py
|
|
16
|
+
desktop/idevicetail/device_names.py
|
|
17
|
+
desktop/idevicetail/discovery.py
|
|
18
|
+
desktop/idevicetail/engine_agent.py
|
|
19
|
+
desktop/idevicetail/engine_device.py
|
|
20
|
+
desktop/idevicetail/exporter.py
|
|
21
|
+
desktop/idevicetail/filesink.py
|
|
22
|
+
desktop/idevicetail/manager.py
|
|
23
|
+
desktop/idevicetail/models.py
|
|
24
|
+
desktop/idevicetail/normalize.py
|
|
25
|
+
desktop/idevicetail/server.py
|
|
26
|
+
desktop/idevicetail/store.py
|
|
27
|
+
desktop/idevicetail/web/app.js
|
|
28
|
+
desktop/idevicetail/web/index.html
|
|
29
|
+
desktop/idevicetail/web/styles.css
|
|
30
|
+
docs/ARCHITECTURE.md
|
|
31
|
+
docs/COMPATIBILITY.md
|
|
32
|
+
docs/FEASIBILITY.md
|
|
33
|
+
docs/GUIDE.md
|
|
34
|
+
docs/PROTOCOL.md
|
|
35
|
+
docs/SETUP-DESKTOP.md
|
|
36
|
+
docs/SETUP-iOS.md
|
|
37
|
+
docs/TESTPLAN.md
|
|
38
|
+
docs/TROUBLESHOOTING.md
|
|
39
|
+
ios/README.md
|
|
40
|
+
ios/IDeviceTailAgent/project.yml
|
|
41
|
+
ios/IDeviceTailAgent/Sources/AgentModel.swift
|
|
42
|
+
ios/IDeviceTailAgent/Sources/ContentView.swift
|
|
43
|
+
ios/IDeviceTailAgent/Sources/IDeviceTailAgentApp.swift
|
|
44
|
+
ios/IDeviceTailAgent/Sources/Info.plist
|
|
45
|
+
ios/IDeviceTailKit/Package.swift
|
|
46
|
+
ios/IDeviceTailKit/Sources/IDeviceTailKit/FrameCodec.swift
|
|
47
|
+
ios/IDeviceTailKit/Sources/IDeviceTailKit/HostBrowser.swift
|
|
48
|
+
ios/IDeviceTailKit/Sources/IDeviceTailKit/LogForwarder.swift
|
|
49
|
+
ios/IDeviceTailKit/Sources/IDeviceTailKit/LogRecord.swift
|
|
50
|
+
ios/IDeviceTailKit/Sources/IDeviceTailKit/LogStreamClient.swift
|
|
51
|
+
ios/IDeviceTailKit/Sources/IDeviceTailKit/OSLogStoreReader.swift
|
|
52
|
+
ios/IDeviceTailKit/Tests/IDeviceTailKitTests/FrameCodecTests.swift
|
|
53
|
+
ios/IDeviceTailKit/Tests/IDeviceTailKitTests/LogRecordTests.swift
|
|
54
|
+
scripts/provision-device.ps1
|
|
55
|
+
scripts/run.ps1
|
|
56
|
+
scripts/setup-desktop.ps1
|
|
57
|
+
scripts/setup-desktop.sh
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
idevicetail
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
"""iDeviceTail — wireless iOS/iPadOS log collection.
|
|
2
|
+
|
|
3
|
+
Two capture engines feed one normalized log bus:
|
|
4
|
+
|
|
5
|
+
* ``engine_device`` — real system logs / crash reports / sysdiagnose via the
|
|
6
|
+
``pymobiledevice3`` CLI over Wi-Fi (requires a one-time USB pairing + Trust and,
|
|
7
|
+
on iOS 16+, Developer Mode).
|
|
8
|
+
* ``engine_agent`` — app-level logs streamed by the bundled Swift agent app
|
|
9
|
+
(``IDeviceTailKit``) over a framed TCP protocol. No pairing, no cable, no
|
|
10
|
+
Developer Mode; limited to the agent's own process by the iOS sandbox.
|
|
11
|
+
|
|
12
|
+
See ``docs/FEASIBILITY.md`` for exactly what iOS does and does not allow.
|
|
13
|
+
"""
|
|
14
|
+
|
|
15
|
+
__version__ = "0.1.0"
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
"""In-process log fan-out.
|
|
2
|
+
|
|
3
|
+
Every :class:`~idevicetail.models.LogRecord` from either engine is published here.
|
|
4
|
+
Consumers (the WebSocket server, the SQLite writer, exporters) each ``subscribe``
|
|
5
|
+
and get an independent asyncio queue.
|
|
6
|
+
|
|
7
|
+
Backpressure policy: each subscriber queue is bounded. If a consumer falls
|
|
8
|
+
behind, the *oldest* item in that consumer's queue is dropped to make room for
|
|
9
|
+
the newest — a slow browser tab can never stall the capture pipeline. Dropped
|
|
10
|
+
counts are tracked so the UI can show "N lines dropped".
|
|
11
|
+
"""
|
|
12
|
+
|
|
13
|
+
from __future__ import annotations
|
|
14
|
+
|
|
15
|
+
import asyncio
|
|
16
|
+
from collections import deque
|
|
17
|
+
from typing import Any
|
|
18
|
+
|
|
19
|
+
from .models import LogRecord
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
class Subscription:
|
|
23
|
+
__slots__ = ("queue", "dropped", "_bus")
|
|
24
|
+
|
|
25
|
+
def __init__(self, bus: "LogBus", maxsize: int) -> None:
|
|
26
|
+
self.queue: asyncio.Queue[dict[str, Any]] = asyncio.Queue(maxsize=maxsize)
|
|
27
|
+
self.dropped = 0
|
|
28
|
+
self._bus = bus
|
|
29
|
+
|
|
30
|
+
async def get(self) -> dict[str, Any]:
|
|
31
|
+
return await self.queue.get()
|
|
32
|
+
|
|
33
|
+
def close(self) -> None:
|
|
34
|
+
self._bus._subs.discard(self)
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
class LogBus:
|
|
38
|
+
def __init__(self, ring_size: int = 200_000) -> None:
|
|
39
|
+
self._subs: set[Subscription] = set()
|
|
40
|
+
self._ring: deque[dict[str, Any]] = deque(maxlen=ring_size)
|
|
41
|
+
self._seq = 0
|
|
42
|
+
self.total_published = 0
|
|
43
|
+
|
|
44
|
+
# -- producers ---------------------------------------------------------
|
|
45
|
+
def publish(self, rec: LogRecord) -> None:
|
|
46
|
+
self._seq += 1
|
|
47
|
+
rec.seq = self._seq
|
|
48
|
+
wire = rec.to_wire()
|
|
49
|
+
self._ring.append(wire)
|
|
50
|
+
self.total_published += 1
|
|
51
|
+
for sub in list(self._subs):
|
|
52
|
+
_offer(sub, wire)
|
|
53
|
+
|
|
54
|
+
def publish_many(self, recs: list[LogRecord]) -> None:
|
|
55
|
+
for r in recs:
|
|
56
|
+
self.publish(r)
|
|
57
|
+
|
|
58
|
+
# -- consumers -------------------------------------------------------
|
|
59
|
+
def subscribe(self, maxsize: int = 20_000) -> Subscription:
|
|
60
|
+
sub = Subscription(self, maxsize)
|
|
61
|
+
self._subs.add(sub)
|
|
62
|
+
return sub
|
|
63
|
+
|
|
64
|
+
def snapshot(self, limit: int | None = None) -> list[dict[str, Any]]:
|
|
65
|
+
if limit is None or limit >= len(self._ring):
|
|
66
|
+
return list(self._ring)
|
|
67
|
+
return list(self._ring)[-limit:]
|
|
68
|
+
|
|
69
|
+
@property
|
|
70
|
+
def seq(self) -> int:
|
|
71
|
+
return self._seq
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
def _offer(sub: Subscription, wire: dict[str, Any]) -> None:
|
|
75
|
+
try:
|
|
76
|
+
sub.queue.put_nowait(wire)
|
|
77
|
+
return
|
|
78
|
+
except asyncio.QueueFull:
|
|
79
|
+
pass
|
|
80
|
+
# Drop oldest, retry once.
|
|
81
|
+
try:
|
|
82
|
+
sub.queue.get_nowait()
|
|
83
|
+
sub.dropped += 1
|
|
84
|
+
except asyncio.QueueEmpty: # pragma: no cover - race
|
|
85
|
+
pass
|
|
86
|
+
try:
|
|
87
|
+
sub.queue.put_nowait(wire)
|
|
88
|
+
except asyncio.QueueFull: # pragma: no cover - consumer is fully wedged
|
|
89
|
+
sub.dropped += 1
|