If you want to use a programmatic approach instead of using ProGuard, then by creating your own class with two instances, one for debug and one for release, you can choose what to log in either circumstances.
So, if you don't want to log anything when in release, simply implement a Logger that does nothing, like the example below:
import android.util.Logsealed class Logger(defaultTag: String? = null) { protected val defaultTag: String = defaultTag ?: "[APP-DEBUG]" abstract fun log(string: String, tag: String = defaultTag) object LoggerDebug : Logger() { override fun log(string: String, tag: String) { Log.d(tag, string) } } object LoggerRelease : Logger() { override fun log(string: String, tag: String) {} } companion object { private val isDebugConfig = BuildConfig.DEBUG val instance: Logger by lazy { if(isDebugConfig) LoggerDebug else LoggerRelease } }}
Then to use your logger class:
class MainActivity : AppCompatActivity() {private val logger = Logger.instanceoverride fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) logger.log("Activity launched...") ... myView.setOnClickListener { ... logger.log("My View clicked!", "View-click") }}
== UPDATE ==
If we want to avoid string concatenations for better performances, we can add an inline function with a lambda that will be called only in debug config:
// Add this function to the Logger class.inline fun commit(block: Logger.() -> Unit) { if(this is LoggerDebug) block.invoke(this)}
And then:
logger.commit { log("Logging without $myVar waste of resources"+"My fancy concat") }
Since we are using an inline function, there are no extra object allocation and no extra virtual method calls.