[Solved] How do you usually Tag log entries? (android)

I assume most of you are aware of android.util.Log
All logging methods accept ‘String tag’ as a first argument.

And my question is How do you usually tag your logs in your applications?
I’ve seen some hardcode like this:

public class MyActivity extends Activity {
    private static final String TAG = "MyActivity";
    //...
    public void method () {
        //...
        Log.d(TAG, "Some logging");
    }
}

This doesn’t look nice because of many reasons:

  • You can tell me this code doesn’t have hardcode, but it does.
  • My application could have any number of classes in different packages with the same name. So it would be hard to read the log.
  • It isn’t flexible. You always have put a private field TAG into your class.

Is there any neat way to get a TAG for a class?

Enquirer: andrii

||

Solution #1:

I use a TAG, but I initialise it like this:

private static final String TAG = MyActivity.class.getName();

This way when I refactor my code the tag will also change accordingly.

Respondent: gianpi

Solution #2:

I usually create an App class that sits in a different package and contains useful static methods. One of the method is a getTag() method, this way I can get the TAG everywhere.

App class looks like this:

EDIT: Improved per br mob comment ( Thanks 🙂 )

public class App {

    public static String getTag() {
        String tag = "";
        final StackTraceElement[] ste = Thread.currentThread().getStackTrace();
        for (int i = 0; i < ste.length; i++) {
            if (ste[i].getMethodName().equals("getTag")) {
                tag = "("+ste[i + 1].getFileName() + ":" + ste[i + 1].getLineNumber()+")";
            }
        }
        return tag;
    }

}

And when I want to use it:

Log.i(App.getTag(), "Your message here");

The output of the getTag method is the name of the caller class (with the package name), and the line number where the getTag is called from, for easy debuging.

Respondent: Yaniv

Solution #3:

Go to Android Studio -> preference -> Live Templates -> AndroidLog then select Log.d(TAG, String).

In Template text replace

android.util.Log.d(TAG, "$METHOD_NAME$: $content$");

with

android.util.Log.d("$className$", "$METHOD_NAME$: $content$");

Image of Android menu

Then click Edit variables and enter className() in the Expression column next to the className Name column. image of Android menu 2

Now when you type the shortcut logd it will put

Log.d("CurrentClassName", "currentMethodName: ");

You dont need to define a TAG anymore.

Respondent: Nicolas Manzini

Solution #4:

I like to improve Yaniv answer
if you have the log in this format (filename.java:XX) xx line number you can link the shortcut the same way gets linked when there’s an error, this way I can get direct to the line in question just by click on the logcat

I put this inside my extended Application so i can use in every other file

public static String getTag() {
    String tag = "";
    final StackTraceElement[] ste = Thread.currentThread().getStackTrace();
    for (int i = 0; i < ste.length; i++) {
        if (ste[i].getMethodName().equals("getTag")) {
            tag = "("+ste[i + 1].getFileName() + ":" + ste[i + 1].getLineNumber()+")";
        }
    }
    return tag;
}

Screenshot:

Respondent: br mob

Solution #5:

AndroidStudio has a logt template by default (you can type logtand press tab to have it expand to a sinppet of code) . I recommend using this to avoid copy pasting the TAG definition from another class and forgetting to change the class you’re referring to. The template expands by default to

private static final String TAG = "$CLASS_NAME$"

To avoid using the old class name after refactoring you could change that to

private static final String TAG = $CLASS_NAME$.class.getSimpleName();

Remember to check the “Edit variables” button and make sure that the CLASS_NAME variable is defined to use the className() Expression and has “Skip if defined” checked.

Respondent: Hemaolle

Solution #6:

I have created a class of Static variables, methods and classes named as S.

The following is the logging method:

public static void L(Context ctx, Object s) {
    Log.d("CCC " + ctx.getClass().getName().replace(ctx.getPackageName(), ""), s.toString());
}

It is called in any class as S.L(this, whaterver_object); The getClass().getName() also appends the package name, hence, I am removing it out to avoid making the tag unnecessarily long.

