dotnet / dotnet/android

Add AdbRunner structured logcat streaming API

Open
#12,085 0 comments 0 reactions 0 assignees View on GitHub
android-tools needs-triage
Dominant language
C#
Stars
2.1k
Forks
579
Avg merge
1d 21h
Merged PRs (30d)
257

Description

## Summary

Add structured `logcat` streaming to `Xamarin.Android.Tools.AdbRunner` so the MAUI DevTools CLI can surface device logs to agents and IDEs without consumers parsing raw `adb logcat` output.

## Context

`adb logcat` is the only way to see app logs from an Android device until the DevFlow agent in the app is up and running. Even after that, system-level logs (ART runtime, app crashes, native binder errors) only appear in `logcat`. The MAUI DevTools CLI and DevFlow skills currently advise raw `adb logcat …` as a fallback — see [maui-labs#197](https://github.com/dotnet/maui-labs/issues/197) audit. We want a typed stream so consumers can filter and emit structured JSON.

## Proposed API

```csharp
namespace Xamarin.Android.Tools;

public partial class AdbRunner
{
/// adb -s logcat [-v threadtime] [-T 'YYYY-MM-DD HH:mm:ss.SSS' | -d]
public virtual IAsyncEnumerable LogcatAsync(
string serial,
LogcatOptions? options = null,
CancellationToken cancellationToken = default);

/// adb -s logcat -c — clear the device log buffer.
public virtual Task ClearLogcatAsync(string serial, CancellationToken cancellationToken = default);
}

public record LogcatOptions(
/// Tag/priority filter pairs. Examples: ("MauiDevFlow","V"), ("DOTNET","I"), ("*","W")
IReadOnlyList? Filters = null,
/// Restrict to a process. When set, runs `adb shell pidof ` to resolve PID once.
string? PackageName = null,
int? Pid = null,
/// `-T `: only entries since this point. Implies `-d` is false.
DateTimeOffset? Since = null,
/// `-d`: dump existing buffer and exit (no streaming).
bool DumpAndExit = false,
/// Buffer to read: main, system, crash, events, all.
LogcatBuffer Buffers = LogcatBuffer.Main | LogcatBuffer.System | LogcatBuffer.Crash);

public record LogcatFilter(string Tag, LogcatLevel Minimum);
public enum LogcatLevel { Verbose, Debug, Info, Warning, Error, Fatal, Silent }

[Flags]
public enum LogcatBuffer { Main = 1, System = 2, Radio = 4, Events = 8, Crash = 16, All = Main | System | Radio | Events | Crash }

public record LogcatEntry(
DateTimeOffset Timestamp,
int Pid,
int Tid,
LogcatLevel Level,
string Tag,
string Message);
```

Implementation notes:
- Use `-v threadtime` format (well-defined columns) and parse line-by-line. Format spec: `MM-DD HH:MM:SS.mmm PID TID L tag: message`.
- The async enumerable yields one `LogcatEntry` per parsed line. Cancellation kills the underlying `adb logcat` process.
- When `PackageName` is set and PID resolution returns nothing, retry once after a short delay (covers app-not-yet-launched). After two failures, throw.
- `ClearLogcatAsync` is separate so streaming can resume from a known point.

## Consumer

- **MAUI DevTools CLI** ([dotnet/maui-labs](https://github.com/dotnet/maui-labs)) — `maui android device logcat [--package …] [--tag …] [--since …] [--json]` with sensible MAUI defaults (tags `MauiDevFlow`, `DOTNET`, `mono-rt`, `ART`, level Info on the rest). See [maui-labs#197](https://github.com/dotnet/maui-labs/issues/197) audit.
- **DevFlow agent debugging** — pre-agent diagnostics (the agent itself emits structured logs via the HTTP API once up; this gap covers the pre-agent window).
- **Integration test fixtures** that need to assert "log line X appeared within Y seconds" without a manual parser.

## Related

- dotnet/android#12071 — Add ADB wrapper (parent issue)
- dotnet/android-tools#305 — pattern reference (ServiceHub-equivalent typed API)
- maui-labs dotnet/android-tools#197 — DevFlow skill audit; current `references/android.md` "Raw fallbacks not yet in `maui` CLI" section

Contributor guide

No contributing guide indexed for this repository

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.