01 · Configure filter
Tag filters
Default priority for everything else
App filter
Output format
Buffers
Modifiers
Shell
02 · Generated command


                    
Quick recipes · tap to load

How logcat filtering actually works

adb logcat's filter syntax confuses most people because it works backwards from how most filter systems do. Most filters are "show nothing by default, add what you want." Logcat is "show everything by default, then quiet down what you don't want." Once that flip clicks, the rest of the syntax falls into place.

Priority levels and the cascade

Every log entry has a priority. Lowest to highest: V (verbose), D (debug), I (info), W (warn), E (error), F (fatal). There's also S for silent. S isn't a real log priority. It's a meta-value meaning "show nothing for this tag."

When you write a filter like MyTag:D, you're saying "show MyTag at DEBUG or higher." The priority cascades upward. D includes D, I, W, E, F. W includes W, E, F. S includes nothing. So *:E shows only errors and fatals across every tag, which is typically what you want when hunting for crashes.

The "silence everything else" pattern

Here's the first real gotcha. You might run adb logcat MyTag:V expecting to see only MyTag's logs. You'll see all logs, plus MyTag at verbose. That's because the default priority is verbose. Your MyTag:V filter just also enables MyTag explicitly, which it already was.

The fix is to add *:S at the end: adb logcat MyTag:V *:S. The * is the "all other tags" wildcard. Setting it to S silences everything except what you've explicitly enabled. Now you see only MyTag's logs, at verbose or higher.

Order matters. *:S goes at the end. Earlier filters override later ones for the same tag, but * is the catchall, and it gets evaluated last after all the specific tag filters have been applied.

The -s shortcut

The silence-everything-else pattern is so common that logcat has a shortcut for it: adb logcat -s MyTag MyOtherTag. The -s flag means "silent default, then enable all subsequent tags at verbose." That command is equivalent to adb logcat MyTag:V MyOtherTag:V *:S. The Build Mode above generates the explicit form because it's easier to read. -s is shorter to type but harder to scan at a glance.

Filtering by app process with pidof

Often what you actually want is "show only my app's logs, regardless of which tag they use." The way to do that is filter by process ID:

adb logcat --pid=$(adb shell pidof com.example.app)

The $(adb shell pidof X) part is bash command substitution. It runs the inner command, captures the PID, and substitutes it into the outer command. The whole thing evaluates to something like adb logcat --pid=12345.

The reason to resolve the PID dynamically rather than hard-coding it is that PIDs change every time the app process restarts. Hard-coded PIDs go stale within minutes. Resolving on every run means the same command keeps working across debug sessions without editing.

On Windows PowerShell the equivalent is (adb shell pidof com.example.app): parentheses, no dollar sign. On Windows cmd, dynamic substitution is awkward. You have to run adb shell pidof com.example.app separately and then paste the PID into the second command. The Build Mode above adjusts the syntax depending on which shell you select.

Why threadtime matters

logcat's default output format is brief: D/MyTag(12345): some message. Concise, but missing two crucial fields. There's no timestamp and no thread ID. For any non-trivial debugging, switch to threadtime:

05-08 14:23:15.243  12345 12350 D MyTag: some message

Now you have the date, time (with milliseconds), PID, TID (thread ID), priority, tag, and message. Thread IDs are essential for diagnosing concurrency issues. Without them, you can't tell if "X happened after Y" was a single-thread sequence or a race condition between two threads. Default to threadtime. Switch to brief or tag only when you specifically want less noise.

Buffers

Android maintains separate log buffers. By default logcat reads only the main buffer. There are others worth knowing:

  • main: the default. App and system logs from android.util.Log calls.
  • system: Android framework internal messages, separate from app code.
  • crash: app crashes, fatal exceptions, ANRs. Reading from this buffer is faster than grepping main for "AndroidRuntime: FATAL EXCEPTION."
  • events: structured system events. Used by some monitoring tools, but less useful for typical debugging.
  • radio: telephony and radio stack. Almost never useful unless you work on the Android telephony layer specifically.

Read multiple buffers by repeating -b: adb logcat -b main -b crash.

Things that will trip you up

Tag matching is case-sensitive. OkHttp:V works. okhttp:V just silently shows nothing, and you spend ten minutes thinking your filter is broken before realising the SDK uses Pascal case. Hosts in URLs are case-insensitive on the JVM, but logcat tags are not. Copy-paste the tag from the library's source rather than typing it.

There's no regex support in the built-in filter syntax. The tag filter is exact match. For pattern matching across the message body, pipe through grep: adb logcat -v threadtime | grep -i "exception". That's fine for interactive use but inconvenient for scripted log capture, where you may want to use adb logcat -d (dump) and process the output with whatever pattern matching your tooling supports.

The log buffer can be clogged with hours of stale output if you don't clear it first. Run adb logcat -c before reproducing your bug. Otherwise you're scrolling through unrelated lines looking for the moment your repro fired. The clear is fast and non-destructive. You're not losing anything you'd want.

Multiple connected devices need -s, but in that position -s means something different from the one earlier in this article. adb -s <serial> logcat ... targets a specific device by its serial number (from adb devices). The -s after logcat means "silent default." Same letter, different meaning, different position. Yes, this is annoying.

The last one is more advice than gotcha. Don't run adb logcat without any filters on a noisy device. A modern Android phone produces hundreds of log lines per second from system services running in the background. Bluetooth scanning, location updates, framework chatter, the works. Without a filter, ten seconds of "the part you actually care about" gets buried in ten thousand lines of noise.

Patterns I actually reach for

Hunting a crash: adb logcat -b crash *:E. The dedicated crash buffer is much faster to scan than grepping the main buffer for "FATAL EXCEPTION," and the *:E filter trims anything below ERROR. Good first stop when something's gone wrong and you don't yet have a hypothesis.

Verifying a feature works: adb logcat MyFeatureTag:V *:S -v threadtime. Just the tag I'm working on, at verbose, with timestamps. The threadtime format is what lets me verify ordering between events. Without it, you can't tell which event happened first when two of them fire in the same second.

Debugging a third-party SDK like OkHttp or Firebase Analytics: adb logcat OkHttp:V FA:V *:S. Multiple tags allow-listed, everything else silenced. The tag names are case-sensitive (again) so check the SDK's documentation or source for the exact spelling.

Filing a bug report: adb logcat -d -v threadtime > bug-report.txt. The -d flag dumps the current buffer and exits, so you get a finite file rather than a live stream. Pair it with adb bugreport if you need the full system snapshot for an OEM-specific bug.

Watching my app's process holistically: adb logcat --pid=$(adb shell pidof com.example.app) -v threadtime. Every log line from my process regardless of which tag it uses. Best for verifying that an end-to-end flow does what you expect. You see your code logging, the framework logging, third-party libraries logging, all interleaved in real time.

By Belchior · Last updated · May 2026

Copied