Bạn thường Tag các mục nhật ký như thế nào? (android)


96

Tôi cho rằng hầu hết các bạn đều biết đến android.util.Log Tất cả các phương thức ghi nhật ký đều chấp nhận 'Thẻ chuỗi' làm đối số đầu tiên.

Và câu hỏi của tôi là Bạn thường gắn thẻ nhật ký của mình trong ứng dụng của mình như thế nào? Tôi đã thấy một số mã cứng như thế này:

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

Cái này trông không đẹp vì nhiều lý do:

  • Bạn có thể cho tôi biết mã này không có mã cứng, nhưng nó có.
  • Ứng dụng của tôi có thể có bất kỳ số lớp nào trong các gói khác nhau có cùng tên. Vì vậy, sẽ rất khó để đọc nhật ký.
  • Nó không linh hoạt. Bạn luôn đặt TAG trường riêng vào lớp học của mình.

Có cách nào gọn gàng để lấy TAG cho một lớp học không?


2
Sử dụng TAG được đề xuất bởi Android javadoc , vì vậy tôi không nghĩ nó tệ hơn việc lấy tên lớp trong thời gian chạy
Vladimir

tôi thích tạo một lớp cụ thể như GeneralConstants và đặt các TAG của mình vào đó và tôi có thể tiếp cận các thẻ của mình bất kỳ lớp nào mà tôi muốn như vậy; GeneralConstans.MY_TAG
cagryInside

6
Tôi nghĩ tốt nhất nên xác định TAG trong lớp, mã hóa cứng tên lớp là xấu nhưng là cách đáng tin cậy duy nhất để làm việc với proguard. Nếu bạn không bao giờ sử dụng proguard thì MyActivity.class.getName () là giải pháp tốt nhất. Nếu bạn lo lắng về các tên trùng lặp, chỉ cần bao gồm tên gói. Có tên TAG ở một nơi khác sẽ trở thành một cơn ác mộng bảo trì.
Ralph Mueller

Câu trả lời:


179

Tôi sử dụng TAG, nhưng tôi khởi tạo nó như thế này:

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

Bằng cách này khi tôi cấu trúc lại mã của mình, thẻ cũng sẽ thay đổi theo.


21
Tôi đang xác định hằng số TAG theo cách tương tự. Tuy nhiên, tôi đang tự hỏi, các công cụ làm xáo trộn mã sẽ ảnh hưởng như thế nào đến tên lớp của tôi và kết quả là giá trị của hằng số này?
Gumbit 22/10/12

1
tất cả thời gian này tôi đã dán thủ công "MyActivity.class.getName();". Tôi luôn nghĩ "TAG" chỉ là một trình giữ chỗ trong các ví dụ từ Google, v.v ... không phải là một Staticbiến thực tế ! Đây là một giải pháp tốt hơn nhiều, cảm ơn :)
wired00

4
Tại sao không loại bỏ tĩnh và this.getClass().getName()thay vào đó sử dụng để làm cho nó chung chung hơn?
theblang

11
Bạn có thể muốn thử this.getClass (). GetSimpleName () để tránh giới hạn độ dài trên TAG. IllegalArgumentException được ném nếu thẻ.length ()> 23.
Michael Levy

14
Như đã đề cập bởi Ralph Mueller, kỹ thuật này không hoạt động nếu bạn sử dụng Proguard (như hầu hết các dự án Android làm) để làm xáo trộn tên lớp.
John Patterson

16

Tôi thường tạo một Applớp nằm trong một gói khác và chứa các phương thức tĩnh hữu ích. Một trong những phương pháp là một getTag()phương pháp, bằng cách này tôi có thể nhận được TAG ở mọi nơi.
Applớp trông như thế này:

CHỈNH SỬA : Cải thiện mỗi bình luận của đám đông br (Cảm ơn :))

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

}

Và khi tôi muốn sử dụng nó:

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

Đầu ra của getTagphương thức là tên của lớp người gọi (với tên gói) và số dòng nơi getTaggọi từ đó, để dễ dàng gỡ lỗi.


6
Tôi chắc chắn sẽ không làm điều này .. Báo cáo nhật ký của bạn sẽ có hiệu suất lớn nếu bạn làm. Nếu bạn làm điều này, chắc chắn bạn sẽ muốn có thông báo nhật ký xóa proguard cho bất kỳ điều gì ít hơn cảnh báo trên các bản dựng sản xuất.
Matt Wolfe

