logger¶
Pulls diagnostic logs off a connected device via adb shell logcat, in dump-and-exit
mode — a snapshot of what's already in the buffer, not a live tail.
adb_automation_mcp.modules.logger.tools
¶
Module-level, statically-introspectable tool functions for the logger module.
Kept as plain top-level functions, never closures, so that documentation tooling and the registry meta-test can both introspect them directly.
clear_logs(ctx: Context, serial: str, buffer: LogBuffer = 'main') -> ClearLogsResult
async
¶
Clear a device's log buffer: adb shell logcat -c -b BUFFER.
Pairs with read_logs for the standard debugging workflow: clear, reproduce the issue, then read_logs to see only what happened since. Wipes diagnostic history, not user/app data, so this is "write" rather than "destructive".
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
serial
|
str
|
The target device's adb serial (see list_connected_devices). |
required |
buffer
|
LogBuffer
|
Which ring buffer to clear. |
'main'
|
Returns:
| Type | Description |
|---|---|
ClearLogsResult
|
The serial and buffer cleared. |
Error handling
Propagates the same way most tools do (unlike check_adb_available): if the adb binary itself can't be found or is unresponsive, or the serial doesn't match a connected device, that surfaces as an actual tool error.
Example
Called with serial="emulator-5554", buffer="main". A typical response:
{
"status": "success",
"message": "Cleared main log buffer on emulator-5554.",
"data": {"serial": "emulator-5554", "buffer": "main"},
"error": null
}
Source code in src/adb_automation_mcp/modules/logger/tools.py
98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 | |
get_log_buffer_size(ctx: Context, serial: str, buffer: LogBuffer = 'main') -> LogBufferSize
async
¶
Report a log buffer's ring size and usage: adb shell logcat -g -b BUFFER.
Cheap, read-only introspection — useful before deciding max_lines for read_logs, or whether to clear_logs first.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
serial
|
str
|
The target device's adb serial (see list_connected_devices). |
required |
buffer
|
LogBuffer
|
Which ring buffer to report on. |
'main'
|
Returns:
| Type | Description |
|---|---|
LogBufferSize
|
The serial, buffer, and logd's raw size/usage text for it. |
Error handling
Propagates the same way most tools do (unlike check_adb_available): if
the adb binary itself can't be found or is unresponsive, or the
serial doesn't match a connected device, that surfaces as an actual
tool error. Verified live that an unknown buffer name (or one this
device's build doesn't have, e.g. "kernel" on a user build) fails
with "Unknown -b buffer '
Example
Called with serial="emulator-5554", buffer="crash". A typical response:
{
"status": "success",
"message": "Log buffer size for crash on emulator-5554: crash: ring buffer is 2 MiB (512 KiB consumed, 22 KiB readable), max entry is 5120 B, max payload is 4068 B",
"data": {
"serial": "emulator-5554",
"buffer": "crash",
"output": "crash: ring buffer is 2 MiB (512 KiB consumed, 22 KiB readable), max entry is 5120 B, max payload is 4068 B"
},
"error": null
}
Source code in src/adb_automation_mcp/modules/logger/tools.py
137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 | |
read_logs(ctx: Context, serial: str, buffer: LogBuffer = 'main', max_lines: int = 200, min_priority: LogPriority | None = None, tag: str | None = None, pid: int | None = None) -> LogDump
async
¶
Dump recent device logs: adb shell logcat -d -v threadtime -t N -b BUFFER.
Dump-and-exit, not a live tail: this returns a snapshot of what's already in the buffer, not a stream of future log lines.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
serial
|
str
|
The target device's adb serial (see list_connected_devices). |
required |
buffer
|
LogBuffer
|
Which ring buffer to read. "kernel" only exists on userdebug/eng builds and "security" only under Device Owner — either can legitimately fail on a given device. |
'main'
|
max_lines
|
int
|
How many of the most recent raw lines to read, before any tag/priority filter is applied (see Error handling below for why that ordering matters). Must be a positive integer — 0 or negative raises INVALID_ARGUMENT. |
200
|
min_priority
|
LogPriority | None
|
Minimum priority to include ("V" < "D" < "I" < "W" < "E" < "F" < "S"=silent). None means no filter (everything). |
None
|
tag
|
str | None
|
If set, show only this tag (at min_priority or above) and silence every other tag — verified live this is genuinely exclusive, not additive with min_priority's usual "everything at this level or above" meaning. |
None
|
pid
|
int | None
|
If set, show only log lines from this process ID. |
None
|
Returns:
| Type | Description |
|---|---|
LogDump
|
The raw logcat text for the requested buffer, plus the serial and buffer requested. |
Error handling
Propagates the same way most tools do (unlike check_adb_available): if the adb binary itself can't be found or is unresponsive, or the serial doesn't match a connected device, that surfaces as an actual tool error. A max_lines below 1 raises INVALID_ARGUMENT. Verified live that max_lines truncates the RAW buffer first, then filters — a narrow tag/priority filter combined with a small max_lines can come back with empty output (data, not an error) even though matching lines exist further back in the buffer; increase max_lines if that happens.
Example
Called with serial="emulator-5554", buffer="main", max_lines=3. A typical response:
{
"status": "success",
"message": "Read 3 log line(s) from main on emulator-5554.",
"data": {
"serial": "emulator-5554",
"buffer": "main",
"output": "--------- beginning of main\n08-26 08:24:26.364 462 11426 E audio_hw_generic_caremu: mixer_thread_loop error[-1] writing data to pcm\n..."
},
"error": null
}
Source code in src/adb_automation_mcp/modules/logger/tools.py
27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 | |
read_package_logs(ctx: Context, serial: str, package: str, buffer: LogBuffer = 'main', max_lines: int = 200, min_priority: LogPriority | None = None) -> PackageLogDump
async
¶
Dump recent logs for one package: resolves its PID via adb shell pidof
-s PACKAGE, then adb shell logcat -d -v threadtime -t N -b BUFFER
--pid=PID.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
serial
|
str
|
The target device's adb serial (see list_connected_devices). |
required |
package
|
str
|
Exact package/process name (e.g. "com.android.systemui") — pidof requires an exact match, not a substring. |
required |
buffer
|
LogBuffer
|
Which ring buffer to read. |
'main'
|
max_lines
|
int
|
How many of the most recent raw lines to read before any priority filter and the pid filter are applied. Same truncate-then-filter ordering caveat as read_logs. Must be a positive integer — 0 or negative raises INVALID_ARGUMENT. |
200
|
min_priority
|
LogPriority | None
|
Minimum priority to include. None means no filter. |
None
|
Returns:
| Type | Description |
|---|---|
PackageLogDump
|
The serial, package, resolved pid, and matching logcat text. |
Error handling
Propagates the same way most tools do (unlike check_adb_available): if the adb binary itself can't be found or is unresponsive, or the serial doesn't match a connected device, that surfaces as an actual tool error. Verified live that pidof exits 1 with no output both when the package isn't installed and when it's installed but not currently running — adb can't tell those apart, so this raises a single "no running process for package" error either way rather than guessing which. Also verified live that logcat only accepts one --pid per call, so a multi-process package (isolated services, separate process names) only returns its primary process's logs — a known limitation, not a bug.
Example
Called with serial="emulator-5554", package="com.android.systemui". A typical response:
{
"status": "success",
"message": "Read 4 log line(s) for com.android.systemui (pid 19861) on emulator-5554.",
"data": {
"serial": "emulator-5554",
"package": "com.android.systemui",
"pid": 19861,
"output": "--------- beginning of main\n08-26 08:24:32.118 19861 19934 D SystemUI: ...\n..."
},
"error": null
}
Source code in src/adb_automation_mcp/modules/logger/tools.py
181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 | |
start_log_session(ctx: Context, serial: str, name: str, buffer: LogBuffer = 'main', min_priority: LogPriority | None = None, tag: str | None = None, pid: int | None = None, package: str | None = None) -> LogSessionHandle
async
¶
Start a log-capture session: anchors on the device's current log position, to be replayed later by stop_log_session.
Not a live tail — this doesn't stream logs anywhere while the session is open. It records where the buffer currently is (plus whatever filter is given here), and stop_log_session later dumps everything matching that filter from that point to when it's called. See stop_log_session for how the captured logs actually reach a file. Filtering is configured here, not at stop time, so this API shape would still work if session capture ever became a true live background tail (whose filter flags have to be fixed when the process starts, not changed mid-stream) — a checkpoint- and-dump session's filter is applied at replay time either way, so the two are equivalent for now, but only one of them stays correct if that changes later.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
serial
|
str
|
The target device's adb serial (see list_connected_devices). |
required |
name
|
str
|
A human-readable label for this session (e.g. "wifi_repro") — purely for your own tracking across concurrent sessions; not interpreted by adb or validated for uniqueness. |
required |
buffer
|
LogBuffer
|
Which ring buffer to anchor on and later capture from. |
'main'
|
min_priority
|
LogPriority | None
|
Minimum priority to include at stop time. None means no filter (everything). Same semantics as read_logs's min_priority. |
None
|
tag
|
str | None
|
If set, only this tag (at min_priority or above) is captured and every other tag is silenced. Same semantics as read_logs's tag. |
None
|
pid
|
int | None
|
If set, only this process's logs are captured. Mutually exclusive with package — set at most one. |
None
|
package
|
str | None
|
If set, resolves to that package's PID the same way
read_package_logs does (exact match via |
None
|
Returns:
| Type | Description |
|---|---|
LogSessionHandle
|
A session_id to pass to stop_log_session, plus the serial, buffer, name, and (if pid or package was given) the pid that will be filtered on. |
Error handling
Propagates the same way most tools do (unlike check_adb_available): if the adb binary itself can't be found or is unresponsive, or the serial doesn't match a connected device, that surfaces as an actual tool error. Passing both pid and package is a tool error (ambiguous), not success:false data. package resolution can fail the same way read_package_logs's does: no running process for that package is a tool error, not a session that silently captures nothing. An empty buffer at start time is not an error — the session is still created; stop_log_session captures whatever's present at stop-time instead of filtering by timestamp.
Example
Called with serial="emulator-5554", name="wifi_repro", tag="WifiManager". A typical response:
{
"status": "success",
"message": "Started log session 'wifi_repro' (3fa1f2b0-...) on main@emulator-5554.",
"data": {
"session_id": "3fa1f2b0-...",
"serial": "emulator-5554",
"buffer": "main",
"name": "wifi_repro",
"pid": null,
"package": null
},
"error": null
}
Source code in src/adb_automation_mcp/modules/logger/tools.py
246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 | |
stop_log_session(ctx: Context, session_id: str, local_path: str) -> LogSessionResult
async
¶
Stop a log-capture session and write everything logged since start_log_session to a file on the host running this server.
local_path is a host filesystem path, not a device path — it's resolved against the server's configured local_root and must stay inside it (see Error handling). The captured text depends on the device's ring buffer not having wrapped past the session's start point — fine for a normal debugging session, not a hard guarantee for a very long or very high-volume one.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
session_id
|
str
|
The id returned by start_log_session. |
required |
local_path
|
str
|
Where to write the captured log text, relative to (or, if absolute, still required to resolve inside) the server's configured local_root. |
required |
Returns:
| Type | Description |
|---|---|
LogSessionResult
|
The session_id, serial, buffer, name, pid/package (if the session was filtered by one), the resolved local_path actually written, how many lines were captured, and the session's duration in seconds. |
Error handling
session_id must refer to a session that's still open — an unknown or already-stopped id is a tool error, not success:false data. Sessions are held in memory only, for the server process's lifetime; they don't expire on their own. local_path is checked before any device round-trip: if the server has no local_root configured at all, or local_path resolves outside it (including via ".." or an absolute path elsewhere on the host), the call is refused rather than writing anywhere — there is no default local_root; an operator must set ADB_AUTOMATION_LOCAL_ROOT explicitly. Beyond that, this propagates the same way most tools do: adb being unreachable or the session's serial no longer being connected surfaces as an actual tool error.
Example
Called with session_id="3fa1f2b0-...", local_path="session1.log". A typical response:
{
"status": "success",
"message": "Wrote 148 log line(s) from session 'wifi_repro' (3fa1f2b0-...) to /var/adb-logs/session1.log.",
"data": {
"session_id": "3fa1f2b0-...",
"serial": "emulator-5554",
"buffer": "main",
"name": "wifi_repro",
"pid": null,
"package": null,
"local_path": "/var/adb-logs/session1.log",
"line_count": 148,
"duration_s": 42.7
},
"error": null
}
Source code in src/adb_automation_mcp/modules/logger/tools.py
333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 | |