[英]How do you usually Tag log entries? (android)
我假設你們中的大多數人都知道 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,但我這樣初始化它:
private static final String TAG = MyActivity.class.getName();
這樣當我重構我的代碼時,標簽也會相應地改變。
我通常會創建一個App
類,它位於不同的包中並包含有用的靜態方法。 其中一種方法是getTag()
方法,這樣我就可以在任何地方獲取 TAG。
App
類如下所示:
編輯:改進每個 br mob 評論(謝謝:))
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
的行號,以便於調試。
轉到Android Studio -> 首選項 -> 實時模板 -> AndroidLog然后選擇Log.d(TAG, String) 。
在模板文本替換
android.util.Log.d(TAG, "$METHOD_NAME$: $content$");
和
android.util.Log.d("$className$", "$METHOD_NAME$: $content$");
然后單擊編輯變量並在 className Name列旁邊的Expression列中輸入 className()。
現在,當您鍵入快捷方式logd
,它將放置
Log.d("CurrentClassName", "currentMethodName: ");
您不再需要定義 TAG。
我喜歡改進 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;
}
截屏:
默認情況下,AndroidStudio 有一個logt
模板(您可以輸入logt
並按 tab 將其擴展為代碼的 sinppet)。 我建議使用它來避免從另一個類復制粘貼 TAG 定義並忘記更改您所指的類。 模板默認擴展為
private static final String TAG = "$CLASS_NAME$"
為了避免在重構后使用舊的類名,您可以將其更改為
private static final String TAG = $CLASS_NAME$.class.getSimpleName();
請記住檢查“編輯變量”按鈕並確保將CLASS_NAME
變量定義為使用className()
表達式並選中“如果定義則跳過”。
我創建了一類名為S
的靜態變量、方法和類。
以下是日志記錄方法:
public static void L(Context ctx, Object s) {
Log.d("CCC " + ctx.getClass().getName().replace(ctx.getPackageName(), ""), s.toString());
}
它在任何類中都被稱為SL(this, whaterver_object);
getClass().getName()
還附加了包名,因此,我將其刪除以避免使標簽不必要地過長。
優點:
Log.d(TAG,
toString
Log.d
,因為我只需要刪除該方法並且所有日志的位置都被標記為紅色。CCC
前綴(一個簡短的、易於輸入的字符串),因此很容易在 Android Studio 的 android 監視器中僅列出您的日志。 有時您同時運行服務或其他類。 如果您必須單獨按活動名稱進行搜索,那么您無法准確看到獲得服務響應的時間以及您的活動的操作發生的時間。 像 CCC 這樣的前綴會有所幫助,因為它可以按時間順序記錄活動發生的時間當我在方法之間移動代碼或重命名方法時,以更新這些字符串為代價,我喜歡執行以下操作。 從哲學上講,在標簽中保留“位置”或“上下文”似乎更好,而不是在消息中。
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()
。 我發現它們更難在日志中過濾,因為沒有什么可做的了。
這是一個非常古老的問題,但即使認為 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);
}
}
}
}
不要忘記木材依賴性。
implementation 'com.jakewharton.timber:timber:4.7.1'
如果您使用的是 Kotlin,則Any
上的擴展屬性對此很有用:
val Any.TAG: String
get() = this::class.java.simpleName
這使得TAG
可用於任何類或對象,只需要導入。
您可以使用this.toString()
獲取打印到日志的特定類的唯一標識符。
對於訪問此問題的用戶:
private val TAG:String = this.javaClass.simpleName;
他們將 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");
請注意,這使得日志僅在調試狀態下可用,並有助於您手動刪除它們以在 Google Play 上啟動 -
在Play商店發布應用程序時,我們需要從應用程序中刪除所有Log語句,以便用戶信息,隱藏應用程序數據,auth-tokens等應用程序數據都不會以純文本形式提供給用戶
查看這篇文章https://medium.com/mindorks/better-logging-in-android-using-timber-72e40cc2293d
我通常使用方法名稱作為標簽,但來自 Thread
String TAG = Thread.currentThread().getStackTrace()[1].getMethodName();
這避免了新的異常。
private static final String TAG = new RuntimeException().getStackTrace()[0].getClassName();
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.