106

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?

Dominik Schmidt
  • 537
  • 1
  • 8
  • 22
unorsk
  • 9,371
  • 10
  • 36
  • 42
  • 2
    Using TAG is suggested by Android [javadoc](http://developer.android.com/reference/android/util/Log.html), so I don't think it's worse than getting class name at runtime – Vladimir Dec 02 '11 at 11:32
  • 1
    i prefer to create a specific class like GeneralConstants and put my TAGs on it and i can reach my tags any class i want like that; GeneralConstans.MY_TAG – cagryInside Dec 02 '11 at 11:40
  • 6
    I think it is best to have the TAG defined in the class, hardcoding the class name is ugly but the only reliable way to work with proguard. If you never use proguard then MyActivity.class.getName() is the best solution. If you are worried about duplicate names just include the package name. Having TAG names in a different place will become a maintenance nightmare. – Ralph Mueller Oct 14 '13 at 15:43

15 Answers15

193

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.

gianpi
  • 3,110
  • 1
  • 17
  • 13
  • 23
    I am defining the TAG constant in the same way. However, I am wondering, how code obfuscation tools will affect my class names and as a result the value of this constant? – Olegs Briska Oct 22 '12 at 10:49
  • 1
    all this time i've manually pasted `"MyActivity.class.getName();"`. I've always thought "TAG" was just a placeholder in examples from Google etc... not an actual `Static` variable! This is a much better solution thanks :) – wired00 May 01 '13 at 03:46
  • 5
    Why not remove the static and use `this.getClass().getName()` instead to make it more generic? – theblang Jan 14 '14 at 16:26
  • 13
    You may want to try this.getClass().getSimpleName() to avoid the length limitations on TAG. IllegalArgumentException is thrown if the tag.length() > 23. – Michael Levy Mar 05 '14 at 02:12
  • 14
    As mentioned by Ralph Mueller, this technique does not work if you use Proguard (as most Android projects do) to obfuscate the class names. – John Patterson Apr 28 '14 at 22:55
  • I understand that is what many people do, but not why. If you want to log the triggering class, you can do that in your logging implementation (e.g. Timber does it for you in `DebugTree`, and you can do something similar in a custom `Tree`). You don't need to put it into the tag. I thought tags were more for providing extra information to the logging event. For example, we use it to tell the logger implementation which file to log to and whether to do it synchronously or asynchronously. That seems more of a valid use case for tags than what most people use them for. – Adam Burley Nov 16 '22 at 17:52
19

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.

Nicolas Manzini
  • 8,379
  • 6
  • 63
  • 81
  • 1
    that's a really cool usage of Android Studio and an interesting approach to the problem, though at the same time you're actually inputting string in place of TAG variable, meaning it could be a little cumbersome if needed to change it, right? +1 for showing the functionality though, thanks! – Voy Dec 16 '16 at 21:21
  • 3
    I like this way, however I'd rather create a new log entry instead of modifying the existing one, just to be on the safe side if it changed in a future update or something. – Alaa Feb 21 '17 at 13:20
  • In case you're using kotlin: `AndroidLogKotlin` instead of `AndroidLog` and `kotlinClassName()` instead of `className()` – Alex Mandelias May 31 '23 at 19:52
17

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.

Yaniv
  • 562
  • 1
  • 6
  • 18
  • 7
    I definitely wouldn't do this.. Your log statements are going to take a big performance hit if you do. If you do this you'll definitely want to have proguard remove log messages for anything less than warning on production builds. – Matt Wolfe Nov 24 '15 at 19:38
  • 1
    Matt, you're absolutely right! It's a good practice to remove / strip logs on production - http://stackoverflow.com/a/2019563/2270166 – Yaniv Nov 25 '15 at 13:11
  • 2
    This is probably not longer recommended since tag length is now restricted to 23 characters – Claudio Redi Dec 09 '15 at 14:07
9

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:

dvs
  • 12,324
  • 6
  • 38
  • 45
br mob
  • 91
  • 1
  • 3
3

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.

Hemaolle
  • 1,950
  • 18
  • 21
3

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.

Nicolas
  • 6,611
  • 3
  • 29
  • 73
2

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
suku
  • 10,507
  • 16
  • 75
  • 120
  • 1
    Great solution! I use it! But I replaced `Context ctx` by `Object ctx` and `ctx.getClass().getName().replace(ctx.getPackageName(), "")` by `ctx.getClass().getSimpleName()`. That way, I can call `S.L(Object, Object)` anywhere (including in `Fragment`s which do not extend `Context`, for instantce). – Antônio Medeiros Aug 05 '18 at 15:07
1

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.

tar
  • 1,538
  • 1
  • 20
  • 33
1

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'
aleksandrbel
  • 1,422
  • 3
  • 20
  • 38
1

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

kaspermoerch
  • 16,127
  • 4
  • 44
  • 67
0

For those users that visit this question:

private val TAG:String = this.javaClass.simpleName;
Pamira
  • 129
  • 7
0

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

Dan Alboteanu
  • 9,404
  • 1
  • 52
  • 40
0

I understand that most people use the class name as the tag but I don't really understand this practice. Nowhere have I seen documented what the "tag" conceptually actually is or what it should be used for. But at my company, we are using it differently - to provide information to the logging implementation, such as which file to log to or whether logging can be done asynchronously. For example, a log message might need to be redirected because it's applicable to all customers rather than just the active one, and we may need to force synchronous logging if the application is about to shut down.

The fact that there was originally a 23 character limit on tag names suggests that it was never intended to be used for class names in the first place. If you are using Timber, you can even log the calling class in every log message yourself by using techniques such as Thread.currentThread.stackTrace in your custom Tree (have a look at how Timber does it in DebugTree which is very similar). This doesn't require the use of tags, so you can use tags for other stuff like I mentioned above.

Adam Burley
  • 5,551
  • 4
  • 51
  • 72
-1

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

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

This avoids the new Exception.

-9
private static final String TAG = new RuntimeException().getStackTrace()[0].getClassName();
Arise
  • 800
  • 1
  • 10
  • 11
  • 3
    Why would you create a new `RuntimeException` just to get the current class name? Very bad. – asgs Apr 03 '13 at 07:50
  • This is how I TAG my log entries, it is the only solution I can properly refactor when I copy a class from a project to another, so why not. I'm open to suggestions if you have better and more comfortable ideas. – Arise Apr 13 '13 at 07:50
  • 1
    If you're just copying Java class files from one location to another, without any renaming, the solution provided by @gianpi is what is needed. Otherwise, you could just do `this.getClass().getName()` although you would have to remove the static scope of the `TAG` – asgs Apr 14 '13 at 01:22