How to add logging in android studio with examples!

Android Logging is a must to know every developer we believe. In their development lifecycle, one has to hear “Check the logs” at least for once from others. In fact, checking the logs saves lots of unexpected errors. But First of all, we need a clear concept on it; Logging, log messages, advantages, and disadvantages, etc. Let’s try to find it out.

What is this buzzword, “Logging”?

Logging — the cutting, skidding, on-site processing and loading of trees onto trucks (taken from Wikipedia). OK, but this is not what we are looking for. What is logging in software development? What is the role of it?

Logging is a process; a process of printing information about what exactly the code is doing, which data we are working on etc. In software development, there are different languages with different syntax, there are different platforms, but the general idea of logging is the same for all.

Advantages & disadvantages of logging

Developers must learn the right way to log. If the logging process is properly, then it can be a saver to detect bugs, performance issues, etc. It can also provide related important information on the software or technology we are using. But if the logging process is wrong, it can create overhead for no reason; i.e. some developers may print a thousand lines of log message without any need.

Advantages

  • We can easily trace using proper logging mechanism to monitor the method execution order
  • A developer can traverse through the data flow of the software
  • Monitoring the real data that the software is using or working with

Disadvantages (depends on the implementation)

  • Logging may generate lots of unnecessary information if the developer is not careful
  • It may decrease the readability of the codes

Types of logging in Android

There are several types of logging options in the Android framework (which is built-in) where a dedicated special class named “Log” to provide the functionality of printing a log message. There are different types of a log message. It can be simple information, it can be an error. A developer may want to get the log in debug mode and not at the release time. We are going to discuss on the right below, Log.i — it is used to log INFO type messages. When someone wants log useful information; i.e. a file is downloading, a process is finished, connect to the cloud, etc, this type of log messages can be used.

package com.example.architecturecomponents.ui.main
import android.os.Bundle
import android.util.Log
import androidx.appcompat.app.AppCompatActivity
import androidx.lifecycle.ViewModelProviders
import com.example.architecturecomponents.R
import com.example.architecturecomponents.data.ClickLoggingInterceptor
import com.example.architecturecomponents.data.LoggingViewModel
import com.example.architecturecomponents.data.LoggingViewModelFactory
import com.example.architecturecomponents.ui.setRipple
import kotlinx.android.synthetic.main.activity_main.*
class MainActivity : AppCompatActivity() {
 private var viewModel: LoggingViewModel? = null
 private val LOG_TAG = this.javaClass.simpleName
 override fun onCreate(savedInstanceState: Bundle?) {
 super.onCreate(savedInstanceState)
 setContentView(R.layout.activity_main)
 viewModel = ViewModelProviders.of(this,
LoggingViewModelFactory(ClickLoggingInterceptor()))
 .get(LoggingViewModel::class.java)
 text_view_click.text = viewModel?.count.toString()
 text_view_click.setRipple(R.color.colorPrimary50)
 text_view_click.setOnClickListener {
 viewModel?.count = viewModel?.count?.inc()!!
 text_view_click.text = (viewModel?.count).toString()
 // Here we are logging the count
 Log.i(LOG_TAG, (viewModel?.count).toString())
 }
 }
}

Log.e — here e stands for error. Usually, this type of log message is used to print error details.

This log messages often appear at the catch statements of our code.

package com.example.architecturecomponents.ui.main
import android.os.Bundle
import android.text.TextUtils
import android.util.Log
import androidx.appcompat.app.AppCompatActivity
import androidx.lifecycle.ViewModelProviders
import com.example.architecturecomponents.R
import com.example.architecturecomponents.data.ClickLoggingInterceptor
import com.example.architecturecomponents.data.LoggingViewModel
import com.example.architecturecomponents.data.LoggingViewModelFactory
import com.example.architecturecomponents.ui.setRipple
import kotlinx.android.synthetic.main.activity_main.*
import kotlin.random.Random
class MainActivity : AppCompatActivity() {
 private var viewModel: LoggingViewModel? = null
 private val LOG_TAG = this.javaClass.simpleName
 override fun onCreate(savedInstanceState: Bundle?) {
 super.onCreate(savedInstanceState)
 setContentView(R.layout.activity_main)
 viewModel = ViewModelProviders.of(this,
LoggingViewModelFactory(ClickLoggingInterceptor()))
 .get(LoggingViewModel::class.java)
 text_view_click.text = viewModel?.count.toString()
 text_view_click.setRipple(R.color.colorPrimary50)
 text_view_click.setOnClickListener {
 viewModel?.count = viewModel?.count?.inc()!!
 val randomValue = Random.nextInt(0, 9)
 try {
 viewModel?.count = viewModel?.count!! / randomValue
 text_view_click.text = (viewModel?.count).toString()
 Log.i(LOG_TAG, (viewModel?.count).toString())
 } catch (e: Exception) {
 if (!TextUtils.isEmpty(e.message)) {
 // Here is the error log message
 Log.e(LOG_TAG, e.message!!)
 }
 }
 }
 }
}

