[Android development] Get logcat from your app and save it as a file
This article is about how to get log from your app and save it into internal phone’s storage. Then if you want to send it to server or do any others stuff as you aim to.
Why I wrote this? We have a bunch of tools that can help us to track app like Google crashlytics or some third party’s libraries (Just did some Google search). But if you want to completely control the logs and you have your own server to track log, that can tell you what exactly your customer problems. Then you need to implement it yourself.
The basic idea is get log from device using Runtime class (provided by java) and filter log that relate to our app, then read and save it into device’s storage.
Now, let’s move on the implementation part!
I define this article with 2 part,
- Part 1: Thread for running log process
- Part 2: Helper for some extend functions that make easy to use.
Part 1: Thread for running log process
Create LogDumper class as Thread for running our log stuff.
Now, our LogDumper have some params in constructor. Let me explain it:
- pID: Its current app package ID. We’ll use this for filtering out logcat lines that only log from our application. (When we use logcat command, all log, include system log will be shown, and that will annoy our log content)
- logcatPath: Place for saving log files.
Private variables:
- logcatProc: When running Runtime exec method, it return a separate process that executes the specified command. Save it into this variable for reading stream data later.
- reader: Read stream data from locatProc
- outputStream: For writing log into files
command = "logcat | grep \"($pID)\""
clearLogCommand = "logcat -c"
- command: Command for getting logcat log data, the using grep to get only line of log that contain pID.
- clearLogCommand: Clear logcat log content.
Continue reading the below code snippet, you will meet some variable that I haven’t define yet, but don’t worry, I put the complete code at the end of this article.
- maxFileSize: Max log file size
- maxFolderSize: Max log folder size
This 2 variables are used for controlling log content size. And deleteOldestFile will be called if it met 1 of the 2 max size above.
Now, let’s see how the thread run through override fun run:
After combine all above logic, we have the main implementation for run function.
To know exactly what I’ve done, we go through the main flow:
- First, clear the old log content by using clearLogCommand
- Then, execute log command with grep filter
- Read the stream from process which is returned from Runtime class.
- While loop for reading line by line in logcat content.
- Check for file size and folder size to determine create new file or delete the oldest one, then write the log content into file.
At this point, we have done the Thread implementation for read and writing log, next, we’ll create a helper class for using this Thread.
Part 2: Helper for some extend functions that make easy to use.
Create a Result class for return log result.
In the init part, just initialize value for pID, logDumper and logcatPath.
Then we have 2 support function start() and stop() for running logDumper thread.
Now, we have almost done, we can start the log, writing log into file, and we can stop log.
So, how about getting log files? We have it in internal storage. So, just come and get it.
To start getting log file, stop the log process.
Create an output directory and output file for merging all log files, so you don’t have to send all log files, just merge it into a file, then save it into output dir. Then return the file and you get the file. Congratulations!
How to merge it? Here you go
So, we’ve done this article.
Full implementation here!
For your further improve:
- If you are using proguard, then the log file will be obfuscated with class names, function names or some other rules that you apply in. So you can see the document from Android developer page .
- If the app go as product build, then all the log should be disable. For deeper log config, you can try the Timber library.
That’s it. Done!
Thanks for reading!