एंड्रॉइड ऐप के रिलीज़ संस्करण के निर्माण से पहले सभी डिबग लॉगिंग कॉल कैसे निकालें?


397

Google के अनुसार, मुझे अपने एंड्रॉइड ऐप को Google Play पर प्रकाशित करने से पहले " सोर्स कोड में लॉग तरीकों से किसी भी कॉल को निष्क्रिय करना होगा" । प्रकाशन चेकलिस्ट की धारा 3 से निकालें :

रिलीज से पहले अपने आवेदन को बनाने से पहले सुनिश्चित करें कि आप लॉगिंग को निष्क्रिय कर दें और डिबगिंग विकल्प को निष्क्रिय कर दें। आप अपने स्रोत फ़ाइलों में लॉग विधियों में कॉल हटाकर लॉगिंग को निष्क्रिय कर सकते हैं।

मेरा ओपन-सोर्स प्रोजेक्ट बड़ा है और हर बार रिलीज होने पर इसे मैन्युअल रूप से करना एक दर्द है। इसके अतिरिक्त, लॉग लाइन हटाना संभावित रूप से मुश्किल है, उदाहरण के लिए:

if(condition)
  Log.d(LOG_TAG, "Something");
data.load();
data.show();

यदि मैं लॉग लाइन पर टिप्पणी करता हूं, तो स्थिति अगली पंक्ति पर लागू होती है, और संभावनाएं लोड होती हैं () नहीं कहा जाता है। क्या ऐसी स्थितियां काफी दुर्लभ हैं जो मैं तय कर सकता हूं कि इसका अस्तित्व नहीं होना चाहिए?

तो, क्या ऐसा करने के लिए एक बेहतर स्रोत कोड-स्तरीय तरीका है? या शायद कुछ चतुर ProGuard सिंटैक्स कुशलता से लेकिन सुरक्षित रूप से सभी लॉग लाइनों को हटाने के लिए?


2
+1 क्योंकि मुझे याद नहीं था कि यह प्रकाशन चेकलिस्ट में था।
आरडीएस

51
एक गैर-अवरुद्ध लाइन पर टिप्पणी करने के लिए, मैं "//" के बजाय "; //" का उपयोग करता हूं।
यिंग

यदि आपको इसे पूर्ववत करने में सक्षम होने की आवश्यकता है, तो आप संभवतः sed 's_^\(\s*Log\.\)_;//'`date|tr -s \ -`'\1_g'इसके बजाय उपयोग करना चाहेंगे ।
यिंग

2
दिमितर ने जो लिंक जोड़ा वह किसी और काम नहीं आता। मैंने इसके बजाय source.android.com/source/code-style.html#log-sparingly पाया ।
जोसेफ

1
@mboy: संभवतः प्रदर्शन के लिए मुख्य रूप से आजकल, लेकिन पुराने एंड्रॉइड संस्करणों पर इसके सुरक्षा लाभ भी हैं।
निकोलस राउल

जवाबों:


488

मुझे लगता है कि एक आसान समाधान यह है कि हम ifसभी जगहों पर सभी जांच को भूल जाएं और जब हम अपने चींटी लक्ष्य को कॉल करते हैं तो किसी भी या विधि कॉल को हटाने के लिए प्रोगार्ड का उपयोग करें ।Log.d()Log.v()release

इस तरह, हमारे पास हमेशा डिबग जानकारी नियमित बिल्ड के लिए आउटपुट होती है और रिलीज बिल्ड के लिए कोई कोड परिवर्तन नहीं करना पड़ता है। ProGuard अन्य अवांछित बयानों को हटाने के लिए बायटेकोड के ऊपर से कई पास भी कर सकता है, खाली ब्लॉक और उपयुक्त तरीके से स्वचालित रूप से इनलाइन कर सकता है।

उदाहरण के लिए, यहाँ Android के लिए एक बहुत ही बुनियादी ProGuard विन्यास है:

-dontskipnonpubliclibraryclasses
-dontobfuscate
-forceprocessing
-optimizationpasses 5

-keep class * extends android.app.Activity
-assumenosideeffects class android.util.Log {
    public static *** d(...);
    public static *** v(...);
}

तो आप इसे एक फ़ाइल में सहेजेंगे, फिर चींटी से प्रोगार्ड को कॉल करेंगे, जो आपके न्यायपूर्ण संकलन जार और एंड्रॉइड प्लेटफॉर्म जार का उपयोग कर रहे हैं।

ProGuard मैनुअल में भी उदाहरण देखें ।


अद्यतन (4.5 वर्ष बाद): आजकल मैंने टिम्बर का उपयोग किया है एंड्रॉइड लॉगिंग के लिए ।

न केवल यह डिफ़ॉल्ट Logकार्यान्वयन की तुलना में थोड़ा अच्छा है - लॉग टैग स्वचालित रूप से सेट है, और यह स्वरूपित स्ट्रिंग्स और अपवादों को लॉग करना आसान है - लेकिन आप रनटाइम पर विभिन्न लॉगिंग व्यवहारों को भी निर्दिष्ट कर सकते हैं।

इस उदाहरण में, लॉगिंग स्टेटमेंट केवल मेरे ऐप के डिबग बिल्ड में लॉगकैट के लिए लिखा जाएगा:

टिम्बर मेरी Application onCreate()विधि में स्थापित है :

if (BuildConfig.DEBUG) {
  Timber.plant(new Timber.DebugTree());
}

फिर मेरे कोड में कहीं भी मैं आसानी से लॉग इन कर सकता हूं:

Timber.d("Downloading URL: %s", url);
try {
  // ...
} catch (IOException ioe) {
  Timber.e(ioe, "Bad things happened!");
}

