A Tour of Logcat
The Logcat window in Android Studio acts as a central hub for displaying system and custom messages for apps across Android devices connected via the Android Debug Bridge — ADB.
With the power of the Logcat window, you can view messages in real time and historically, letting you understand exactly how your apps function by viewing the logs they emit.
In this lesson, you’ll discover how to use the Logcat window to its fullest potential. You’ll learn how to:
- Navigate the Logcat window.
- Send custom log messages from your app.
- Customize the Logcat window, making it easier to read.
- Filter your logs.
- Use logs to help you find and fix bugs.
Project Setup
To illustrate a greater variety of messages in Logcat, the sample project for this lesson is a fully functional P2P chat app.
It uses the Ditto SDK to that end. Ditto is a cross-platform P2P SDK that lets two devices communicate using any type of wireless transport — Bluetooth, Wi-Fi, etc. — without an internet connection or cloud back end.
To get the project up and running on your own devices, you’ll need to register for a free developer license.
Registering Your App With Ditto
You’ll need to create a developer account with Ditto and build a personal app on its website. This gives you access to the authentication keys needed for the SDK. In a web browser, navigate to Ditto.live and click Get started. Then, follow the steps to create an account. The simplest way is to sign up with your existing Google account. Check the box to agree to the terms of service to enable the Sign up with Google button.
Complete the steps to create a new app on the Ditto website. Once you do that, you’ll be able to go to the web page for your app to get the unique SDK keys you’ll need for your chat app.
Once you’ve created an account, you’ll see a prompt to create an app on Ditto’s website.
Enter a name for the app, and the URL will automatically be filled out. Typically, you’ll want to use the same or a similar name to your Android app, but it doesn’t matter. Click Create App, and the site takes you to Step 1 of the Quickstart page.
Select Android for the framework. The site will take you to Step 2, which states Install Ditto. The next section covers how to do that. Click Next step; it shows some sample code. Don’t copy it, but note that it shows an appID and a token with the same values as the App ID and Playground Token displayed at the top of the page. You’ll need these keys in the next step.
Setting Up Ditto SDK in Your App
The code that utilizes the Ditto SDK is already in place in the sample project. All you need to do is add your license keys.
Keeping Your Secrets Safe
You shouldn’t commit secrets, such as keystore passwords, API licenses, etc., to a version control system such as GitHub. Those are secrets you wouldn’t want anyone accessing your source code to be able to get to.
You have a few options to avoid pushing your secrets to a repository. A simple but effective way is to have them in a file you don’t commit. Open the Kodeco Chat starter project in Android Studio, and create a new file with the name keys.properties at the project’s root. An easy way to view this is by switching from Android view in Android Studio to Project View. You can open or close this pane by pressing Command-1 on macOS or Alt-1 on Windows/Linux.
Add the following values in your keys.properties file, replacing the values for each variable with the values for your appID and token that you obtained earlier:
DITTO_APP_ID = "replace with your app ID"
DITTO_TOKEN = "replace with your token"
That’s it! Build and run the app to make sure everything works.
Breaking Down the Logcat Window
To become familiar with the Logcat window, you’ll have to produce some logs first.
- Click the debug app icon to debug the app.
- Once the app has launched, in Android Studio, click the Logcat icon. It looks like a little cat. :] You can also expand the Logcat window by clicking View ▸ Tool Windows ▸ Logcat.
- The Logcat pane opens in Android Studio. In the upper-left corner, you can choose which device to see logs from using the Android device selector. If you have multiple Android devices connected via the ADB, you can select which device’s logs to view with this option. On the left side are time stamps for each log, in the middle is the log level, and on the right side is the log message.
- In the upper-right corner is a Filter search bar — this allows filtering the logs displayed based on text or regex. By default, it should have package:mine listed in it.
On the right side of the filter search bar, there’s an x button — click this to clear the filter. Now, you’ll see many more logs — from any app or process running on the device you’re currently viewing the logs for.
Click in the filter search bar again, and start typing “package”. After just a couple of letters, you’ll see many options pop up to choose from, with “package:mine” at the top of the list. Choose this to filter the logs again to just show logs from the app you’re currently debugging.
Your Android device will emit all your system logs if you don’t have this filter selected, even if your active app isn’t producing them. In most cases, you’ll want this filter on.
Scroll through the list of log messages a bit.
Your Android device has produced a bunch of logs; it can be pretty daunting at first sight, as there are so many! You’ll work through it bit by bit.
An Android app can output logs of six different severity levels. When you choose a severity level, all logs of that level or more severe are shown:
- Verbose: The lowest severity level log — you shouldn’t compile these logs into an app outside of development. Choose this filter if you want to see every log level.
- Debug: Logs that are useful only during development. They should be stripped from release builds.
- Info: General informative log message for standard usage. These are intended to be kept in a release environment.
- Warn: Shows possible issues that could become errors. These are always kept in a released app build.
- Error: Logs that emit due to errors in the app. These will be displayed in a release build.
- Assert: Logs that should never be shown. If they are, something has gone critically wrong with the app.
Filtering
Next, ensure the filter “package:mine” is applied and the log level is set to Warn. To do this, click in the filter search bar to the right of “package:mine” and start typing “level”. As you do this, you’ll see various severity levels come up:
Choose level:warn. Setting the log level filter like this tells Logcat only to display logs at the level of Warn or higher. The log levels higher than Warn are Error and Assert.
If the filter removes all the messages, you’ll see the message, “All log entries are hidden by the filter”, along with a Clear filter button.
Logs that are warnings generally appear as an app launches. This is due to the nature of warnings. A program compiles anything that the program doesn’t think is set up perfectly and may cause a future error only once.
The actual warnings you see may vary depending on your device or emulator and other factors. Android Studio also color-codes the warnings by their severity:
With Android updates, most of the existing warnings disappear, and new ones may show up. It takes a keen eye to spot a warning that’s due to your own code; you should fix these as soon as they’re spotted.
Log Messages Explained
Take a detailed look at one log:
Here’s an explanation of the format:
- The date and time that the log was sent.
- The identifier of the process and thread that sent the log.
- The log tag that helps identify where the log came from, usually the class name. See below for a detailed explanation.
- Package ID of the app that sent the log.
- Log priority identifier, e.g., W for Warn, I for Info, etc.
- The log message itself appears last.
This is the format for every log, no matter the log level.
Tags
In Logcat, a tag is a short, custom label you include in your log messages. It acts like a category identifier for your logs. Here’s what tags do:
- Identify origin: The tag helps you understand where the log message originated in your code. You can use the class name, a component name, or any descriptive string as the tag.
- Filtering: Logcat allows you to filter messages based on the tag. This is incredibly useful when dealing with a large volume of logs. You can see only messages with a specific tag, making it easier to focus on a particular part of your app.
- Grouping: Tags help group related logs together. If all your networking calls use the same tag, you can easily see the flow of network activity.
Here are some common practices for tags:
- Using class name: A common convention is to use the class name where the log originated as the tag. This provides good context about the source.
- Descriptive tags: For more complex scenarios, create descriptive tags that indicate the functionality or component involved.
Using tags effectively makes your debugging process in Logcat much more streamlined and efficient. Later, you’ll learn how to create your own custom tags as well as generate your own log messages.
Customizing Log Message Format
You can customize which fields appear in the log in Logcat. Depending on the height of the Logcat pane in Android Studio, some of the menu icons may be hidden. Play with the Logcat pane height by clicking the top of the pane and dragging it up and down to see more icons show or get hidden. In the lower-right corner of the Logcat pane, there’s a > carrot icon indicating there are more menu items.
Mouse over this icon, and you’ll see the hidden menu items in a pop-up.
Click Configure Logcat Formatting Options and then Modify Views to open a window showing all the different formatting options for log messages.
Try turning on and off various options, and click Apply to see how it affects the view of your log messages. When you’re satisfied, click OK to close the configuration window.
Gemini
You can also ask Android Studio to explain in detail the meaning of any message in Logcat.
First, ensure the Gemini availability in your country/territory.
Next, ensure you’re logged in to Google by going to View ▸ Tool Windows ▸ Gemini.
After you sign in to Google and authorize Gemini, right-click on the message, and choose Explain This Log Entry from the context menu:
This will close the Logcat window and open the Gemini AI window, with a prompt automatically generated asking to explain the log message, along with the response from Gemini:
Adding Custom Logs
You can create and post any kind of log message to Logcat. Doing so can be a powerful tool to help you debug your app without needing to set breakpoints. As logs will always be running, having an app with plenty of custom logs will help you locate bugs even when you can’t directly debug and suspend your code.
To send logs to the Logcat, Android has a utility class named Log. You’ll use this class to set your custom log severity levels, tags, and messages.
Open MainActivity.kt, and add the Log import to the top of the file next to all your other imports:
import android.util.Log
Above the MainActivity class declaration, add a new constant variable called TAG, and set the value to MainActivity:
private const val TAG = "MainActivity"
This will be the tag you’ll use for all the custom logs you’ll send within MainActivity. You can, of course, set tags to anything. As a default, it’s best practice to have your custom log tag as the class that has sent the log so you can easily map the location.
Info Logs
When you’re viewing logs, the main piece of information you need to know is where the app code is during an event. To do this, you can decorate your code with Info logs that simply state what has been called.
Underneath onCreate() inside MainActivity, add an override for onResume() and add a custom log inside the method that tells the Logcat that you’ve called this method:
override fun onResume() {
super.onResume()
Log.i(TAG, "onResume() called.")
}
The Log class has a number of different static methods that dictate the logs’ severity level, the same severity levels discussed earlier in this chapter:
-
Log.v(): Verbose -
Log.d(): Debug -
Log.i(): Info -
Log.w(): Warning -
Log.e(): Error
Each method takes a tag and message String parameter as well as an optional Throwable parameter that logs an exception.
Scroll farther down in MainActivity until you get to checkPermissions(). After the declaration of missing in this method, add another info log:
val missing = DittoSyncPermissions(this).missingPermissions()
Log.i(TAG, "Checking permissions for: '$missing'")
Here, you’re again logging the information that you’ve called checkPermissions(). You’re also passing the value of the missing permissions, if any, within your log’s message string. It’s always best to include any relevant information in your logs that may be able to help with debugging your code.
Now, build and run the app again, ensuring you have the Logcat window expanded. Switch the severity level filter to Info. You only want to see the logs of severity level Info and higher right now. Additionally, in the filter, type “MainActivity” to narrow down the log messages to just the ones you created that custom tag for.
You’ll see right away that you’re now getting an “onResume() called” log appear in the Logcat window:
You also see a message similar to this:
Checking permissions for: ‘[Ljava.lang.String;@4957199’
Now, that’s not terribly useful, is it? Right-click this rather cryptic message and ask Gemini to explain it:
Ah! So, actually, the permissions isn’t simply a string, it’s an array of strings. Update the line of code for this log to print out the entire permission string array like so:
Log.i(TAG, "Checking permissions for: '${missing.contentToString()}'")
Also, you want to see what the missing permissions are the first time you run the app. Since you’ve likely built and run the app before, you would’ve already enabled the permissions when the permissions dialogue was shown. Delete the app from your device or emulator by long-pressing the app icon.
Then, select App info from the context menu. In the App info screen, click Uninstall to remove the app.
Build and run again, and check the logs. Now, you see a list of the missing permissions when you first launch the app, and the permissions have never been requested or granted before:
Great, now this is much more informative!
With only sending these couple of additional logs, the Logcat window has become a lot easier to read as, in between the system logs, there are details of what the app is doing at any given time.
Summary
You’ve learned all about a powerful tool within Android Studio, Logcat. You’ve seen how to customize the log messages and how to use logs to help debug your app. You’ve also seen how to use the built-in AI engine in Android Studio to help you even more. Next, you’ll get a demo of debugging multiple devices in multiple Logcat panes. Get your whiskers ready! 😺