Disallow debug logging in Android release build

Android_Robot_200So I’ve been doing a lot of Android development over the past several months, and came across the question of how to provide debug logging for a debug build of the library/app I’m working on, but to not let those debug logs flow through to the release build.

At first I mistakenly assumed that, hey, it’s a release build, so surely Log.d and Log.v calls won’t show up?  Wrong.  Android release builds don’t care about debug level, they’ll show whatever logging, at whatever logging level you tell it to.

So at first I sat and thought how I could fix the problem.  I came up with a few options:

  1. I could do what the Android Developer guide suggests one does, and comment out all my debug log lines before building a release build.  Ya, right, uh, no.
  2. I could wrap all the debug log lines with if(BuildConfig.DEBUG) { … }, but that felt unnecessarily painful to have to do.
  3. I could create my own Log class, with its own logic on when to actually log (such as a point 2 above, at the very least), and then just call the android.util.Log methods, but that kind of felt like overkill, as surely the expectation to have intelligent logging on Android is not that wrap the existing logging with your own…
  4. I could switch to old familiar Log4J (or Android equivalent); but yuck, that’s _really_ overkill just to get some logging on for an Android library.
  5. I could write some preprocessor and inject it into the gradle build process, that would go and strip out all the debug log calls to Log.v and Log.d, but, well, that felt like something somebody else would have done already (The world being full of lots of clever people and all…)

I then took to Google, and of course came upon several StackOverflow (Good ol’ SO) questions on the problem, and some good solutions.  It took a bit of reading, and finding more questions and answers before I found the exact solution that worked for me.  With one slight small caveat, which I’ll mention later.  Read on to hear about what I ended up using as a solution.

So the answer to my conundrum was ProGuard.  Up to this point I kind of knew what ProGuard was, but never really paid it much attention.

Some assumptions

  • You are using Android Studio release sometime in the recent past, I am working on v2.1.2, I don’t see this solution _not_ working on earlier versions, as long as the gradle build files included some support for ProGuard.
  • Actually, that’s it…

The solution

  1. Add the following lines into your app or library’s proguard-rules.pro file (At the bottom is just fine):
  2. Open your app or library’s build.gradle file, and find the section where the ProGuard configuration is being prepared, the default section looks like this:
  3. (This step is important!) Now change the above proguardFiles line to look like this:

Et voila, that’s it.  When Android Studio kicks off the build process for the release build of your app or library, it will essentially remove any Log.v and Log.d methods it comes across in your code, as part of the gradle build and compilation happens.  (I’m no ProGuard or gradle build process expert, so I might not be explaining this part exactly right, but the idea is there…)

The caveat!

Yes, there is a slight downside here.

The downside is that, due to ProGuard actually removing lines of code during the compilation process, if you end up logging actual stacktraces in your code, the line numbers in stacktrace could end up not matching 100% with the line numbers in your code, as your code still has those log lines in!  This does make tracing the exact spot of a stacktrace be slightly tricky, but this should both not be a problem and not deter you from using this method, as by the time you’re sending out a release, you really shouldn’t have any more stacktraces in your logs anyway. 🙂

Alternatives

During my hunting for a solution, I did come across various incarnations of my initial list of possible solutions, such as this enterprising individual that created his own Log class, this individual that had a similar solution for creating his own Logging class, and even a guy that had the same solution as what I ended up using, ended up updating his answer with an alternative, which was using a logging system called Timber instead of the built-in android.util.Log.  Timber is a clever solution, as it provides a single point of deciding whether it is running in a release or debug build, and either initialises the logging system or not, and leaves all the actual logging code still intact, this the above caveat does not exist.

I chose the simplest solution, which required no code changes, and no additional

Source

The source of my solution was several answers on stackoverflow.com, and the one in particular that pointed me to the ProGuard manual page on sourceforge, specifically the very useful section called “Removing logging code“.  One important step that was missing from the suggested answer, and in fact, has a small little footnote on the ProGuard manual page, is this:

Android SDK revision 20 and higher have a different configuration file for enabling optimization: ${sdk.dir}/tools/proguard/proguard-android-optimize.txt instead of the default ${sdk.dir}/tools/proguard/proguard-android.txt.

Without this (Step 2 and 3 of the solution), the ProGuard rules just don’t get applied.

Finally

Let me know if you’ve had success using the above, or if you’ve come across other solutions for the same problem?

Thanks for reading.

Leave a Reply

Your email address will not be published. Required fields are marked *