अधिक उन्नत उदाहरण के लिए टिम्बर नमूना ऐप देखें , जहां सभी लॉग स्टेटमेंट्स को विकास के दौरान लॉगकैट पर भेजा जाता है और उत्पादन में, कोई डिबग स्टेटमेंट लॉग नहीं किया जाता है, लेकिन त्रुटियों को चुपचाप Crashlytics को रिपोर्ट किया जाता है।


59
और वह डिफ़ॉल्ट प्रूफ़ फ़ाइल में क्यों नहीं है?
आरडीएस

10
+ rds चूंकि यह आपके कोड के उत्पादन स्टैकट्रैक्स लाइन नंबरों को आपके कोड से अलग बनाता है, क्योंकि लाइनें हटा दी जाती हैं।
गाइ

5
मैं पुष्टि कर सकता हूं कि लॉग कॉल को अलग करने से स्टैकट्रैक्स में लाइन नंबर शिफ्ट हो जाएंगे। यह हमेशा सिंक से बाहर नहीं होगा (मैंने कई त्वरित परीक्षण किए, लेकिन वास्तव में यह इंगित नहीं कर सकता कि कारण क्या है, संभवत: यदि आप लॉग कॉल में एक स्ट्रिंग को बदलते हैं), लेकिन कभी-कभी यह कुछ लाइनों से दूर हो जाएगा। लॉग कॉल को आसानी से हटाने की क्षमता के लिए परेशानी IMO के लायक।
टोनी चैन

5
ADF टूल में proguard-android.txt से @Fraggle करें: "ध्यान दें कि यदि आप ऑप्टिमाइज़ेशन को सक्षम करना चाहते हैं, तो आप अपनी स्वयं की प्रोजेक्ट कॉन्फ़िगरेशन फ़ाइल में ऑप्टिमाइज़ेशन फ़्लैग्स को शामिल नहीं कर सकते हैं, इसके बजाय आपको" प्राउड-एंड्रॉइड-ऑप्टिमाइज़ेशन को इंगित करने की आवश्यकता होगी। txt "अपने" # project.properties फ़ाइल से इस के बजाय फ़ाइल।
राणान

3
जैसा कि नीचे दिए गए जवाब में एस्पिनची ने कहा है। "इस दृष्टिकोण के साथ एकमात्र समस्या यह है कि, यदि आप Log.d करते हैं (" टैग "," संसाधित किया गया: "+ नया ItemCounter (blabla) +" आइटम "), भले ही यह लॉग संदेश आपके जारी किए गए संस्करण में प्रकट न हो, StringBuilder का उपयोग संदेश बनाने के लिए किया जाता है, जिसे बनाना महंगा हो सकता है। "क्या टिम्बर मामले में भी यह सच है?
चित्रांग

117

सभी अच्छे उत्तर, लेकिन जब मैं अपने विकास के साथ समाप्त हो गया था तो मैं या तो सभी लॉग कॉल्स के बारे में कथन का उपयोग नहीं करना चाहता था, और न ही मैं बाहरी उपकरणों का उपयोग करना चाहता था।

