你通常如何标记日志条目? (机器人)

时间:2011-12-02 11:27:44

标签: android logging

我假设大多数人都知道android.util.Log 所有日志记录方法都接受'String tag'作为第一个参数。

我的问题是您通常如何在应用程序中标记日志? 我见过这样的硬编码:

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

由于种种原因,这看起来不太好:

  • 你可以告诉我这段代码没有硬编码,但确实如此。
  • 我的应用程序可以在具有相同名称的不同包中包含任意数量的类。所以很难阅读日志。
  • 不灵活。你总是把私人田地TAG放进你的班级。

有没有任何巧妙的方法来获得课程的TAG?

14 个答案:

答案 0 :(得分:157)

我使用TAG,但我将其初始化为:

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

这样,当我重构我的代码时,标记也会相应地改变。

答案 1 :(得分:12)

我通常创建一个App类,它位于不同的包中并包含有用的静态方法。其中一种方法是getTag()方法,这样我就可以到处获取TAG。
App类看起来像这样:

编辑:改进每个暴徒评论(谢谢:))

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;
    }

}

当我想使用它时:

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

getTag方法的输出是调用者类的名称(包名称),以及调用getTag的行号,以便轻松进行调试。

答案 2 :(得分:11)

转到 Android Studio - &gt;偏好 - &gt;实时模板 - &gt; AndroidLog 然后选择 Log.d(TAG,String)

模板文字中替换

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

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

Image of Android menu

然后点击修改变量,并在className 名称列旁边的表达式列中输入className()。 image of Android menu 2

现在,当您输入快捷方式logd时,它会显示

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

您不再需要定义TAG。

答案 3 :(得分:7)

我喜欢改善Yaniv的答案 如果您有这种格式的日志(filename.java:XX)xx行号,您可以链接快捷方式,当出现错误时,链接相同的方式链接,这样我就可以直接到达相关的行点击logcat

我把它放在我的扩展应用程序中,这样我就可以在其他所有文件中使用

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;
}

截图:

答案 4 :(得分:3)

我创建了一类名为S的静态变量,方法和类。

以下是记录方法:

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

它在任何类中都被称为S.L(this, whaterver_object); getClass().getName()也会附加包名称,因此,我将其删除以避免使标记过长。

<强>优点:

  1. Log.d(TAG,
  2. 无需将int值转换为其字符串。事实上,无需键入toString
  3. 我不会忘记删除Log.d,因为我只需删除该方法,所有日志的位置都标记为红色。
  4. 无需在活动顶部定义TAG,因为它取了类的名称。
  5. TAG的前缀为CCC(一个简短的,易于输入的字符串),因此很容易在Android Studio的Android监视器中仅列出您的日志。有时您同时运行服务或其他类。如果您必须单独按活动名称搜索,则无法确切地查看何时获得服务响应,然后发生了您的活动中的操作。像CCC这样的前缀会有所帮助,因为它会按时间顺序为您提供日志记录及其发生的活动

答案 5 :(得分:2)

当我在方法之间移动代码或重命名方法时,以更新这些字符串为代价,我喜欢执行以下操作。从哲学角度来看,在标签中保留“位置”或“上下文”似乎更好,而不是消息。

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!");
    }

}

这里的好处是,即使内容不是静态的,您也可以过滤掉单个方法,例如

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

唯一的缺点是,当我将f()重命名为g()时,我需要记住该字符串。此外,自动IDE重构不会捕获这些。

有一段时间我喜欢使用短类名,我的意思是LOG_TAG = MyClass.class.getSimpleName()。我发现在日志中过滤更难,因为没有更少的东西可以继续。

答案 6 :(得分:2)

默认情况下,AndroidStudio有一个logt模板(您可以输入logt并按Tab键将其扩展为代码片段)。我建议使用它来避免从另一个类复制粘贴TAG定义而忘记更改您所指的类。模板默认扩展为

private static final String TAG = "$CLASS_NAME$"

为避免在重构后使用旧的类名,您可以将其更改为

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

请记得检查&#34;编辑变量&#34;按钮并确保CLASS_NAME变量已定义为使用className()表达式,并且如果已定义&#34;则跳过#34}。检查。

答案 7 :(得分:1)

您可以使用this.toString()获取您在其中打印到日志的特定类的唯一标识符。

答案 8 :(得分:1)

这是一个非常老的问题,但甚至认为2018年7月有更新的答案,使用Timber更可取。为了记录正确的日志记录,可以将错误和警告发送到第三方崩溃库,例如Firebase或Crashlytics。

在实现 Application 的类中,您应该添加以下内容:

@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);
            }
        }
    }
}

不要忘记Timber依赖性。

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

答案 9 :(得分:1)

如果您使用的是 Kotlin,Any 上的扩展属性对此很有用:

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

这使得 TAG 可用于任何类或对象,只需要导入即可。

答案 10 :(得分:0)

对于那些访问此问题的用户:

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

答案 11 :(得分:0)

他们将Timber用于IOsched应​​用程序2019以显示调试信息:

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"
    ... >

用法

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

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

请注意,这使日志仅在DEBUG状态下可用,并方便您手动删除日志以便在Google Play上启动-

  

在Play商店中发布应用程序时,我们需要从应用程序中删除所有Log语句,以便用户在logcat中无法像普通用户一样使用任何应用程序数据(例如用户信息,隐藏的应用程序数据,身份验证令牌)文字

查看这篇文章https://medium.com/mindorks/better-logging-in-android-using-timber-72e40cc2293d

答案 12 :(得分:-2)

我通常使用方法名作为标记但是来自Thread

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

这可以避免新的异常。

答案 13 :(得分:-9)

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