Skip to content

Instantly share code, notes, and snippets.

@frel
Last active October 23, 2018 21:21
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
Star You must be signed in to star a gist
Save frel/79eda166117f70a7579753a3c670b677 to your computer and use it in GitHub Desktop.
This is an example of how log events can be defined using android resources files.
<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:tools="http://schemas.android.com/tools">
<!-- Log events -->
<integer name="event_item_apply" tools:keep="@integer/item_apply">0</integer>
<integer name="event_item_download" tools:keep="@integer/event_item_download">1</integer>
<integer name="event_item_share" tools:keep="@integer/event_item_share">2</integer>
<integer name="event_item_purchase" tools:keep="@integer/event_item_purchase">3</integer>
<!-- Parameters -->
<integer name="param_uuid" tools:keep="@integer/param_uuid">0</integer>
<integer name="param_ctype" tools:keep="@integer/param_ctype">1</integer>
<integer name="param_title" tools:keep="@integer/param_title">2</integer>
</resources>
package com.subgarden.eventlogging
import android.os.Bundle
import android.support.annotation.IntegerRes
import android.support.v7.app.AppCompatActivity
import android.util.Log
import java.util.*
class MainActivity : AppCompatActivity() {
companion object {
const val TAG = "MainActivity"
// This would be part of the application and global state
private lateinit var eventNameMap: Map<String, Int>
private lateinit var eventIdMap: Map<Int, String>
private lateinit var paramNameMap: Map<String, Int>
private lateinit var paramIdMap: Map<Int, String>
}
interface LogHandler {
fun logEvent(eventId: Int, parameters: Map<Int, String>)
}
class AmplitudeLogHandler : LogHandler {
override fun logEvent(eventId: Int, parameters: Map<Int, String>) {
Log.d(TAG, "Logging ${eventIdMap[eventId]}($eventId)")
parameters.forEach { (key, value) ->
Log.d(TAG, "Parameter: ${paramIdMap[key]}($key)=$value")
}
}
}
private val logHandlers: MutableList<LogHandler> = mutableListOf()
private val amplitudeLogHandler = AmplitudeLogHandler()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
// This could be moved to an annotation processor.
initLogEvents()
initLogParams()
logHandlers.add(amplitudeLogHandler)
// Debug all event KVP
eventNameMap.forEach { (key, value) ->
Log.d(TAG, "$key=$value")
}
// Log a download event
logEvent(R.integer.event_item_download,
R.integer.param_uuid to UUID.randomUUID().toString(),
R.integer.param_ctype to "wallpaper",
R.integer.param_title to "This is a title")
}
fun logEvent(@IntegerRes eventId: Int, vararg parameters: Pair<Int, String>) {
// Throws IllegalStateException if eventId <= 0
val eventValue = resources.getInteger(eventId)
// Unnecessary sanity check if we have some compile time validation
require(eventValue > 0)
val parametersMap = parameters.map { resources.getInteger(it.first) to it.second}.toMap()
logEventInternal(eventValue, parametersMap)
}
private fun logEventInternal(eventId: Int, parameters: Map<Int, String>) {
logHandlers.forEach { handler ->
handler.logEvent(eventId, parameters)
}
}
/* This would run at startup of the application, if not code generation is used instead. */
private fun initLogEvents() {
initXmlIntegerResources("event_") { nameMap, idMap ->
eventNameMap = nameMap
eventIdMap = idMap
}
}
private fun initLogParams() {
initXmlIntegerResources("param_") { nameMap, idMap ->
paramNameMap = nameMap
paramIdMap = idMap
}
}
private fun initXmlIntegerResources(namePrefix: String, block: (Map<String, Int>, Map<Int, String>) -> Unit) {
val idMap = hashMapOf<Int, String>()
val nameMap = hashMapOf<String, Int>()
R.integer::class.java.declaredFields
.filter { it.name.startsWith(namePrefix) }
.forEach { field ->
val resourceId = resources.getIdentifier(field.name, "integer", packageName)
val value = resources.getInteger(resourceId)
if (value in idMap) {
throw IllegalStateException(
"All resources must have unique values! " +
"Cannot assign value $value to '${field.name}'. " +
"Already assigned to '${idMap[value]}'.")
}
idMap[value] = field.name
nameMap[field.name] = value
}
block(nameMap.toMap(), idMap.toMap())
}
}
Log output:
event_item_download=1
event_item_share=2
event_item_purchase=3
event_item_apply=0
Logging event_item_download(1)
Parameter: param_uuid(0)=6bb68142-6e2e-4fa0-b24b-da655a038cde
Parameter: param_ctype(1)=wallpaper
Parameter: param_title(2)=This is a title
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment