Android에서 로그 수준을 활성화 / 비활성화하려면 어떻게합니까?


Answers

Android 문서에는 로그 수준에 대해 다음과 같이 나와 있습니다 .

Verbose는 개발 중에는 제외하고 응용 프로그램으로 컴파일되지 않아야합니다. 디버그 로그는 컴파일되지만 런타임에 제거됩니다. 오류, 경고 및 정보 로그는 항상 보관됩니다.

따라서 다른 답변에서 제안 된 것처럼 ProGuard를 사용하여 Log Verbose 로깅 문을 제거하는 것이 좋습니다 .

설명서에 따르면 시스템 등록 정보를 사용하여 개발 장치에서 로깅을 구성 할 수 있습니다. 설정할 속성은 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 가 world 쓰기 가능이면 무시됩니다.

마지막으로 System.setProperty() 메서드를 사용하여 프로그래밍 방식으로 설정할 수 있습니다.

Question

예를 들어 디버깅 할 로깅 문이 많이 있습니다.

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

장치 전화에이 응용 프로그램을 배포하는 동안 로깅을 활성화 / 비활성화 할 수있는 자세한 로깅을 해제하고 싶습니다.




Log4j 또는 slf4j는 logcat과 함께 Android에서 로깅 프레임 워크로 사용할 수도 있습니다. android-logging-log4j 또는 log4j 지원을 참조하십시오.




이 로그 확장 클래스는 https://github.com/dbauduin/Android-Tools/tree/master/logs 볼 수 있습니다.

로그에 대한 정밀한 제어를 가능하게합니다. 예를 들어 모든 로그를 비활성화하거나 일부 패키지 또는 클래스의 로그 만 비활성화 할 수 있습니다.

또한 몇 가지 유용한 기능을 추가합니다 (예 : 각 로그에 태그를 전달할 필요가 없음).




나를 위해 종종 각 TAG마다 다른 로그 수준을 설정할 수있는 것이 유용합니다.

이 매우 간단한 래퍼 클래스를 사용하고 있습니다.

public class Log2 {

    public enum LogLevels {
        VERBOSE(android.util.Log.VERBOSE), DEBUG(android.util.Log.DEBUG), INFO(android.util.Log.INFO), WARN(
                android.util.Log.WARN), ERROR(android.util.Log.ERROR);

        int level;

        private LogLevels(int logLevel) {
            level = logLevel;
        }

        public int getLevel() {
            return level;
        }
    };

    static private HashMap<String, Integer> logLevels = new HashMap<String, Integer>();

    public static void setLogLevel(String tag, LogLevels level) {
        logLevels.put(tag, level.getLevel());
    }

    public static int v(String tag, String msg) {
        return Log2.v(tag, msg, null);
    }

    public static int v(String tag, String msg, Throwable tr) {
        if (logLevels.containsKey(tag)) {
            if (logLevels.get(tag) > android.util.Log.VERBOSE) {
                return -1;
            }
        }
        return Log.v(tag, msg, tr);
    }

    public static int d(String tag, String msg) {
        return Log2.d(tag, msg, null);
    }

    public static int d(String tag, String msg, Throwable tr) {
        if (logLevels.containsKey(tag)) {
            if (logLevels.get(tag) > android.util.Log.DEBUG) {
                return -1;
            }
        }
        return Log.d(tag, msg);
    }

    public static int i(String tag, String msg) {
        return Log2.i(tag, msg, null);
    }

    public static int i(String tag, String msg, Throwable tr) {
        if (logLevels.containsKey(tag)) {
            if (logLevels.get(tag) > android.util.Log.INFO) {
                return -1;
            }
        }
        return Log.i(tag, msg);
    }

    public static int w(String tag, String msg) {
        return Log2.w(tag, msg, null);
    }

    public static int w(String tag, String msg, Throwable tr) {
        if (logLevels.containsKey(tag)) {
            if (logLevels.get(tag) > android.util.Log.WARN) {
                return -1;
            }
        }
        return Log.w(tag, msg, tr);
    }

    public static int e(String tag, String msg) {
        return Log2.e(tag, msg, null);
    }

    public static int e(String tag, String msg, Throwable tr) {
        if (logLevels.containsKey(tag)) {
            if (logLevels.get(tag) > android.util.Log.ERROR) {
                return -1;
            }
        }
        return Log.e(tag, msg, tr);
    }

}

이제 각 클래스의 시작 부분에서 TAG 당 로그 수준을 설정하면됩니다.

Log2.setLogLevel(TAG, LogLevels.INFO);



간단한 매개 변수 목록을 사용하는 래퍼 클래스를 만드는 간단한 경로를 사용했습니다.

 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



여기에 더 복잡한 해결책이 있습니다. 전체 스택 추적을 얻고 필요한 경우에만 toString () 메서드가 호출됩니다 (성능). 프로덕션 모드에서는 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); 



내 애플 리케이션에서 "상태"라는 정적 부울 var가있는 Log 클래스를 래핑하는 클래스가 있습니다. 내 코드 전체에 걸쳐 실제로 "로그"에 쓰기 전에 정적 메서드를 사용하여 "상태"변수의 값을 확인합니다. 그런 다음 앱에서 만든 모든 인스턴스에서 값이 공통적으로 사용되도록 "상태"변수를 설정하는 정적 메서드가 있습니다. 즉, 앱이 실행 중일 때도 한 번의 호출로 앱의 모든 로깅을 사용하거나 사용하지 않도록 설정할 수 있습니다. 지원 호출에 유용합니다 ... 디버깅 할 때 총을 고수해야하며 표준 Log 클래스를 사용하는 것을 회귀하지 말아야합니다.

Java가 값을 할당받지 않은 경우 Java가 부울 var를 false로 해석하는 것이 유용하기 때문에 (즉, 편리합니다), 이는 로깅을 켜야 만 때까지 false로 남겨 둘 수 있습니다.




너는 다음을 사용해야한다.

    if (Log.isLoggable(TAG, Log.VERBOSE)) {
        Log.v(TAG, "my log message");
    }