Как удалить все вызовы журнала отладки перед созданием релизной версии приложения для Android?


397

Согласно Google, я должен « деактивировать любые вызовы методов Log в исходном коде » перед публикацией моего приложения для Android в Google Play. Выдержка из раздела 3 контрольного списка публикации :

Убедитесь, что вы отключили ведение журнала и отключили параметр отладки, прежде чем создавать приложение для выпуска. Вы можете отключить ведение журнала, удалив вызовы методов журнала в исходных файлах.

Мой проект с открытым исходным кодом велик, и каждый раз, когда я выпускаю его, больно делать это вручную. Кроме того, удаление строки журнала потенциально сложно, например:

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

Если я прокомментирую строку журнала, то условие применяется к следующей строке, и скорее всего, load () не вызывается. Достаточно ли редки такие ситуации, чтобы я мог решить, что их не должно быть?

Итак, есть ли лучший способ сделать это на уровне исходного кода? Или, может быть, какой-то умный синтаксис ProGuard для эффективного, но безопасного удаления всех строк журнала?


2
+1, потому что я не помню, это было в контрольном списке публикации.
Rds

51
Чтобы закомментировать неблокированную строку, я использую «; //» вместо «//».
yingted

Если вам нужно отменить это, вы, вероятно, захотите использовать sed 's_^\(\s*Log\.\)_;//'`date|tr -s \ -`'\1_g'вместо этого.
yingted

2
Ссылка, которую добавил Димитар, больше не работает. Я нашел это вместо source.android.com/source/code-style.html#log-sparingly .
JosephL

1
@mboy: Вероятно, для производительности в основном в наши дни, но на старых версиях Android это тоже имеет преимущества для безопасности.
Николас Рауль

Ответы:


488

Я считаю, что гораздо более простое решение - забыть все ifпроверки повсюду и просто использовать ProGuard, чтобы исключить любые вызовы Log.d()или Log.v()вызовы методов, когда мы вызываем нашу releaseцель Ant .

Таким образом, мы всегда выводим отладочную информацию для обычных сборок, и нам не нужно вносить какие-либо изменения в код для релизных сборок. ProGuard также может делать несколько проходов через байт-код для удаления других нежелательных операторов, пустых блоков и может автоматически включать короткие методы, где это необходимо.

Например, вот очень простая конфигурация ProGuard для Android:

-dontskipnonpubliclibraryclasses
-dontobfuscate
-forceprocessing
-optimizationpasses 5

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

Таким образом, вы должны сохранить это в файл, а затем вызвать ProGuard из Ant, передав свой только что скомпилированный JAR-файл и JAR-платформу Android, которую вы используете.

Смотрите также примеры в руководстве ProGuard.


Обновление (4,5 года спустя): в настоящее время я использую Timber для Android регистрации.

Он не только немного лучше, чем Logреализация по умолчанию - тег журнала устанавливается автоматически и легко регистрировать отформатированные строки и исключения, но вы также можете указать различные способы ведения журнала во время выполнения.

В этом примере операторы регистрации будут записываться в logcat только в отладочных сборках моего приложения:

Древесина настроена в моем 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!");
}

Посмотрите пример приложения Timber для более продвинутого примера, где все операторы журнала отправляются в logcat во время разработки, а в процессе производства не регистрируются отладочные операторы, но об ошибках молча сообщается Crashlytics.


59
И почему это не в файле proguard по умолчанию?
Rds

10
+ rds, поскольку производственные стеки отслеживают номера строк, отличные от тех, что в вашем коде, поскольку строки удаляются.
Парень

5
Я могу подтвердить, что удаление вызовов журнала сместит номера строк в трассировке стека. Это не всегда будет не синхронизировано (я провел несколько быстрых тестов, но не могу точно определить, в чем причина, возможно, если вы объедините строку в вызове Log), но иногда это будет несколько строк. Стоит хлопот ИМО за возможность легко удалить журнал звонков.
Тони Чан

5
@Fraggle Из proguard-android.txt в инструментах ADT: «Обратите внимание, что если вы хотите включить оптимизацию, вы не можете просто включить флаги оптимизации в свой файл конфигурации проекта; вместо этого вам нужно будет указать на« proguard-android-optimize ». txt "файл вместо этого из вашего" # project.properties file.
Раанан

3
Как сказал эспинчи в ответе ниже. «Единственная проблема с этим подходом заключается в том, что если вы выполните Log.d (« tag »,« Processed: »+ new ItemCounter (blabla) +« items »), даже если это сообщение журнала не появится в вашей выпущенной версии, StringBuilder используется для создания сообщения, которое может быть дорогостоящим для создания. "Верно ли это и в случае с Timber?
Читранг