Advantages:

  1. Shorter than Log.d(TAG,
  2. No need to convert int values to their string. Infact no need to type toString
  3. Won’t forget to delete Log.d ever as I just have to delete the method and the locations of all logs get marked red.
  4. No need to define TAG at the top of the activity as it takes the name of the class.
  5. The TAG has a prefix of CCC (a short, easy to type string) so that it is easy to list only your logs in android monitor in Android Studio. Sometimes you are running services or other classes simultaneously. If you have to search by activity name alone then you cannot see exactly when a service response was obtained and then an action from your activity has occurred. A prefix like CCC helps as it gives you logs chronologically with the activity in which it occured
Respondent: suku

Solution #7:

You could use this.toString() to get a unique identifer for the specific class in which you print to the log.

Respondent: kaspermoerch

Solution #8:

At the expense of updating these strings when I move code between methods or rename methods, I like doing the following. Philosophically it also seems to be better to keep “location” or “context” in the tag, not the message.

public class MyClass {

    // note this is ALWAYS private...subclasses should define their own
    private static final LOG_TAG = MyClass.class.getName();

    public void f() {
        Log.i(LOG_TAG + ".f", "Merry Christmas!");
    }

}

The benefit here is that you can filter out a single method even if the content isn’t static, e.g.

Log.i(LOG_TAG + ".f", String.valueOf(new Random().nextInt()));

The only drawback is that when I rename f() to g() I need to keep that string in mind. Also, automatic IDE refactoring won’t catch these.

For a while I was a fan of using the short class name, I mean LOG_TAG = MyClass.class.getSimpleName(). I found them harder to filter in the logs because there was less to go on.

Respondent: tar

Solution #9:

It is a very old question, but even thought an updated answer for July 2018 it is more preferable to use Timber. In order to Log the correct logging, errors and warns can be send to third party crash libraries, such as Firebase or Crashlytics.

In the class that implements Application you should add this:

@Override
public void onCreate() {
    super.onCreate();
    if (BuildConfig.DEBUG) {
        Timber.plant(new Timber.DebugTree());
    } else {
        Timber.plant(new CrashReportingTree());
    }
}

/** A tree which logs important information for crash reporting. */
private static class CrashReportingTree extends Timber.Tree {
    @Override protected void log(int priority, String tag, String message, Throwable t) {
        if (priority == Log.VERBOSE || priority == Log.DEBUG) {
            return;
        }

        FakeCrashLibrary.log(priority, tag, message);

        if (t != null) {
            if (priority == Log.ERROR) {
                FakeCrashLibrary.logError(t);
            } else if (priority == Log.WARN) {
                FakeCrashLibrary.logWarning(t);
            }
        }
    }
}

Do not forget Timber dependency.

implementation 'com.jakewharton.timber:timber:4.7.1'
Respondent: aleksandrbel

Solution #10:

If you’re using Kotlin, an extension property on Any can be useful for this:

val Any.TAG: String
    get() = this::class.java.simpleName

This makes TAG available for any class or object, only needing an import.

Respondent: Nicolas

Solution #11:

For those users that visit this question:

private val TAG:String = this.javaClass.simpleName;
Respondent: Pamirzameen

Solution #12:

they use Timber for the IOsched app 2019 to show debug info:

implementation 'com.jakewharton.timber:timber:4.7.1'

class ApplicationController: Application() {

override fun onCreate() {  
    super.onCreate()
    if(BuildConfig.DEBUG){
        Timber.plant(Timber.DebugTree())
    }
}   
// enables logs for every activity and service of the application
// needs to be registered in manifest like:  
 <application
    android:label="@string/app_name"
    android:name=".ApplicationController"
    ... >

usage

  Timber.e("Error Message") 
  // will print ->  D/MainActivity: Error Message

  Timber.d("Debug Message");
  Timber.tag("new tag").e("error message");

note that this makes the Logs available only during DEBUG state and facilitates you the task of removing them manually for the launch on Google Play –

when release the app on the play store, we need to remove all Log statement from the app, so that none of the application data such as user information, hidden application data, auth-tokens are available to user in logcat as plain text

check out this article https://medium.com/mindorks/better-logging-in-android-using-timber-72e40cc2293d

Respondent: Dan Alboteanu

Solution #13:

I usually use the method name as the tag but from Thread

String TAG = Thread.currentThread().getStackTrace()[1].getMethodName();

This avoids the new Exception.

Respondent: user2705093

Solution #14:

private static final String TAG = new RuntimeException().getStackTrace()[0].getClassName();
Respondent: Arise

The answers/resolutions are collected from stackoverflow, are licensed under cc by-sa 2.5 , cc by-sa 3.0 and cc by-sa 4.0 .

Leave a Reply

Your email address will not be published.