Как включить / отключить уровни журналов в Android? - PullRequest
146 голосов
/ 07 января 2010

У меня есть много операторов регистрации для отладки, например.

Log.v(TAG, "Message here");
Log.w(TAG, " WARNING HERE");

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

Ответы [ 18 ]

191 голосов
/ 07 января 2010

Документация Android гласит следующее об уровнях журналов :

Verbose никогда не должен компилироваться в приложение, кроме как во время разработки. Журналы отладки компилируются, но удаляются во время выполнения. Журналы ошибок, предупреждений и информации всегда сохраняются.

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

Согласно документации, вы можете настроить ведение журнала на устройстве разработки, используя Свойства системы. Устанавливается свойство log.tag.<YourTag>, и оно должно быть установлено в одно из следующих значений: VERBOSE, DEBUG, INFO, WARN, ERROR, ASSERT или SUPPRESS. Более подробная информация об этом доступна в документации по методу isLoggable().

Вы можете временно установить свойства с помощью команды setprop. Например:

C:\android>adb shell setprop log.tag.MyAppTag WARN
C:\android>adb shell getprop log.tag.MyAppTag
WARN

В качестве альтернативы, вы можете указать их в файле /data/local.prop следующим образом:

log.tag.MyAppTag=WARN

Более поздние версии Android требуют, чтобы /data/local.prop был доступен только для чтения . Этот файл читается во время загрузки, поэтому вам нужно будет перезагрузить его после обновления. Если /data/local.prop доступна для записи во всем мире, она, вероятно, будет проигнорирована.

Наконец, вы можете установить их программно, используя System.setProperty() метод .

88 голосов
/ 07 января 2010

Самый простой способ - это, вероятно, запустить ваш скомпилированный JAR через ProGuard перед развертыванием с такой конфигурацией, как:

-assumenosideeffects class android.util.Log {
    public static int v(...);
}

Это будет & mdash; кроме всех других оптимизаций ProGuard & mdash; удалите все подробные операторы журнала непосредственно из байт-кода.

78 голосов
/ 07 января 2010

Распространенным способом является создание int с именем loglevel и определение его уровня отладки на основе loglevel.

public static int LOGLEVEL = 2;
public static boolean ERROR = LOGLEVEL > 0;
public static boolean WARN = LOGLEVEL > 1;
...
public static boolean VERBOSE = LOGLEVEL > 4;

    if (VERBOSE) Log.v(TAG, "Message here"); // Won't be shown
    if (WARN) Log.w(TAG, "WARNING HERE");    // Still goes through

Позже вы можете просто изменить LOGLEVEL для всех уровней вывода отладки.

18 голосов
/ 06 февраля 2011