117

Все хорошие ответы, но когда я закончил свою разработку, я не хотел использовать операторы if для всех вызовов Log, а также не хотел использовать внешние инструменты.

Поэтому решение, которое я использую, состоит в том, чтобы заменить класс android.util.Log своим собственным классом Log:

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.Log своим собственным классом.


143
Единственная проблема с этим подходом заключается в том, что если вы выполните Log.d («tag», «Processed:» + new ItemCounter (blabla) + «items»), даже если это сообщение журнала не появится в вашей выпущенной версии, StringBuilder используется для создания сообщения, которое может быть дорогим для создания.
Espinchi

9
У этого решения есть большая проблема. эспинчи упомянул только верхушку айсберга. Проблема заключается в том, что когда вы вызываете Log.d("tag", someValue.toString());это, очень легко забыть проверить someValue на предмет отсутствия значения null, что означает, что он может запустить NullPointerExceptionв работе. Он предлагает безопасное решение, но он обманет вас. Мы, private static boolean DEBUGа затемif(DEBUG)Log.d(TAG, msg);
Филипп

2
@espinchi Ваша проблема, кажется, относится ко всем библиотекам журналов, как описано в этом ответе stackoverflow.com/a/15452492/433718 (Slf4j, backlog, ...). Разве не предлагается их использовать?
OneWorld,

1
Единственный способ минимизировать накладные расходы, упомянутые в 1-м комментарии @espinchi, - это изменить методы ведения журнала, чтобы вместо них принимать varargs String. Полное решение описано здесь . Это, очевидно, имеет еще один недостаток: каждый вызов должен редактироваться (а не только одна строка импорта).
Стан

21
Просто к сведению, если вы используете Android Studio и систему сборки Gradle, вы можете использовать static final boolean LOG = BuildConfig.DEBUGэтот файл , и вам не нужно будет его изменять.
ашишдух

61

Я предлагаю иметь где-то статическое логическое значение, указывающее, регистрироваться или нет:

class MyDebug {
  static final boolean LOG = true;
}

Затем, куда бы вы ни захотели войти в свой код, просто сделайте это:

if (MyDebug.LOG) {
  if (условие) Log.i (...);
}

Теперь, когда для MyDebug.LOG установлено значение false, компилятор удаляет весь код внутри таких проверок (поскольку он является статическим финалом, он знает, что во время компиляции код не используется).

Для более крупных проектов вы можете захотеть использовать логические значения в отдельных файлах, чтобы иметь возможность легко включать или отключать ведение журнала там, где это необходимо. Например, это различные константы регистрации, которые мы имеем в оконном менеджере:

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
Разве не было бы менее многословным передать условие в качестве первого параметра?
Сниколас

1
Похоже, это лучшее решение, хотя для каждого оператора журнала требуется дополнительный код: номера строк сохраняются (слабость подхода ProGuard), код для создания сообщения журнала не выполняется ( слабость подхода с классом-оберткой и, очевидно, также подхода с использованием библиотеки журналов) , Использование этого подхода в Googles в примере биллинга приложения согласно @LA_ также поддерживает мои мысли.
OneWorld,

2
@Snicolas Как вы можете передать условие в качестве первого параметра без реализации оболочки? Более того, если вы добавите его в качестве параметра, то перед вводом метода необходимо оценить все параметры, а также строку сообщения. Условие должно быть проверено перед построением параметров. Предложенное решение, возможно, является лучшим, без внешнего инструмента.
type-a1pha

2
Мудрый двоичный код, это лучше. Но кодирование, как это просто много усилий для простого вывода журнала отладки. Читаемость кода значительно падает. Выиграть, проиграть, я думаю ...
Ричард Ле Мезурье

30

Решение Кристофера Proguard является лучшим, но если по какой-то причине вам не нравится Proguard, вот решение с очень низкими технологиями:

Журналы комментариев:

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

Раскомментируйте логи:

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

Ограничение состоит в том, что ваши инструкции по ведению журнала не должны занимать несколько строк.

(Выполните эти строки в оболочке UNIX в корне вашего проекта. Если вы используете Windows, получите слой UNIX или используйте эквивалентные команды Windows)


1
нужно "" после -i в Sed, если работает на Mac (согласно этому ) Спасибо.
Вишал

Я чувствую, что это может быть тем, что я в конечном итоге использую для чего-то, над чем я работаю, потому что мне совсем не повезло делать это с Proguard
Joe Plante

