Tracking Android app metrics

When I joined Monzo I was keen to keep a track of metrics that would help us keep a handle on the app’s size and method count. I set up a shell script on our CI to upload the numbers to StatHat each time we merged a change to our develop
branch. This was great in theory, but not visible enough to be actually useful - in fact, one of the stats stopped uploading properly some months ago and we didn’t even notice.
We recently started using Danger and I thought it would be a great opportunity to surface these numbers, so we could actually see the impact of each change being merged into the app.
Step 1 - Upload stats when merging into develop
The StatHat docs are really helpful here, there are many ways to upload a stat so pick your favourite. I went with Ruby.
Uploading the apk size is pretty simple once you’ve found the right path to it.
#!/usr/bin/env ruby | |
require 'rubygems' | |
require 'stathat' | |
def apk_size() | |
File.size("app/build/outputs/apk/flavour/debug/app-flavour-debug.apk") | |
end | |
StatHat::SyncAPI.ez_post_value("apksize", "YOUR_EZKEY", apk_size()) |
The method count is tricker - we’ve use this plugin on our build which outputs a CSV with the method counts and it’s been working perfectly. I just needed to whip up some command line magic to extract the right number ✨
def method_count() | |
# Ignore the first line of the CSV and take the 1st column | |
`tail -1 app/build/outputs/dexcount/flavourDebug.csv | cut -d ',' -f1`.to_i | |
end |
How/where you run this script will depend on your setup - we use CircleCI.
- run: | |
name: Upload APK size/method count statistics to StatHat (only runs on develop) | |
command: | | |
if [ ${CIRCLE_BRANCH} = 'develop' ]; then bundle exec upload_stats.rb; fi |
Step 2 - Retrieve stats from develop
Next up, we need to be able to retrieve the stats we’ve uploaded to compare the latest develop against what we have locally. This was trickier, as you can only retrieve raw data points from StatHat, so we need to filter down all the points and get the most recently uploaded stat.
# Retrieve most recently uploaded size of apk on develop by their id | |
# All stats: https://www.stathat.com/x/ACCESSTOKEN/statlist | |
def apk_size_develop() | |
get_stat("https://www.stathat.com/x/ACCESSTOKEN/data/ID") | |
end | |
# Helper, get most recent stat from StatHat by url | |
def get_stat(url) | |
uri = URI.parse(url) | |
response = Net::HTTP.get_response(uri) | |
# Api returns an array of points with time and value, filter out 0 values and take the last | |
JSON.parse(response.body)[0]['points'].select { |time| time['value'] != 0}.map { |time| time['value'] }.last() || 0 | |
end |
Step 3 - Comment on pull request with changes
Finally, we need to put it all together. We retrieve the apk size from the local branch and compare it against the what it is on develop. Danger runs on CI for all branches (except develop, master and release-*) and will warn us by commenting on the pull request if the app size has changed by more than half a MB.
require 'humanize-bytes' | |
apk_size = apk_size() # Apk size from local branch | |
apk_size_develop = apk_size_develop() # Apk size from stats uploaded to StatHat | |
difference = Humanize::Byte.new(apk_size - apk_size_develop) | |
warn "APK size has changed! Now: %.2fMb; on develop: %.2fMb. Difference: %0.2fKb" % [Humanize::Byte.new(apk_size).to_m.value, Humanize::Byte.new(apk_size_develop).to_m.value, difference.to_k.value] if difference.to_k.value.abs > 512 |
Originally I had it showing a warning if the apk size didn’t exactly match, but that meant it posted on every PR. We felt that if it posts on every change, it will likely start to get ignored - so instead set an allowable range.
That’s it! It’s been running for the past week and is working really well so far.
If you enjoyed reading this post, you can find me on twitter @emmaguy