Log.w — w stands for warning. The log message is of WARN type. This type implies that something
something strange happened, but it is not necessarily an error.

package com.example.architecturecomponents.ui.main
import android.os.Bundle
import android.text.TextUtils
import android.util.Log
import androidx.appcompat.app.AppCompatActivity
import androidx.lifecycle.ViewModelProviders
import com.example.architecturecomponents.R
import com.example.architecturecomponents.data.ClickLoggingInterceptor
import com.example.architecturecomponents.data.LoggingViewModel
import com.example.architecturecomponents.data.LoggingViewModelFactory
import com.example.architecturecomponents.ui.setRipple
import kotlinx.android.synthetic.main.activity_main.*
import kotlin.random.Random
class MainActivity : AppCompatActivity() {
 private var viewModel: LoggingViewModel? = null
 private val LOG_TAG = this.javaClass.simpleName
 override fun onCreate(savedInstanceState: Bundle?) {
 super.onCreate(savedInstanceState)
 setContentView(R.layout.activity_main)
 viewModel = ViewModelProviders.of(this,
LoggingViewModelFactory(ClickLoggingInterceptor()))
 .get(LoggingViewModel::class.java)
 text_view_click.text = viewModel?.count.toString()
 text_view_click.setRipple(R.color.colorPrimary50)
 text_view_click.setOnClickListener {
 viewModel?.count = viewModel?.count?.inc()!!
 val randomValue = Random.nextInt(0, 9)
 // Here is the warning log message
 Log.w(LOG_TAG, "The value is: $randomValue. (It should not be zero)")
 try {
 viewModel?.count = viewModel?.count!! / randomValue
 text_view_click.text = (viewModel?.count).toString()
 Log.i(LOG_TAG, (viewModel?.count).toString())
 } catch (e: Exception) {
 if (!TextUtils.isEmpty(e.message)) {
 // Here is the error log message
 Log.e(LOG_TAG, e.message!!)
 }
 }
 }
 }
}

Log.d — Sometimes developers might need to check if some of the codes/ code blocks are properly
working, the statements are running properly. This means the process is still under development and the
developer wants to check something for now only. It’s the time when this log message comes. d stands
for DEBUG. Some may think that this log message is used for debugging, then all of the log messages will
be removed automatically during runtime. And if you follow up on the official Android documentation, you
are right! But, in reality, that’s not the case. It needs some additional steps in order to achieve that.

package com.example.architecturecomponents.ui.main
import android.os.Bundle
import android.text.TextUtils
import android.util.Log
import androidx.appcompat.app.AppCompatActivity
import androidx.lifecycle.ViewModelProviders
import com.example.architecturecomponents.R
import com.example.architecturecomponents.data.ClickLoggingInterceptor
import com.example.architecturecomponents.data.LoggingViewModel
import com.example.architecturecomponents.data.LoggingViewModelFactory
import com.example.architecturecomponents.ui.setRipple
import kotlinx.android.synthetic.main.activity_main.*
import kotlin.random.Random
class MainActivity : AppCompatActivity() {
 private var viewModel: LoggingViewModel? = null
 private val LOG_TAG = this.javaClass.simpleName
 override fun onCreate(savedInstanceState: Bundle?) {
 super.onCreate(savedInstanceState)
 setContentView(R.layout.activity_main)
 viewModel = ViewModelProviders.of(this,
LoggingViewModelFactory(ClickLoggingInterceptor()))
 .get(LoggingViewModel::class.java)
 text_view_click.text = viewModel?.count.toString()
 text_view_click.setRipple(R.color.colorPrimary50)
 text_view_click.setOnClickListener {
 viewModel?.count = viewModel?.count?.inc()!!
 // Here is the debug log message
 Log.w(LOG_TAG, "The value is: $Random.nextInt(0, 9). Is it between 0 and 9?")

 val randomValue = Random.nextInt(0, 9)
 // Here is the warning log message
 Log.w(LOG_TAG, "The value is: $randomValue. (It should not be zero)")
 try {
 viewModel?.count = viewModel?.count!! / randomValue
 text_view_click.text = (viewModel?.count).toString()
 Log.i(LOG_TAG, (viewModel?.count).toString())
 } catch (e: Exception) {
 if (!TextUtils.isEmpty(e.message)) {
 // Here is the error log message
 Log.e(LOG_TAG, e.message!!)
 }
 }
 }
 }
}

Log.v — v stands for VERBOSE. This is more like a general type of a log message. Developers can use it
whenever you want to print some very detailed info about the event that occurred.