А что если у вас есть Журнал после ветки без скобок, как вы предложили в своем первом посте?
type-a1pha

@ type-a1pha: если вы примете это решение, то вам придется считать блокирующие блоки обязательными.
Николас Рауль

2
@NicolasRaoul Точка с запятой решает эту проблему ( //против ;//)
Алекс Гиттемайер

18

Я хотел бы добавить некоторые подробности об использовании Proguard с Android Studio и Gradle, поскольку у меня было много проблем с удалением строк журнала из окончательного двоичного файла.

Для того, чтобы сделать assumenosideeffectsв Proguard работы, есть обязательное условие.

В вашем файле Gradle вы должны указать использование 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 , тем более, когда я разрабатываю некоторые библиотеки, которые распространяются среди других. Преимущество в том, что по умолчанию нет вывода. И если интегратору нужны какие-то выходные данные журнала, он может использовать Logback for Android и активировать журналы, чтобы журналы можно было перенаправить в файл или в LogCat.

Если мне действительно нужно удалить журналы из окончательной библиотеки, я добавляю в свой файл Proguard (после включения proguard-android-optimize.txtфайла, конечно):

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

Это не работает с новым компилятором Джека
толстяк

Это помогло мне; и в proguard-android-optimize.txtкачестве файла Proguard по умолчанию и -assumenosideeffectsв пользовательском файле Proguard были необходимы! Я использую R8 Shinker (по умолчанию в настоящее время) и логирование Android по умолчанию.
Джоник

10

Я настоятельно рекомендую использовать Timber от Джейка Уортона

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

печатать

"Ваш класс / MSG" без указания тега


2
Timber очень хорош, но если у вас уже есть существующий проект - вы можете попробовать github.com/zserge/log . Это альтернатива android.util.Log для замены и имеет большинство функций, которые есть у Timber, и даже больше.
zserge

zserge, ваше решение для журнала выглядит хорошо. Много возможностей. Рассматривали ли вы добавить правила Lint, как Timber?
jk7

8

Я использовал класс LogUtils, как в примере приложения Google IO. Я изменил это, чтобы использовать специфическую для приложения константу DEBUG вместо BuildConfig.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");
  }
}

+1 за отчет об ошибке, Build.DEBUGкоторый я использовал. Я также отказался от различных «правильных» обходных путей и использую аналогичное стилевое решение для вас.
Ричард Ле Мезурье

7

Я хотел бы рассмотреть возможность использования средства ведения журнала roboguice вместо встроенного android.util.Log

Их средство автоматически отключает отладочные и подробные журналы для сборок выпуска. Кроме того, вы получаете бесплатные функции (например, настраиваемое поведение при ведении журнала, дополнительные данные для каждого журнала и многое другое)

Использование proguard может быть довольно сложным делом, и я не буду испытывать трудности с настройкой и настройкой его работы с вашим приложением, если у вас нет веских причин для этого (отключение журналов не является хорошим)


Очень хороший подход, когда вы не можете использовать Obfuscation .... особенно из-за разрушения roboguice из-за Proguard LOL
Snicolas

1
Обновлена ​​ссылка для средства ведения журнала robojuice: github.com/roboguice/roboguice/wiki/Logging-via-Ln
RenniePet

7

Я публикую это решение, которое применяется специально для пользователей Android Studio. Я также недавно обнаружил Timber и успешно импортировал его в свое приложение, выполнив следующие действия:

Поместите последнюю версию библиотеки в ваш build.gradle:

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

Затем в Android Studios, перейдите в Edit -> Find -> Replace in Path ...