Я выбрал простой путь - создал класс-обертку, который также использует списки переменных параметров.

 public class Log{
        public static int LEVEL = android.util.Log.WARN;


    static public void d(String tag, String msgFormat, Object...args)
    {
        if (LEVEL<=android.util.Log.DEBUG)
        {
            android.util.Log.d(tag, String.format(msgFormat, args));
        }
    }

    static public void d(String tag, Throwable t, String msgFormat, Object...args)
    {
        if (LEVEL<=android.util.Log.DEBUG)
        {
            android.util.Log.d(tag, String.format(msgFormat, args), t);
        }
    }

    //...other level logging functions snipped
10 голосов
/ 16 марта 2013

Лучший способ - использовать SLF4J API + некоторые его реализации.

Для приложений Android вы можете использовать следующее:

  1. Android Logger - это легкая, но простая в настройке реализация SLF4J (<50 КБ). </li>
  2. LOGBack - самая мощная и оптимизированная реализация, но ее размер составляет около 1 Мб.
  3. Любой другой на ваш вкус: slf4j-android, slf4android.
8 голосов
/ 07 января 2010

Вы должны использовать

    if (Log.isLoggable(TAG, Log.VERBOSE)) {
        Log.v(TAG, "my log message");
    }
4 голосов
/ 20 октября 2011

Удаление журналов с помощью proguard (см. Ответ от @Christopher) было простым и быстрым, но это приводило к тому, что трассировки стека из производства не соответствовали источнику, если в файле была какая-либо запись отладки.

Вместо этого, вот техника, которая использует разные уровни ведения журнала в разработке и производстве, предполагая, что Proguard используется только в производстве. Он распознает производственный процесс, видя, переименовал ли proguard заданное имя класса (в примере я использую «com.foo.Bar» - вы бы заменили его на полное имя класса, которое, как вы знаете, будет переименовано proguard).

В этой технике используется регистрация общего достояния.

private void initLogging() {
    Level level = Level.WARNING;
    try {
        // in production, the shrinker/obfuscator proguard will change the
        // name of this class (and many others) so in development, this
        // class WILL exist as named, and we will have debug level
        Class.forName("com.foo.Bar");
        level = Level.FINE;
    } catch (Throwable t) {
        // no problem, we are in production mode
    }
    Handler[] handlers = Logger.getLogger("").getHandlers();
    for (Handler handler : handlers) {
        Log.d("log init", "handler: " + handler.getClass().getName());
        handler.setLevel(level);
    }
}
3 голосов
/ 14 июня 2015

Есть небольшая замена стандартного класса журнала Android - https://github.com/zserge/log

В основном все, что вам нужно сделать, это заменить импорт с android.util.Log на trikita.log.Log.Затем в вашем Application.onCreate() или в каком-либо статическом инициализаторе проверьте BuilConfig.DEBUG или любой другой флаг и используйте Log.level(Log.D) или Log.level(Log.E), чтобы изменить минимальный уровень журнала.Вы можете использовать Log.useLog(false), чтобы вообще отключить ведение журнала.

3 голосов
/ 23 декабря 2011

Log4j или slf4j также могут использоваться в качестве каркасов ведения журналов в Android вместе с logcat. Смотрите проект android-logging-log4j или log4j в поддержке android

2 голосов
/ 05 сентября 2013

Вот более сложное решение. Вы получите полную трассировку стека, и метод toString () будет вызываться только при необходимости (Performance). Атрибут BuildConfig.DEBUG будет иметь значение false в рабочем режиме, поэтому все журналы трассировки и отладки будут удалены. Компилятор горячих точек имеет возможность удалить вызовы из-за конечных статических свойств.

import java.io.ByteArrayOutputStream;
import java.io.PrintStream;
import android.util.Log;

public class Logger {

    public enum Level {
        error, warn, info, debug, trace
    }

    private static final String DEFAULT_TAG = "Project";

    private static final Level CURRENT_LEVEL = BuildConfig.DEBUG ? Level.trace : Level.info;

    private static boolean isEnabled(Level l) {
        return CURRENT_LEVEL.compareTo(l) >= 0;
    }

    static {
        Log.i(DEFAULT_TAG, "log level: " + CURRENT_LEVEL.name());
    }

    private String classname = DEFAULT_TAG;

    public void setClassName(Class<?> c) {
        classname = c.getSimpleName();
    }

    public String getClassname() {
        return classname;
    }

    public boolean isError() {
        return isEnabled(Level.error);
    }

    public boolean isWarn() {
        return isEnabled(Level.warn);
    }

    public boolean isInfo() {
        return isEnabled(Level.info);
    }

    public boolean isDebug() {
        return isEnabled(Level.debug);
    }

    public boolean isTrace() {
        return isEnabled(Level.trace);
    }

    public void error(Object... args) {
        if (isError()) Log.e(buildTag(), build(args));
    }

    public void warn(Object... args) {
        if (isWarn()) Log.w(buildTag(), build(args));
    }

    public void info(Object... args) {
        if (isInfo()) Log.i(buildTag(), build(args));
    }

    public void debug(Object... args) {
        if (isDebug()) Log.d(buildTag(), build(args));
    }

    public void trace(Object... args) {
        if (isTrace()) Log.v(buildTag(), build(args));
    }

    public void error(String msg, Throwable t) {
        if (isError()) error(buildTag(), msg, stackToString(t));
    }

    public void warn(String msg, Throwable t) {
        if (isWarn()) warn(buildTag(), msg, stackToString(t));
    }

    public void info(String msg, Throwable t) {
        if (isInfo()) info(buildTag(), msg, stackToString(t));
    }

    public void debug(String msg, Throwable t) {
        if (isDebug()) debug(buildTag(), msg, stackToString(t));
    }

    public void trace(String msg, Throwable t) {
        if (isTrace()) trace(buildTag(), msg, stackToString(t));
    }

    private String buildTag() {
        String tag ;
        if (BuildConfig.DEBUG) {
            StringBuilder b = new StringBuilder(20);
            b.append(getClassname());

            StackTraceElement stackEntry = Thread.currentThread().getStackTrace()[4];
            if (stackEntry != null) {
                b.append('.');
                b.append(stackEntry.getMethodName());
                b.append(':');
                b.append(stackEntry.getLineNumber());
            }
            tag = b.toString();
        } else {
            tag = DEFAULT_TAG;
        }
    }

    private String build(Object... args) {
        if (args == null) {
            return "null";
        } else {
            StringBuilder b = new StringBuilder(args.length * 10);
            for (Object arg : args) {
                if (arg == null) {
                    b.append("null");
                } else {
                    b.append(arg);
                }
            }
            return b.toString();
        }
    }

    private String stackToString(Throwable t) {
        ByteArrayOutputStream baos = new ByteArrayOutputStream(500);
        baos.toString();
        t.printStackTrace(new PrintStream(baos));
        return baos.toString();
    }
}

используйте так:

Loggor log = new Logger();
Map foo = ...
List bar = ...
log.error("Foo:", foo, "bar:", bar);
// bad example (avoid something like this)
// log.error("Foo:" + " foo.toString() + "bar:" + bar); 
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...