package com.example.architecturecomponents.ui.main
import android.os.Bundle
import android.text.TextUtils
import android.util.Log
import androidx.appcompat.app.AppCompatActivity
import androidx.lifecycle.ViewModelProviders
import com.example.architecturecomponents.R
import com.example.architecturecomponents.data.ClickLoggingInterceptor
import com.example.architecturecomponents.data.LoggingViewModel
import com.example.architecturecomponents.data.LoggingViewModelFactory
import com.example.architecturecomponents.ui.setRipple
import kotlinx.android.synthetic.main.activity_main.*
import kotlin.random.Random
class MainActivity : AppCompatActivity() {
 private var viewModel: LoggingViewModel? = null
 private val LOG_TAG = this.javaClass.simpleName
 override fun onCreate(savedInstanceState: Bundle?) {
 super.onCreate(savedInstanceState)
 setContentView(R.layout.activity_main)
 viewModel = ViewModelProviders.of(this,
LoggingViewModelFactory(ClickLoggingInterceptor()))
 .get(LoggingViewModel::class.java)
 text_view_click.text = viewModel?.count.toString()
 text_view_click.setRipple(R.color.colorPrimary50)
 text_view_click.setOnClickListener {
 viewModel?.count = viewModel?.count?.inc()!!
 // Here is the debug log message
 Log.w(LOG_TAG, "The value is: $Random.nextInt(0, 9). Is it between 0 and 9?")
 val randomValue = Random.nextInt(0, 9)
 // Here is the warning log message
 Log.w(LOG_TAG, "The value is: $randomValue. (It should not be zero)")
 try {
 viewModel?.count = viewModel?.count!! / randomValue
 text_view_click.text = (viewModel?.count).toString()
 Log.i(LOG_TAG, (viewModel?.count).toString())
 } catch (e: Exception) {
 if (!TextUtils.isEmpty(e.message)) {
 // Here is the error log message
 Log.e(LOG_TAG, e.message!!)
 }
 // Here is the full log message of the error
 Log.v(LOG_TAG, e.toString())
 }
 }
 }
}

Log.wtf — wtf stands for ‘What a Terrible Failure’. It looks like Log.e, but its way more sever. It’s to be
used in these strange cases, which should never happen but they do from time to time.

package com.example.architecturecomponents.ui.main
import android.os.Bundle
import android.text.TextUtils
import android.util.Log
import androidx.appcompat.app.AppCompatActivity
import androidx.lifecycle.ViewModelProviders
import com.example.architecturecomponents.R
import com.example.architecturecomponents.data.ClickLoggingInterceptor
import com.example.architecturecomponents.data.LoggingViewModel
import com.example.architecturecomponents.data.LoggingViewModelFactory
import com.example.architecturecomponents.ui.setRipple
import kotlinx.android.synthetic.main.activity_main.*
import kotlin.random.Random
class MainActivity : AppCompatActivity() {
 private var viewModel: LoggingViewModel? = null
 private val LOG_TAG = this.javaClass.simpleName
 override fun onCreate(savedInstanceState: Bundle?) {
 super.onCreate(savedInstanceState)
 setContentView(R.layout.activity_main)
 viewModel = ViewModelProviders.of(this,
LoggingViewModelFactory(ClickLoggingInterceptor()))
 .get(LoggingViewModel::class.java)
 text_view_click.text = viewModel?.count.toString()
 text_view_click.setRipple(R.color.colorPrimary50)
 text_view_click.setOnClickListener {
 viewModel?.count = viewModel?.count?.inc()!!
 // Here is the debug log message
 Log.w(LOG_TAG, "The value is: $Random.nextInt(0, 9). Is it between 0 and 9?")
 val randomValue = Random.nextInt(0, 9)
 // Here is the warning log message
 Log.w(LOG_TAG, "The value is: $randomValue. (It should not be zero)")
 try {
 viewModel?.count = viewModel?.count!! / randomValue
 text_view_click.text = (viewModel?.count).toString()
 Log.i(LOG_TAG, (viewModel?.count).toString())
 } catch (e: Exception) {
 if (!TextUtils.isEmpty(e.message)) {
 // Here is the error log message
 Log.e(LOG_TAG, e.message!!)
 }
 // Here is the full log message of the error
 Log.v(LOG_TAG, e.toString())
 // Here is the log message of the error as WTF
 Log.wtf(LOG_TAG, "What a terrible failure", e)
 }
 }
 }
}

Conclusion

Logging is a must and error-cutting process in software development. In the next episode, we will go through the usage of Timber to log in to Android. Stay with us. Another interesting topic to check out here.

References:

  • Find author reference git repo:
  • https://developer.android.com/reference/android/util/Log
  • https://developer.android.com/studio/debug/am-logcat
  • https://android.jlelse.eu/logging-in-android-cfcd50cdc1ae
  • https://developer.android.com/studio/images/debug/logcat_2x.png

Leave a comment