Введите Log.e(TAG,или, однако, вы определили свои сообщения журнала в "Text to find"текстовое поле. Тогда вы просто замените егоTimber.e(

введите описание изображения здесь

Нажмите Найти и затем заменить все.

Android Studios теперь будет просматривать все ваши файлы в вашем проекте и заменять все журналы тембрами.

Единственная проблема, с которой я столкнулся при использовании этого метода, заключается в том, что gradle впоследствии выдает миллион сообщений об ошибках, потому что не может найти «Timber» в импорте для каждого из ваших java-файлов. Просто нажмите на ошибки, и Android Studios автоматически импортирует «Timber» в вашу Java. Как только вы сделали это для всех ваших файлов ошибок, gradle снова скомпилирует.

Вам также нужно поместить этот фрагмент кода в ваш 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\;
Кларк Уилсон

или вы можете использовать структурный поиск и заменить, как показывает Чике Мгбемена в своем посте
Максим Тураев

@MaksimTuraev Ваша ссылка больше не актуальна. Теперь это блог о прическах.
Вадим Котов

Похоже, сообщение удалено = (нигде не могу его найти.
Максим Тураев

@MakimTuraev вот копия с машины Wayback, но изображения не работают - web.archive.org/web/20161004161318/http://chikemgbemena.com/…
Вадим Котов

6

За android.util.Log предоставляет способ включить / отключить журнал:

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

По умолчанию метод isLoggable (...) возвращает false, только после того, как вы установили proprop в устройстве, вот так:

adb shell setprop log.tag.MyAppTag DEBUG

Это означает, что любой журнал выше уровня DEBUG можно распечатать. Ссылка на Android документ:

Проверяет, доступен ли журнал для указанного тега на указанном уровне. Уровень любого тега по умолчанию установлен на INFO. Это означает, что любой уровень выше, включая INFO, будет зарегистрирован. Прежде чем делать какие-либо вызовы метода регистрации, вы должны проверить, должен ли ваш тег регистрироваться. Вы можете изменить уровень по умолчанию, установив системное свойство: 'setprop log.tag. «Где уровень - VERBOSE, DEBUG, INFO, WARN, ERROR, ASSERT или SUPPRESS. SUPPRESS отключит все записи для вашего тега. Вы также можете создать файл local.prop со следующим: '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

Если вы можете запустить глобальную замену (один раз), и после этого сохранить некоторые кодирования конвенции, вы можете следовать шаблону , часто используемый в Android рамках .

Вместо того чтобы писать

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

иметь это как

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

Теперь proguard может удалить 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'
    }
  }
}

С плагином для Android Studio gradle, он достаточно надежный, поэтому вам не нужны дополнительные константы для управления зачисткой.BuildConfig.DEBUG


4

Добавьте следующие строки в Proguard-Rules.txt файл

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

4

введите описание изображения здесь

Это то, что я делал на своих проектах Android.

В Android Studio мы можем выполнить аналогичную операцию, нажав Ctrl + Shift + F для поиска по всему проекту (Command + Shift + F в MacOs) и Ctrl + Shift + R для замены ((Command + Shift + R в MacOs))


Это, кажется, открывает работу с проектами затмения. Опция поиска даже не доступна на Android-студиях.
Саймон

2
в Android Studio вы можете сделать похожий поиск с помощью сочетания клавиш Ctrl + Shift + F
Lins Louis

Пример кода в вопросе объясняет, почему это ненадежно.
Николас Рауль

Это может вызвать проблемы при удалении любой команды, содержащейся в журнале. Например chocolateLog.recipie ();
Эндрю С

Невозможно найти эту опцию для Android Studio 2.1. Кроме того, я могу использовать этот трюк для одного файла за раз обычным поиском / заменой.
ВВБ

3

У меня очень простое решение. Я использую IntelliJ для разработки, поэтому детали меняются, но идея должна применяться ко всем IDE.

Я выбираю в корне моего исходного дерева, щелкаю правой кнопкой мыши и выбираю «заменить». Я тогда решил заменить все "Журнал". с "// Log." Это удаляет все записи журнала. Чтобы вернуть их позже, я повторяю ту же самую замену, но на этот раз, чтобы заменить все "// Журнал". с "Журнал."

Работает просто отлично для меня. Просто не забудьте установить замену с учетом регистра, чтобы избежать несчастных случаев, таких как «Диалог». Для дополнительной уверенности вы также можете сделать первый шаг с помощью «Журнала». в качестве строки для поиска.

Brilliant.


2
Пожалуйста, прочитайте пункт «Если я прокомментирую строку журнала» в моем вопросе.
Николас Рауль

ОК, да, я должен перечитывать чаще после просмотра ответов :). Если у вас есть такие случаи, вам может потребоваться другое решение, например, предложенное ранее, например, размещение всех ваших журналов за другим интерфейсом. Возможно, мое предложение лучше подходит для небольших команд и проектов, где люди хотят избежать лишних библиотек, вы хорошо знаете людей и код и т. Д.
kg_sYy

1
Замена Log.d на; // Log.d также позаботится об этом сценарии «Если».
Джаспер

3

Как подсказал комментарий Зсерге,

Timber очень хорош, но если у вас уже есть существующий проект - вы можете попробовать github.com/zserge/log. Это альтернатива android.util.Log для замены и имеет большинство функций, которые есть у Timber, и даже больше.

его библиотека журналов обеспечивает простое включение / отключение переключения печати журналов, как показано ниже.