तो I`m का उपयोग करने वाला समाधान android.util को बदलना है। अपने वर्ग के साथ लॉग करें।

public class Log {
    static final boolean LOG = BuildConfig.DEBUG;

    public static void i(String tag, String string) {
        if (LOG) android.util.Log.i(tag, string);
    }
    public static void e(String tag, String string) {
        if (LOG) android.util.Log.e(tag, string);
    }
    public static void d(String tag, String string) {
        if (LOG) android.util.Log.d(tag, string);
    }
    public static void v(String tag, String string) {
        if (LOG) android.util.Log.v(tag, string);
    }
    public static void w(String tag, String string) {
        if (LOG) android.util.Log.w(tag, string);
    }
}

केवल एक चीज जो मुझे सभी स्रोत फ़ाइलों में करनी थी, वह थी android.util के आयात को बदलने के लिए। अपनी ही कक्षा के साथ काम करें।


143
इस दृष्टिकोण के साथ एकमात्र समस्या यह है कि, यदि आप Log.d करते हैं ("टैग", "संसाधित:" + नया ItemCounter (blabla) + "आइटम"), भले ही यह लॉग संदेश आपके जारी किए गए संस्करण में प्रकट न हो, StringBuilder का उपयोग संदेश बनाने के लिए किया जाता है, जिसे बनाना महंगा हो सकता है।
17

9
इस समाधान में एक बड़ी समस्या है। espinchi ने हिमशैल के सिर्फ टिप का उल्लेख किया है। समस्या यह है कि जब आप कॉल करते हैं Log.d("tag", someValue.toString());कि यह बहुत आसान है कि आप कुछ वल्यू की जांच करना भूल जाएं, क्योंकि इसका मतलब यह नहीं है कि यह NullPointerExceptionउत्पादन में फेंक सकता है । यह एक सुरक्षित समाधान का सुझाव देता है लेकिन यह आपको धोखा देगा। हम एक private static boolean DEBUGऔर फिरif(DEBUG)Log.d(TAG, msg);
दीक्षा

2
@espinchi आपकी चिंता इस तरह की चर्चा stackoverflow.com/a/15452492/433718 (Slf4j, बैकलॉग, ...) पर चर्चा की तरह सभी लॉगिंग पुस्तकालयों पर लागू होती है । क्या उनका उपयोग करने का सुझाव नहीं दिया गया है?
वनवर्ल्ड

1
@Espinchi द्वारा 1-सेंट टिप्पणी में उल्लिखित ओवरहेड्स को कम करने का एकमात्र तरीका इसके बजाय वेरार को स्वीकार करने के लिए लॉगिंग विधियों को बदलना है String। सम्पूर्ण समाधान यहाँ डिक्रिप्टेड है । इसका स्पष्ट रूप से एक और दोष है: प्रत्येक कॉल को संपादित किया जाना चाहिए (न केवल एक आयात लाइन)।
स्टेन

21
सिर्फ एक FYI करें, यदि आप Android Studio और gradle बिल्ड सिस्टम का उपयोग कर रहे हैं, तो आप static final boolean LOG = BuildConfig.DEBUGइस फ़ाइल को कभी भी संशोधित नहीं कर सकते हैं ।
आशीषुध

61

मेरा सुझाव है कि एक स्थिर बूलियन कहीं न कहीं यह दर्शाता है कि लॉग इन करना है या नहीं:

वर्ग MyDebug {
  स्थिर अंतिम बूलियन लॉग = सच;
}

फिर आप अपने कोड में जहां भी लॉग इन करना चाहते हैं, बस यह करें:

अगर (MyDebug.LOG) {
  if (कंडीशन) Log.i (...);
}

अब जब आप MyDebug.LOG को गलत पर सेट करते हैं, तो कंपाइलर ऐसे चेक के अंदर सभी कोड को हटा देगा (चूंकि यह एक स्थिर फाइनल है, यह संकलन समय पर जानता है कि कोड का उपयोग नहीं किया गया है।)

बड़ी परियोजनाओं के लिए, आप व्यक्तिगत फाइल में बूलियन्स रखना शुरू कर सकते हैं ताकि आसानी से सक्षम हो सकें या आवश्यकतानुसार लॉगिंग को अक्षम कर सकें। उदाहरण के लिए, हमारे पास विंडो प्रबंधक में विभिन्न लॉगिंग स्थिरांक हैं:

static final String TAG = "WindowManager";
static final boolean DEBUG = false;
static final boolean DEBUG_FOCUS = false;
static final boolean DEBUG_ANIM = false;
static final boolean DEBUG_LAYOUT = false;
static final boolean DEBUG_RESIZE = false;
static final boolean DEBUG_LAYERS = false;
static final boolean DEBUG_INPUT = false;
static final boolean DEBUG_INPUT_METHOD = false;
static final boolean DEBUG_VISIBILITY = false;
static final boolean DEBUG_WINDOW_MOVEMENT = false;
static final boolean DEBUG_ORIENTATION = false;
static final boolean DEBUG_APP_TRANSITIONS = false;
static final boolean DEBUG_STARTING_WINDOW = false;
static final boolean DEBUG_REORDER = false;
static final boolean DEBUG_WALLPAPER = false;
static final boolean SHOW_TRANSACTIONS = false;
static final boolean HIDE_STACK_CRAWLS = true;
static final boolean MEASURE_LATENCY = false;

इसी कोड के साथ:

    if (DEBUG_FOCUS || DEBUG_WINDOW_MOVEMENT) Log.v(
        TAG, "Adding window " + window + " at "
        + (i+1) + " of " + mWindows.size() + " (after " + pos + ")");

1
मैं ऐसे दृष्टिकोण के लिए भी मतदान करूंगा। यह आधिकारिक Google के इन-ऐप बिलिंग नमूने में भी उपयोग किया जाता है।
LA_

4
क्या पहले पैरामीटर के रूप में स्थिति को पारित करना कम क्रिया नहीं होगा?
Snicolas

1
यह सबसे अच्छा समाधान प्रतीत होता है, हालांकि इसके लिए प्रत्येक लॉग स्टेटमेंट पर अतिरिक्त कोड की आवश्यकता होती है: लाइन नंबर संरक्षित हैं (ProGuard दृष्टिकोण की कमजोरी), लॉग संदेश बनाने के लिए कोई कोड निष्पादित नहीं किया गया है ( आवरण वर्ग दृष्टिकोण की कमजोरी और जाहिर तौर पर लॉगिंग लाइब्रेरी दृष्टिकोण भी) । @LA_ के अनुसार ऐप बिलिंग नमूने में Googles में इस दृष्टिकोण का उपयोग मेरे विचारों का भी समर्थन करता है।
वनवर्ल्ड

2
@Snicolas आप रैपर को लागू किए बिना पहले पैरामीटर के रूप में शर्त कैसे पारित कर सकते हैं? इसके अलावा यदि आप इसे पैरामीटर के रूप में जोड़ते हैं, तो विधि में प्रवेश करने से पहले, सभी मापदंडों का मूल्यांकन करने की आवश्यकता है, अर्थात् संदेश स्ट्रिंग भी। मापदंडों के निर्माण से पहले स्थिति का परीक्षण करने की आवश्यकता होती है। प्रस्तावित समाधान संभवतः सबसे अच्छा है जिसे कोई बाहरी उपकरण नहीं दिया गया है।
टाइप- a1pha

2
बाइनरी कोड वार, यह सबसे अच्छा है। लेकिन इस तरह कोडिंग एक साधारण डिबग लॉग आउटपुट के लिए बहुत प्रयास है। कोड पठनीयता काफी कम हो जाती है। कुछ जीतो, कुछ खो दो, मुझे लगता है ...
रिचर्ड ले मेसुरियर

30

क्रिस्टोफर का Proguard समाधान सबसे अच्छा है, लेकिन अगर किसी भी कारण से आप Proguard को पसंद नहीं करते हैं, तो यहां एक बहुत ही कम तकनीकी समाधान है:

टिप्पणी लॉग:

find . -name "*\.java" | xargs grep -l 'Log\.' | xargs sed -i 's/Log\./;\/\/ Log\./g'

Uncomment लॉग:

find . -name "*\.java" | xargs grep -l 'Log\.' | xargs sed -i 's/;\/\/ Log\./Log\./g'

एक बाधा यह है कि आपके लॉगिंग निर्देश कई लाइनों पर नहीं होने चाहिए।

(अपनी परियोजना के मूल में UNIX शेल में इन पंक्तियों को निष्पादित करें। यदि Windows का उपयोग कर रहे हैं, तो UNIX परत प्राप्त करें या Windows प्रोग्राम का उपयोग करें)


1
मैक में चल रहा है अगर (" इस के अनुसार ) सैड में -i के बाद" "की जरूरत है । धन्यवाद।
विशाल

मुझे लगता है कि यह वही हो सकता है जो मैं किसी ऐसी चीज के लिए उपयोग कर रहा हूं, जिस पर मैं काम कर रहा हूं क्योंकि मेरे पास यह सब करने के लिए बहुत भाग्यशाली नहीं है
जो

और क्या होगा यदि आपके पास शाखा में एक गैर-ब्रैकेट के बाद एक लॉग है, जैसा कि आपने अपनी पहली पोस्ट में सुझाव दिया था?
टाइप- a1pha

@ type-a1pha: यदि आप इस समाधान को अपनाते हैं, तो आपको ब्रैकेट ब्लॉक को अनिवार्य मानना ​​होगा।
निकोलस राउल


18

मैं एंड्रॉइड स्टूडियो और ग्रेडेल के साथ Proguard का उपयोग करने के बारे में कुछ प्राथमिकताएं जोड़ना चाहूंगा, क्योंकि मुझे अंतिम बाइनरी से लॉग लाइनों को हटाने के लिए बहुत सारी समस्याएं थीं।

assumenosideeffectsप्रोग्रेस कार्यों में बनाने के लिए , एक शर्त है।

अपनी श्रेणी फ़ाइल में, आपको proguard-android-optimize.txtडिफ़ॉल्ट फ़ाइल के उपयोग को निर्दिष्ट करना होगा ।

buildTypes {
    release {
        minifyEnabled true
        proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'

        // With the file below, it does not work!
        //proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
    }
}

दरअसल, डिफ़ॉल्ट proguard-android.txtफ़ाइल में, अनुकूलन दो झंडे के साथ अक्षम होता है:

-dontoptimize
-dontpreverify

proguard-android-optimize.txtफ़ाइल उन पंक्तियों को जोड़ने नहीं है, इसलिए अब assumenosideeffectsकाम कर सकते हैं।

फिर, व्यक्तिगत रूप से, मैं SLF4J का उपयोग करता हूं , सभी और जब मैं कुछ पुस्तकालय विकसित करता हूं जो दूसरों को वितरित किए जाते हैं। लाभ यह है कि डिफ़ॉल्ट रूप से कोई आउटपुट नहीं है। और अगर इंटीग्रेटर कुछ लॉग आउटपुट चाहता है, तो वह एंड्रॉइड के लिए लॉगबैक का उपयोग कर सकता है और लॉग को सक्रिय कर सकता है, इसलिए लॉग को फ़ाइल या लॉगकैट पर रीडायरेक्ट किया जा सकता है।

अगर मुझे वास्तव में अंतिम लाइब्रेरी से लॉग को स्ट्रिप करने की आवश्यकता है, तो मैं अपनी प्रोगार्ड फ़ाइल ( proguard-android-optimize.txtपाठ्यक्रम की फ़ाइल को सक्षम करने के बाद) में जोड़ता हूं :

-assumenosideeffects class * implements org.slf4j.Logger {
    public *** trace(...);
    public *** debug(...);
    public *** info(...);
    public *** warn(...);
    public *** error(...);
}

यह नए जैक कंपाइलर के साथ काम नहीं करता है
fattire

इससे मुझे मदद मिली; दोनों proguard-android-optimize.txtडिफ़ॉल्ट के रूप में Proguard फ़ाइल और -assumenosideeffectsकस्टम में Proguard फ़ाइल की जरूरत थी! मैं आर 8 शिन्कर (आजकल डिफ़ॉल्ट) और डिफ़ॉल्ट एंड्रॉइड लॉगिंग का उपयोग कर रहा हूं।
Jonik

10

मैं अत्यधिक जेक व्हार्टन से टिम्बर का उपयोग करने का सुझाव देता हूं

https://github.com/JakeWharton/timber

यह सक्षम / अक्षम करने के साथ आपकी समस्या को हल करता है और स्वचालित रूप से टैग वर्ग जोड़ता है

केवल

public class MyApp extends Application {

  public void onCreate() {
    super.onCreate();
    //Timber
    if (BuildConfig.DEBUG) {
      Timber.plant(new DebugTree());
    }
    ...

लॉग का उपयोग केवल आपके डीबग वेर में किया जाएगा, और फिर उपयोग करें

Timber.d("lol");

या

Timber.i("lol says %s","lol");

प्रिंट

"आपकी कक्षा / संदेश" टैग को निर्दिष्ट किए बिना


2
टिम्बर बहुत अच्छा है, लेकिन अगर आपके पास पहले से ही एक मौजूदा परियोजना है - तो आप github.com/zserge/log की कोशिश कर सकते हैं । यह android.util.Log के लिए एक ड्रॉप-इन प्रतिस्थापन है और इसमें टिम्बर और उससे भी अधिक विशेषताएं हैं।
zserge

zserge, आपका लॉग समाधान अच्छा लग रहा है। खूबियां। क्या आपने टिम्बर जैसे लिंट नियमों को जोड़ने पर विचार किया है?
jk7

8

मैंने Google IO उदाहरण अनुप्रयोग की तरह एक LogUtils वर्ग का उपयोग किया है । मैंने BuildConfig.DEBUG के बजाय एप्लिकेशन विशिष्ट DEBUG स्थिरांक का उपयोग करने के लिए इसे संशोधित किया क्योंकि BuildConfig.DEBUG अविश्वसनीय है । फिर मेरी कक्षाओं में मेरे पास निम्नलिखित हैं।

import static my.app.util.LogUtils.makeLogTag;
import static my.app.util.LogUtils.LOGV;

public class MyActivity extends FragmentActivity {
  private static final String TAG = makeLogTag(MyActivity.class);

  protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    LOGV(TAG, "my message");
  }
}

Build.DEBUGउस पर बग रिपोर्ट के लिए +1 मैं उपयोग करता था। मैंने विभिन्न "सही" वर्कअराउंड के साथ भी हार मान ली और आप के लिए एक समान शैली समाधान का उपयोग करें।
रिचर्ड ले मेसुरियर

7

मैं बिल्ट-इन android.util.Log के बजाय रोबोगुइस की लॉगिंग सुविधा का उपयोग करने पर विचार करूंगा

उनकी सुविधा स्वचालित रूप से डिबग को निष्क्रिय कर देती है और रिलीज़ बिल्ड के लिए वर्बोज़ लॉग बनाती है। साथ ही, आपको मुफ्त में कुछ निफ्टी सुविधाएँ मिलती हैं (जैसे अनुकूलन योग्य व्यवहार, प्रत्येक लॉग के लिए अतिरिक्त डेटा और अधिक)

प्रागार्ड का उपयोग करना काफी परेशानी भरा हो सकता है और जब तक आपके पास इसके लिए एक अच्छा कारण नहीं होता तब तक आपके आवेदन के साथ काम करने और इसे कॉन्फ़िगर करने की परेशानी से मैं नहीं गुजरूंगा।


एक बहुत अच्छा तरीका है जब आप Obfuscation का उपयोग नहीं कर सकते हैं .... विशेष रूप से लुटेगियों की वजह से ब्रेकिंग की वजह से LOL
स्निकोलस

1
रब्बोजाइस की लॉगिंग सुविधा के लिए अद्यतन लिंक: github.com/roboguice/roboguice/wiki/Logging-via-Ln
RenniePet

7

मैं इस समाधान को पोस्ट कर रहा हूं जो विशेष रूप से एंड्रॉइड स्टूडियो उपयोगकर्ताओं के लिए लागू होता है। मैंने हाल ही में टिम्बर की भी खोज की है और इसे निम्न तरीके से अपने ऐप में सफलतापूर्वक आयात किया है:

लाइब्रेरी के नवीनतम संस्करण को अपने बिल्ड.ग्रेड में रखें:

compile 'com.jakewharton.timber:timber:4.1.1'

फिर एंड्रॉइड स्टूडियो में, संपादित करें -> ढूंढें -> पथ में बदलें ...

टाइप करें Log.e(TAG,या फिर आपने अपने लॉग संदेशों को "Text to find"टेक्स्टबॉक्स में परिभाषित किया है । तो फिर तुम इसे के साथ बदलेंTimber.e(

यहां छवि विवरण दर्ज करें

ढूँढें पर क्लिक करें और फिर सभी को बदलें।

एंड्रॉइड स्टूडियो अब आपके प्रोजेक्ट में आपकी सभी फाइलों के माध्यम से जाएगा और सभी लॉग को टिम्बर्स से बदल देगा।

इस पद्धति के साथ मेरी एकमात्र समस्या यह है कि ग्रेडेल में बाद में witha मिलियन त्रुटि संदेश आते हैं क्योंकि यह आपकी प्रत्येक जावा फाइलों के आयात में "टिम्बर" नहीं खोज सकता है। बस त्रुटियों पर क्लिक करें और एंड्रॉइड स्टूडियो स्वचालित रूप से "टिम्बर" को आपके जावा में आयात करेगा। एक बार जब आप इसे अपनी सभी त्रुटियों की फाइलों के लिए कर लेते हैं, तो एक बार फिर से संकलन होगा।

आपको onCreateअपनी Applicationकक्षा के इस कोड को अपनी विधि में रखना होगा :

    if (BuildConfig.DEBUG) {
        Timber.plant(new Timber.DebugTree());
    }

यह एप्लिकेशन लॉगिंग के परिणामस्वरूप होगा जब आप विकास मोड में होंगे उत्पादन में नहीं। आप BuildConfig.RELEASEरिलीज़ मोड में लॉगिंग के लिए भी हो सकते हैं ।


3
अपने आयातों के लिए एक ही काम करने की कोशिश करें, और सुनिश्चित करें कि नियमित अभिव्यक्ति बॉक्स की जाँच की जाती है पाठ खोजने के लिए: इसके import android\.util\.Log\;साथ बदलें:import android\.util\.Log\;\nimport timber\.log\.Timber\;
क्लार्क विल्सन

या आप उपयोग कर सकते structual खोज और Chike Mgbemena शो की तरह की जगह अपने में पोस्ट
Maksim Turaev

@MaksimTuraev आपका लिंक अब प्रासंगिक नहीं है। अब यह हेयर स्टाइल के बारे में एक ब्लॉग है।
वादिम कोटोव

ऐसा लगता है कि पोस्ट हटा दिया जाता है = (नहीं इसे कहीं भी मिल सकता है।
Maksim Turaev

@MaksimTuraev यहां वेकबैक मशीन की एक प्रति है, लेकिन छवियां टूटी हुई हैं - web.archive.org/web/20161004161318/http://chikemgbemena.com/ ...
वादिम

6

प्रति android.util.Log लॉग को सक्षम / अक्षम करने का एक तरीका प्रदान करता है:

public static native boolean isLoggable(String tag, int level);

डिफॉल्ट विधि लोजिबल (...) गलत है, केवल तभी जब आप डिवाइस में सेटप्रॉप इसे पसंद करते हैं:

adb shell setprop log.tag.MyAppTag DEBUG

इसका मतलब यह है कि DEBUG स्तर से ऊपर के किसी भी लॉग को प्रिंट किया जा सकता है। संदर्भ एंड्रॉयड डॉक्टर:

यह देखने के लिए जाँच करता है कि निर्दिष्ट टैग के लिए लॉग निर्दिष्ट स्तर पर लॉग करने योग्य है या नहीं। किसी भी टैग का डिफ़ॉल्ट स्तर INFO पर सेट है। इसका मतलब है कि INFO के ऊपर और सम्‍मिलित किसी भी स्‍तर को लॉग किया जाएगा। इससे पहले कि आप लॉगिंग विधि में कोई कॉल करें, आपको यह देखने के लिए जांचना चाहिए कि क्या आपका टैग लॉग होना चाहिए। आप सिस्टम गुण सेट करके डिफ़ॉल्ट स्तर बदल सकते हैं: 'setprop log.tag। 'जहां का स्तर या तो VERBOSE, DEBUG, INFO, WARN, ERROR, ASSERT, या संक्षिप्तता है। समर्थन आपके टैग के लिए सभी लॉगिंग बंद कर देगा। आप इसमें एक स्थानीय फ़ाइल भी बना सकते हैं जिसमें निम्नलिखित हैं: 'log.tag। =' और उस जगह को /data/local.prop में।

इसलिए हम कस्टम लॉग का उपयोग कर सकते हैं:

public final class Dlog 
{
    public static void v(String tag, String msg)
    {
        if (Log.isLoggable(tag, Log.VERBOSE))
            Log.v(tag, msg);
    }

    public static void d(String tag, String msg)
    {
        if (Log.isLoggable(tag, Log.DEBUG))
            Log.d(tag, msg);
    }

    public static void i(String tag, String msg)
    {
        if (Log.isLoggable(tag, Log.INFO))
            Log.i(tag, msg);
    }

    public static void w(String tag, String msg)
    {
        if (Log.isLoggable(tag, Log.WARN))
            Log.w(tag, msg);
    }

    public static void e(String tag, String msg)
    {
        if (Log.isLoggable(tag, Log.ERROR))
            Log.e(tag, msg);
    }
}

6

यदि आप एक वैश्विक प्रतिस्थापन (एक बार) चला सकते हैं, और उसके बाद कुछ कोडिंग कन्वेंशन को संरक्षित करते हैं, तो आप अक्सर एंड्रॉइड फ्रेमवर्क में उपयोग किए जाने वाले पैटर्न का पालन कर सकते हैं ।

लिखने के बजाय

Log.d(TAG, string1 + string2 + arg3.toString());

के रूप में है

if (BuildConfig.DEBUG) Log.d(TAG, string1 + String.format("%.2f", arg2) + arg3.toString());

अब प्रोगार्ड StringBuilder और सभी स्ट्रिंग्स और तरीकों को हटा सकते हैं, जो रास्ते पर उपयोग करते हैं, अनुकूलित रिलीज DEX से। उपयोग करें proguard-android-optimize.txtऔर आपको अपने Android.util.Log के बारे में चिंता करने की आवश्यकता नहीं है proguard-rules.pro:

android {
  
  buildTypes {
    release {
      minifyEnabled true
      proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
    }
  }
}

एंड्रॉइड स्टूडियो ग्रेडल प्लगइन के साथ, काफी विश्वसनीय है, इसलिए आपको स्ट्रिपिंग को नियंत्रित करने के लिए अतिरिक्त स्थिरांक की आवश्यकता नहीं है।BuildConfig.DEBUG


4

यहां छवि विवरण दर्ज करें

यही मैंने अपने android प्रोजेक्ट्स पर किया है।

Android Studio में हम पूरे प्रोजेक्ट (Ctrl + Shift + F को MacOs में) और Ctrl + Shift + R से रिप्लेस ((MacOs में कमांड + शिफ्ट + आर) में खोजने के लिए Ctrl + Shift + F के समान ऑपरेशन कर सकते हैं।


यह ग्रहण परियोजनाओं के साथ काम करने लगता है। Android स्टूडियो पर खोज विकल्प उपलब्ध नहीं है।
साइमन

2
एंड्रॉइड स्टूडियो में आप Ctrl + Shift + F शॉर्टकट
Lins Louis

प्रश्न में उदाहरण कोड बताता है कि यह विश्वसनीय क्यों नहीं है।
निकोलस राउल

यह लॉग में शामिल किसी भी कमांड को हटाने में समस्या पैदा कर सकता है। उदाहरण के लिए ChocolateLog.recipie ();
एंड्रयू एस

Android स्टूडियो 2.1 के लिए इस विकल्प को खोजने में असमर्थ। इसके अलावा, मैं सामान्य खोज / प्रतिस्थापन द्वारा एक बार में 1 फ़ाइल पर इस ट्रिक का उपयोग कर सकता हूं।
वीवीबी

3

मेरे पास एक बहुत ही सरल उपाय है। मैं IntelliJ का उपयोग विकास के लिए करता हूं, इसलिए विवरण अलग-अलग होते हैं, लेकिन विचार सभी IDE पर लागू होना चाहिए।

मैं अपने स्रोत पेड़ की जड़ को चुनता हूं, राइट-क्लिक करें और "बदलें" का चयन करें। मैं तो सभी "लॉग" को बदलने का विकल्प चुनता हूं। "// लॉग" के साथ। यह सभी लॉग स्टेटमेंट को हटा देता है। बाद में उन्हें वापस रखने के लिए मैं उसी रिप्लेसमेंट को दोहराता हूं लेकिन इस बार सभी "// लॉग" की जगह लें। "लॉग" के साथ।

मेरे लिए बस महान काम करता है। बस "डायलॉग" जैसी दुर्घटनाओं से बचने के लिए केस को संवेदनशील के रूप में प्रतिस्थापित करने के लिए याद रखें। अतिरिक्त आश्वासन के लिए आप "लॉग" के साथ पहला चरण भी कर सकते हैं। खोज करने के लिए स्ट्रिंग के रूप में।

प्रतिभाशाली।


2
कृपया मेरे प्रश्न में "यदि मैं लॉग लाइन पर टिप्पणी करता हूं" पैराग्राफ पढ़ें ।
निकोलस राउल

ठीक है, हाँ मुझे उत्तर ब्राउज़ करने के बाद अधिक बार पढ़ना चाहिए :)। यदि आपके पास ऐसे मामले हैं, तो आप एक अलग समाधान चाहते हैं जैसे कि सुझाव दिया जाए जैसे कि अपने सभी लॉग को किसी अन्य इंटरफ़ेस के पीछे रखना। मेरा सुझाव शायद छोटी टीमों और परियोजनाओं के लिए बेहतर काम करता है, जहां लोग अतिरिक्त लॉगिंग
लिबास

1
// के साथ Log.d जगह; Log.d उस "अगर" परिदृश्य का भी ख्याल रखता है।
जस्पर

3

जैसा कि zserge की टिप्पणी ने सुझाव दिया है,

टिम्बर बहुत अच्छा है, लेकिन अगर आपके पास पहले से ही एक मौजूदा परियोजना है - तो आप github.com/zserge/log की कोशिश कर सकते हैं। यह android.util.Log के लिए एक ड्रॉप-इन प्रतिस्थापन है और इसमें टिम्बर और उससे भी अधिक विशेषताएं हैं।

उसका लॉग लाइब्रेरी नीचे के रूप में सरल सक्षम / अक्षम लॉग प्रिंटिंग स्विच प्रदान करता है।

इसके अलावा, इसे केवलimport लाइनों को बदलने की आवश्यकता है , और कथन के लिए कुछ भी बदलने की आवश्यकता नहीं हैLog.d(...);

if (!BuildConfig.DEBUG)
    Log.usePrinter(Log.ANDROID, false); // from now on Log.d etc do nothing and is likely to be optimized with JIT

क्या आपको प्रत्येक गतिविधि / फ़्रैगमेंट में, या बस एक ही स्थान पर कोड की एक पंक्ति रखनी है?
नूह टेरनुलो

व्युत्पन्न अनुप्रयोग फ़ाइल में @NoahTernullo //। DefaultApplication.java
यंगजई

3

अपने प्रोगार्ड- rules.txt फ़ाइल का अनुसरण करें

-assumenosideeffects class android.util.Log {
  public static *** d(...);
  public static *** w(...);
  public static *** v(...);
  public static *** i(...);
}

1

मैंने विभिन्न लॉग स्तरों के लिए सहायता प्रदान करके और कोड को लाइव डिवाइस या एमुलेटर पर चलाया जा रहा है या नहीं इसके आधार पर लॉग स्तर को स्वचालित रूप से बदलकर उपरोक्त समाधान पर सुधार किया है।

public class Log {

final static int WARN = 1;
final static int INFO = 2;
final static int DEBUG = 3;
final static int VERB = 4;

static int LOG_LEVEL;

static
{
    if ("google_sdk".equals(Build.PRODUCT) || "sdk".equals(Build.PRODUCT)) {
        LOG_LEVEL = VERB;
    } else {
        LOG_LEVEL = INFO;
    }

}


/**
 *Error
 */
public static void e(String tag, String string)
{
        android.util.Log.e(tag, string);
}

/**
 * Warn
 */
public static void w(String tag, String string)
{
        android.util.Log.w(tag, string);
}

/**
 * Info
 */
public static void i(String tag, String string)
{
    if(LOG_LEVEL >= INFO)
    {
        android.util.Log.i(tag, string);
    }
}

/**
 * Debug
 */
public static void d(String tag, String string)
{
    if(LOG_LEVEL >= DEBUG)
    {
        android.util.Log.d(tag, string);
    }
}

/**
 * Verbose
 */
public static void v(String tag, String string)
{
    if(LOG_LEVEL >= VERB)
    {
        android.util.Log.v(tag, string);
    }
}


}

1
पिछले समाधान के रूप में एक ही समस्या। यदि स्ट्रिंग पैरामीटर महंगी कॉल का उपयोग करके बनाया गया है, तो यह अभी भी संसाधनों को बर्बाद करता है। कॉलिंग के लिए चेक पास किए गए मापदंडों के निर्माण से पहले किए जाने की आवश्यकता है।
टाइप- a1pha

1

ProGuard आपके लिए अपनी रिलीज़ बिल्ड और अब android.com से खुशखबरी:

http://developer.android.com/tools/help/proguard.html

ProGuard उपकरण सिकुड़ता है, अनुकूलन करता है, और अप्रयुक्त कोड को हटाकर और कोड का नाम बदलकर, फ़ील्ड्स, फ़ील्ड्स और विधियों को शब्दार्थ रूप से अस्पष्ट नामों के साथ बदल देता है। परिणाम एक छोटे आकार की .apk फ़ाइल है, जो रिवर्स इंजीनियर के लिए अधिक कठिन है। क्योंकि ProGuard आपके एप्लिकेशन को रिवर्स इंजीनियर के लिए कठिन बना देता है, इसलिए यह महत्वपूर्ण है कि आप इसका उपयोग तब करें जब आपका एप्लिकेशन उन विशेषताओं का उपयोग करता है जो सुरक्षा के प्रति संवेदनशील होती हैं जैसे कि जब आप अपने एप्लिकेशन को लाइसेंस दे रहे हों।

ProGuard को एंड्रॉइड बिल्ड सिस्टम में एकीकृत किया गया है, इसलिए आपको इसे मैन्युअल रूप से लागू करने की आवश्यकता नहीं है। ProGuard केवल तभी चलता है जब आप अपने एप्लिकेशन को रिलीज़ मोड में बनाते हैं, इसलिए आपको डिबग मोड में अपना एप्लिकेशन बनाते समय मोटे कोड से निपटने की आवश्यकता नहीं होती है। ProGuard रन पूरी तरह से वैकल्पिक है, लेकिन अत्यधिक अनुशंसित है।

इस दस्तावेज़ में बताया गया है कि ProGuard को कैसे सक्षम और कॉन्फ़िगर किया जाए और साथ ही साथ फ़ोकस किए गए स्टैक ट्रैक्स को डिकोड करने के लिए रिट्रेसमेंट टूल का उपयोग करें


2
यह डिबग लॉगिंग को डिफ़ॉल्ट रूप से हटाने के लिए नहीं लगता है, हालांकि। तो क्रिस्टोफर का जवाब बेहतर लगता है।
निकोलस राउल

0

मुझे Log.d (TAG, कुछ स्ट्रिंग, अक्सर एक String.format ()) का उपयोग करना पसंद है।

TAG हमेशा क्लास का नाम है

Log.d.d (TAG, -> Logd) को अपनी कक्षा के पाठ में बदलें

private void Logd(String str){
    if (MainClass.debug) Log.d(className, str);
}

इस तरह जब आप एक रिलीज़ संस्करण बनाने के लिए तैयार हैं, तो MainClass.debug को झूठा सेट करें!


1
इसके अलावा और अन्य समाधानों के साथ समस्या का कारण बनता है या उन्हें टिप्पणी करना कि आप कोड में छोड़ रहे हैं, जिससे संभवतः बड़ी मात्रा में स्ट्रिंग का निर्माण होता है। एक औसत ऐप में समस्या नहीं है, लेकिन अगर आप इसे अनुकूलित करने की कोशिश कर रहे हैं तो यह एक समस्या बन जाती है।
लस्सी किन्नुनेन

0

लाइनक्स और सेड में बैश का उपयोग करके लॉग को हटाया जा सकता है:

find . -name "*\.java" | xargs sed -ri ':a; s%Log\.[ivdwe].*\);%;%; ta; /Log\.[ivdwe]/ !b; N; ba'

बहुस्तरीय लॉग के लिए काम करता है। इस समाधान में आप सुनिश्चित हो सकते हैं, कि लॉग उत्पादन कोड में मौजूद नहीं हैं।


0

मुझे पता है कि यह एक पुराना प्रश्न है, लेकिन आपने अपने सभी लॉग कॉल को बूलियन logCallWasHere = true जैसी किसी चीज़ से प्रतिस्थापित क्यों नहीं किया; // --- अपना बाकी का लॉग यहां

यह आपको तब पता चलेगा, जब आप उन्हें वापस लाना चाहते हैं, और वे आपके कॉल स्टेटमेंट को प्रभावित नहीं करेंगे :)


दिलचस्प है, उम्मीद है कि इस तरह की लाइनों को फिर कंपाइलर / ऑप्टिमाइज़र द्वारा अनदेखा किया जाता है। हालांकि, चर नाम को अद्वितीय होने की आवश्यकता होगी, क्योंकि कुछ विधियों में कई लॉग कॉल हैं, और आप एक ही चर को दो बार घोषित नहीं कर सकते।
निकोलस राउल

आप गतिविधि पर शीर्ष पर चर की घोषणा कर सकते हैं और इस रेखा से बूलियन घोषणा को हटा सकते हैं;)
मसूद एलसाड

0

सिर्फ क्यों नहीं

if(BuildConfig.DEBUG)
  Log.d("tag","msg");

? जब आप रिलीज़ बिल्ड बनाते हैं, तो अतिरिक्त लाइब्रेरी की आवश्यकता नहीं होती है, जो कि प्रोजेक्ट और जावा कंपाइलर को स्क्रू करने के लिए कोई नियम नहीं है।


एक असुविधा यह है कि यह सिर्फ लिखने की तुलना में अधिक क्रियात्मक है Log.d("tag","msg");, और यह भी कि if(BuildConfig.DEBUG)भाग लिखना भूल जाना आसान है ।
निकोलस राउल

1
इसके साथ एक और समस्या पैक्ड रिलीज में बनी हुई है।
स्ट्रेटा

0

यदि आप अतिरिक्त पुस्तकालयों के साथ गड़बड़ नहीं करना चाहते हैं या अपने कोड को मैन्युअल रूप से संपादित करना चाहते हैं तो यहां मेरा समाधान है। मैंने सभी Java फ़ाइलों पर जाने और सभी लॉग संदेशों पर टिप्पणी करने के लिए इस Jupyter नोटबुक को बनाया । सही नहीं है लेकिन यह मेरे लिए काम कर गया।


0

मरे तरीके:

1) कॉलम चयन मोड सक्षम करें (alt + Shift + सम्मिलित करें)

2) एक Log.d (TAG, "text") पर चयन करें; भाग 'लॉग'।

3) फिर Shift + ctrl + alt + j करें

4) बायाँ तीर क्लिक करें

5) शिफ्ट + एंड करें

६) हिट डिलीट।

यह जावा फ़ाइल में एक बार में सभी लॉग कॉल को हटा देता है।


0

आप इस सरल पारंपरिक विधि का उपयोग करने की कोशिश कर सकते हैं:

Ctrl+ Shift+R

बदलने के

Log.e(

साथ में

// Log.e(

यह प्रश्न में दिए गए उदाहरण कोड के साथ अच्छी तरह से काम नहीं करेगा।
निकोलस राउल

0

कोटलिन के साथ आसान, बस कुछ शीर्ष स्तर के कार्यों की घोषणा करें

val isDebug: Boolean
    get() = BuildConfig.DEBUG

fun logE(tag: String, message: String) {
    if (isDebug) Log.e(tag, message)
}

fun logD(tag: String, message: String) {
    if (isDebug) Log.d(tag, message)
}

-1

सबसे सरल तरीका;

उपयोग DebugLog

एप्लिकेशन के रिलीज़ होने पर सभी लॉग डीबग्लॉग द्वारा अक्षम हो जाते हैं।

https://github.com/MustafaFerhan/DebugLog


यह बिलकुल गलत है। यह केवल लॉग को लॉग नहीं करने का कारण बनता है, यह उन्हें कोड से नहीं हटाता है, इसलिए वे अभी भी लोगों को आपके कोड को रिवर्स-इंजीनियर बनाने में मदद करने के लिए हैं, और यह अभी भी उन सभी लॉग के तार को स्वरूपित करने की लागत है।
ग्लेन मेनार्ड
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.