如何在Android中启用/禁用日志级别?

d-m*_*man 148 logging android

我有很多日志语句要调试,例如.

Log.v(TAG, "Message here");
Log.w(TAG, " WARNING HERE");
Run Code Online (Sandbox Code Playgroud)

在设备电话上部署此应用程序时,我想关闭可以启用/禁用日志记录的详细日志记录.

Dav*_*ebb 192

Android文档说,有关日志级别如下:

除了在开发期间,不应该将详细编译到应用程序中.调试日志在运行时编译但被剥离.始终保留错误,警告和信息日志.

因此,您可能需要考虑剥离日志详细日志语句,可能使用另一个答案中建议的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
Run Code Online (Sandbox Code Playgroud)

或者,您可以在文件'/data/local.prop'中指定它们,如下所示:

log.tag.MyAppTag=WARN
Run Code Online (Sandbox Code Playgroud)

更高版本的Android 似乎要求/data/local.prop是只读的.此文件在引导时读取,因此您需要在更新后重新启动.如果/data/local.prop世界可写,它可能会被忽略.

最后,您可以使用该System.setProperty()方法以编程方式设置它们.

  • 我有同样的经历; API文档还不清楚这究竟应该如何工作,甚至似乎提到大多数`android.util.Config`常量被弃用.API文档中指定的硬编码值是无用的,因为这些(据推测)因构建而异.因此,ProGuard路线似乎是我们的最佳解决方案. (4认同)
  • 您是否有幸使用/data/local.prop文件,setprop方法或System.setProperty来配置Android日志记录?我在使用Log.isLoggable(TAG,VERBOSE)为我返回true时遇到了一些麻烦. (3认同)
  • 我已经让android调试工作了.诀窍在于,当您调用Log.d("xyz")之类的内容时,即使对记录器禁用了调试,该消息也会写入logcat.这意味着过滤通常在写入后发生.为了过滤像Log.isLoggable(TAG,Log.VERBOSE)之类的东西{Log.v(TAG,"我的日志消息"); 是必要的.这通常很烦人.我使用slf4j-android的修改版来获得我想要的东西. (2认同)
  • @Dave你是否能够使local.prop方法正常工作.我也无法完成这项工作,我创建了一个条目log.tag.test = INFO然后尝试更改它从adb shell运行setprop log.tag.test SUPPRESS并且它不会改变任何东西.另外使用System.getProperty和System.setProperty什么都不做.想要得到你的更新.谢谢. (2认同)
  • +1评论"API文档非常不清楚这应该如何工作". (2认同)

Chr*_*Orr 88

最简单的方法可能是在部署之前通过ProGuard运行已编译的JAR ,其配置如下:

-assumenosideeffects class android.util.Log {
    public static int v(...);
}
Run Code Online (Sandbox Code Playgroud)

除了所有其他ProGuard优化之外,这将直接从字节码中删除任何详细的日志语句.

  • 请注意 - 即使实际调用Log.v()被剥离,它的参数仍然会被评估.因此,如果您在内部进行一些代价高昂的方法调用,例如Log.v(TAG,generateLog()),那么如果它处于某些热代码路径中,则可能会损害您的性能.甚至像toString()或String.format()这样的东西也很重要. (19认同)
  • @GaneshKrishnan不,那不是真的.对Log.v()的调用被剥离,但默认情况下,不会删除构建字符串的方法调用.请参阅ProGuard作者的回答:http://stackoverflow.com/a/6023505/234938 (4认同)
  • @ larham1:ProGuard对字节码起作用,因此我认为删除日志记录调用不会改变嵌入的行号元数据. (3认同)

Cyt*_*own 78

一种常见的方法是创建一个名为loglevel的int,并根据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
Run Code Online (Sandbox Code Playgroud)

稍后,您只需更改所有调试输出级别的LOGLEVEL即可.

  • 使用BuildConfig.DEBUG而不是自定义变量 (14认同)
  • 在您的示例中,将显示DEBUG消息,而WARN不会显示?你通常不想反对吗? (2认同)

小智 18

我采用了一个简单的路径 - 创建一个包装类,它也使用可变参数列表.

 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
Run Code Online (Sandbox Code Playgroud)

  • 有一个很大的问题,请参阅http://stackoverflow.com/questions/2446248/remove-all-debug-logging-calls-before-publishing-are-there-tools-to-do-this?lq=1 #comment8849301_4592958 (3认同)

小智 10

更好的方法是使用SLF4J API +的一些实现.

对于Android应用程序,您可以使用以下内容:

  1. Android Logger是轻量级但易于配置的SLF4J实现(<50 Kb).
  2. LOGBack是最强大和优化的实现,但其大小约为1 Mb.
  3. 其他任何你的口味:slf4j-android,slf4android.

  • 在Android上,你必须使用[`logback-android`](http://tony.github.com/logback-android)(因为`logback`本身是不兼容的).`logback-android-1.0.10-1.jar`是429 KB,考虑到所提供的功能,这并不算太糟糕,但大多数开发人员都会使用Proguard来优化他们的应用程序. (2认同)

Die*_*ano 8

你应该用

    if (Log.isLoggable(TAG, Log.VERBOSE)) {
        Log.v(TAG, "my log message");
    }
Run Code Online (Sandbox Code Playgroud)

  • 如何配置isLoggable的输出?在清单中将isDebugable设置为false时,debug和详细记录是否不可记录? (2认同)

lar*_*am1 5

使用 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);
    }
}
Run Code Online (Sandbox Code Playgroud)