Кроме того, требуется только изменить 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
Youngjae

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
Та же проблема, что и в предыдущем решении. Если строковый параметр строится с использованием дорогих вызовов, он все равно тратит ресурсы. Проверка на вызов должна быть сделана до построения переданных параметров.
type-a1pha

1

ProGuard сделает это за вас при сборке релиза, и теперь хорошие новости от android.com:

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

Инструмент ProGuard сокращает, оптимизирует и запутывает ваш код, удаляя неиспользуемый код и переименовывая классы, поля и методы с семантически скрытыми именами. В результате получается файл .apk меньшего размера, который сложнее проанализировать. Поскольку ProGuard затрудняет обратное проектирование вашего приложения, важно использовать его, когда ваше приложение использует функции, чувствительные к безопасности, например, когда вы лицензируете свои приложения.

ProGuard интегрирован в систему сборки Android, поэтому вам не нужно вызывать его вручную. ProGuard запускается только при сборке приложения в режиме выпуска, поэтому вам не нужно иметь дело с запутанным кодом при сборке приложения в режиме отладки. Запуск ProGuard совершенно необязателен, но настоятельно рекомендуется.

Этот документ описывает, как включить и настроить ProGuard, а также как использовать инструмент восстановления, чтобы декодировать запутанные следы стека.


2
По-видимому, по умолчанию он не удаляет ведение журнала отладки. Так что ответ Кристофера звучит лучше.
Николас Рауль

0

Мне нравится использовать Log.d (TAG, некоторая строка, часто String.format ()).

TAG - это всегда имя класса

Transform Log.d (TAG, -> Logd (в тексте вашего класса

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

Таким образом, когда вы будете готовы сделать релиз-версию, установите MainClass.debug в false!


1
проблема с этим и другими решениями, кроме proguard или комментирования, заключается в том, что вы оставляете в коде, что может привести к большому количеству сборок строк. в среднем приложении это не проблема, но если вы пытаетесь оптимизировать, это становится проблемой.
Ласси Киннунен

0

Логи можно удалить с помощью bash в linux и sed:

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

Работает для многострочных журналов. В этом решении вы можете быть уверены, что журналы отсутствуют в рабочем коде.


0

Я знаю, что это старый вопрос, но почему вы не заменили все вызовы журнала чем-то вроде Boolean logCallWasHere = true; // --- остальная часть вашего журнала здесь

Вот почему вы будете знать, когда вы хотите вернуть их обратно, и они не повлияют на ваш вызов оператора if :)


Интересно, что такие строки игнорируются компилятором / оптимизатором. Однако имя переменной должно быть уникальным, поскольку некоторые методы имеют несколько вызовов журнала, и вы не можете объявить одну и ту же переменную дважды.
Николас Рауль

Вы можете объявить переменную вверху по активности и удалить логическое объявление из этой строки;)
masood elsad

0

Почему бы просто не сделать

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

? Не нужно никаких дополнительных библиотек, никаких правил proguard, которые могут испортить проект, и java-компилятор просто пропустит байт-код для этого вызова, когда вы сделаете релизную сборку.


Неудобно, что это более многословно, чем просто написание Log.d("tag","msg");, а также легко забыть написание if(BuildConfig.DEBUG)части.
Николас Рауль

1
Другая проблема заключается в том, что строки остаются в упакованном выпуске.
страя

0

Вот мое решение, если вы не хотите связываться с дополнительными библиотеками или редактировать свой код вручную. Я создал этот блокнот Jupyter, чтобы просмотреть все файлы Java и закомментировать все сообщения журнала. Не идеально, но это сделало работу за меня.


0

мой путь:

1) включить режим выбора столбца (alt + shift + insert)

2) выбрать по одному Log.d (TAG, «текст»); часть «Журнал»

3) затем сделайте shift + ctrl + alt + j

4) нажмите стрелку влево

5) сделать сдвиг + конец

6) нажмите удалить.

это удаляет все вызовы LOG одновременно в файле Java.


0

Вы можете попробовать использовать этот простой традиционный метод:

Ctrl+Shift +R

замещать

Log.e(

С

// Log.e(

Это не будет хорошо работать с примером кода, приведенным в вопросе.
Николас Рауль

0

Просто с kotlin, просто объявите несколько функций верхнего уровня

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

Все журналы отключены DebugLog, когда приложение выпущено.

https://github.com/MustafaFerhan/DebugLog


Это абсолютно неправильно. Это только приводит к тому, что журналы не регистрируются, оно не удаляет их из кода, поэтому они все еще там, чтобы помочь людям перепроектировать ваш код, и это все равно требует затрат на форматирование строк всех этих журналов.
Гленн Мейнард
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.