1
Matt, bạn hoàn toàn đúng! Đó là một thực hành tốt để loại bỏ / logs dải sản xuất - stackoverflow.com/a/2019563/2270166
Yaniv

2
Đây có lẽ là không còn đề nghị kể từ chiều dài thẻ hiện đang giới hạn ở 23 ký tự
Claudio Redi

cảm ơn đã chỉ cho tôi cách getStackTrace()hoạt động. Nhưng tôi sẽ không sử dụng nó bởi vì nó đắt
BlueWizard

12

Đi tới Android Studio -> tùy chọn -> Mẫu trực tiếp -> AndroidLog rồi chọn Log.d (TAG, Chuỗi) .

Trong văn bản Mẫu thay thế

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

với

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

Hình ảnh menu Android

Sau đó nhấp vào Chỉnh sửa biến và nhập className () vào cột Biểu thức bên cạnh cột Tên className .hình ảnh của menu Android 2

Bây giờ khi bạn gõ phím tắt, logdnó sẽ đặt

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

Bạn không cần xác định TAG nữa.


1
đó là cách sử dụng Android Studio thực sự thú vị và là một cách tiếp cận vấn đề thú vị, mặc dù đồng thời bạn đang thực sự nhập chuỗi thay cho biến TAG, có nghĩa là có thể hơi rườm rà nếu cần thay đổi nó, phải không? +1 vì đã hiển thị chức năng, cảm ơn!
Voy

3
Tôi thích cách này, tuy nhiên tôi muốn tạo một mục nhật ký mới thay vì sửa đổi mục hiện có, chỉ để an toàn nếu nó thay đổi trong một bản cập nhật trong tương lai hoặc một cái gì đó.
Alaa

9

Tôi muốn cải thiện câu trả lời của Yaniv nếu bạn có nhật ký ở định dạng này (filename.java:XX) số dòng xx, bạn có thể liên kết lối tắt giống như cách được liên kết khi có lỗi, bằng cách này tôi có thể truy cập trực tiếp vào dòng được đề cập chỉ bằng cách nhấp vào logcat

Tôi đặt cái này bên trong Ứng dụng mở rộng của mình để tôi có thể sử dụng trong mọi tệp khác

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

Ảnh chụp màn hình:


Yêu thích nó, "đánh cắp" nó và cập nhật câu trả lời của tôi :)
Yaniv

4
Đây có lẽ là không còn đề nghị kể từ chiều dài thẻ hiện đang giới hạn ở 23 ký tự
Claudio Redi

3

AndroidStudio có một logtmẫu theo mặc định (bạn có thể nhập logtvà nhấn tab để nó mở rộng thành một đoạn mã). Tôi khuyên bạn nên sử dụng điều này để tránh sao chép, dán định nghĩa TAG từ một lớp khác và quên thay đổi lớp mà bạn đang đề cập đến. Theo mặc định, mẫu mở rộng thành

private static final String TAG = "$CLASS_NAME$"

Để tránh sử dụng tên lớp cũ sau khi tái cấu trúc, bạn có thể thay đổi tên đó thành

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

Hãy nhớ kiểm tra nút "Chỉnh sửa biến" và đảm bảo rằng CLASS_NAMEbiến được xác định để sử dụng className()Biểu thức và đã chọn "Bỏ qua nếu được xác định".


2

Tôi đã tạo một lớp các biến, phương thức và lớp tĩnh có tên là S.

Sau đây là phương pháp ghi nhật ký:

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

Nó được gọi trong bất kỳ lớp nào vì S.L(this, whaterver_object);The getClass().getName()cũng gắn thêm tên gói, do đó, tôi loại bỏ nó để tránh làm cho thẻ dài một cách không cần thiết.

Ưu điểm:

  1. Ngắn hơn Log.d(TAG,
  2. Không cần chuyển đổi các giá trị int thành chuỗi của chúng. Infact không cần gõtoString
  3. Đừng quên xóa Log.dvì tôi chỉ cần xóa phương thức và vị trí của tất cả các bản ghi được đánh dấu màu đỏ.
  4. Không cần xác định TAG ở đầu hoạt động vì nó lấy tên của lớp.
  5. TAG có tiền tố là CCC(một chuỗi ngắn, dễ nhập) để dễ dàng chỉ liệt kê nhật ký của bạn trong màn hình android trong Android Studio. Đôi khi bạn đang chạy các dịch vụ hoặc các lớp khác đồng thời. Nếu bạn chỉ phải tìm kiếm theo tên hoạt động thì bạn không thể biết chính xác thời điểm nhận được phản hồi dịch vụ và sau đó hành động từ hoạt động của bạn đã xảy ra. Một tiền tố như CCC giúp ích vì nó cung cấp cho bạn nhật ký theo thứ tự thời gian với hoạt động mà nó xảy ra

1
Giải pháp tuyệt vời! Tôi dùng nó! Nhưng tôi đã thay thế Context ctxbằng Object ctxctx.getClass().getName().replace(ctx.getPackageName(), "")bằng ctx.getClass().getSimpleName(). Bằng cách đó, tôi có thể gọi ở S.L(Object, Object)bất kỳ đâu (kể cả ở Fragmentnhững nơi không mở rộng Context, ngay lập tức).
Antonio Vinicius Menezes Medei

1

Bạn có thể sử dụng this.toString()để lấy một số nhận dạng duy nhất cho lớp cụ thể mà bạn in vào nhật ký.


Điều này có thể trở nên đắt đỏ tùy thuộc vào những gì toString()không.
tar

1

Với chi phí cập nhật các chuỗi này khi tôi di chuyển mã giữa các phương thức hoặc đổi tên phương thức, tôi muốn làm như sau. Về mặt triết học, có vẻ như tốt hơn là giữ "vị trí" hoặc "ngữ cảnh" trong thẻ chứ không phải thông báo.

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

}

Lợi ích ở đây là bạn có thể lọc ra một phương pháp duy nhất ngay cả khi nội dung không tĩnh, ví dụ:

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

Hạn chế duy nhất là khi tôi đổi tên f()thành g()tôi cần ghi nhớ chuỗi đó. Ngoài ra, cấu trúc lại IDE tự động sẽ không bắt được những điều này.

Ý tôi là trong một thời gian, tôi đã rất thích sử dụng tên lớp học ngắn gọn LOG_TAG = MyClass.class.getSimpleName(). Tôi thấy chúng khó lọc hơn trong nhật ký vì có ít thứ để tiếp tục hơn.


1

Đó là một câu hỏi rất cũ, nhưng ngay cả khi nghĩ rằng một câu trả lời được cập nhật cho tháng 7 năm 2018 thì việc sử dụng Gỗ sẽ thích hợp hơn. Để ghi nhật ký chính xác, các lỗi và cảnh báo có thể được gửi đến thư viện sự cố của bên thứ ba, chẳng hạn như Firebase hoặc Crashlytics.

Trong lớp triển khai Ứng dụng, bạn nên thêm cái này:

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

Đừng quên sự phụ thuộc của Gỗ.

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

0

Đối với những người dùng truy cập câu hỏi này:

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

0

họ sử dụng Timber cho ứng dụng IOsched 2019 để hiển thị thông tin gỡ lỗi:

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

sử dụng

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

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

lưu ý rằng điều này làm cho Nhật ký chỉ khả dụng trong trạng thái GỬI và tạo điều kiện cho bạn xóa chúng theo cách thủ công để khởi chạy trên Google Play -

khi phát hành ứng dụng trên cửa hàng Play, chúng tôi cần xóa tất cả câu lệnh Nhật ký khỏi ứng dụng để không có dữ liệu ứng dụng nào như thông tin người dùng, dữ liệu ứng dụng ẩn, mã thông báo xác thực khả dụng cho người dùng trong logcat dưới dạng văn bản thuần túy

xem bài viết này https://medium.com/mindorks/better-logging-in-android-using-timber-72e40cc2293d


-2

Tôi thường sử dụng tên phương thức làm thẻ nhưng từ Chủ đề

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

Điều này tránh Ngoại lệ mới.


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

3
Tại sao bạn lại tạo mới RuntimeExceptionchỉ để lấy tên lớp hiện tại? Rất tệ.
asgs

Đây là cách tôi TAG các mục nhập nhật ký của mình, đó là giải pháp duy nhất tôi có thể cấu trúc lại đúng cách khi tôi sao chép một lớp từ một dự án sang một dự án khác, vậy tại sao không. Tôi sẵn sàng nhận các đề xuất nếu bạn có ý tưởng tốt hơn và thoải mái hơn.
Tăng từ

1
Nếu bạn chỉ sao chép các tệp lớp Java từ vị trí này sang vị trí khác mà không cần đổi tên, giải pháp do @gianpi cung cấp là điều cần thiết. Nếu không, bạn chỉ có thể làm this.getClass().getName()mặc dù bạn sẽ phải loại bỏ các phạm vi tĩnh củaTAG
asgs
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.