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 lodging 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 messages. 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.