如何在Android上配置java.util.logging?

时间:2010-12-30 09:11:43

标签: android logging

我想在Android上使用java.util.logging。我想使用logging.properties配置日志记录系统。但是如何使用特定的配置文件告诉Android?例如,我将logging.properties放在应用程序的类路径根目录中。 Android如何知道logging.properties的位置。

由于

5 个答案:

答案 0 :(得分:50)

现在这是我的一个项目的常见问题解答,希望更多人会在这里找到它:java.util.logging在Android上正常工作。请不要在代码中使用任何其他内容,日志框架就像Java世界中的一个有害生物。

破坏的是Android附带的默认日志记录处理程序,它忽略任何级别比INFO更精细的日志消息。你没有看到DEBUG等消息。

原因是在AndroidHandler.java中调用Log.isLoggable():

https://github.com/android/platform_frameworks_base/blob/master/core/java/com/android/internal/logging/AndroidHandler.java

以下是解决问题的方法:

import android.util.Log;
import java.util.logging.*;

/**
 * Make JUL work on Android.
 */
public class AndroidLoggingHandler extends Handler {

    public static void reset(Handler rootHandler) {
        Logger rootLogger = LogManager.getLogManager().getLogger("");
        Handler[] handlers = rootLogger.getHandlers();
        for (Handler handler : handlers) {
            rootLogger.removeHandler(handler);
        }
        rootLogger.addHandler(rootHandler);
    }

    @Override
    public void close() {
    }

    @Override
    public void flush() {
    }

    @Override
    public void publish(LogRecord record) {
        if (!super.isLoggable(record))
            return;

        String name = record.getLoggerName();
        int maxLength = 30;
        String tag = name.length() > maxLength ? name.substring(name.length() - maxLength) : name;

        try {
            int level = getAndroidLevel(record.getLevel());
            Log.println(level, tag, record.getMessage());
            if (record.getThrown() != null) {
                Log.println(level, tag, Log.getStackTraceString(record.getThrown()));
            }
        } catch (RuntimeException e) {
            Log.e("AndroidLoggingHandler", "Error logging message.", e);
        }
    }

    static int getAndroidLevel(Level level) {
        int value = level.intValue();

        if (value >= Level.SEVERE.intValue()) {
            return Log.ERROR;
        } else if (value >= Level.WARNING.intValue()) {
            return Log.WARN;
        } else if (value >= Level.INFO.intValue()) {
            return Log.INFO;
        } else {
            return Log.DEBUG;
        }
    }
}

在应用程序的主要活动/初始化代码中:

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

    AndroidLoggingHandler.reset(new AndroidLoggingHandler());
    java.util.logging.Logger.getLogger("my.category").setLevel(Level.FINEST);
...

TL; DR:是的,您可以使用一些魔术属性或adb shell命令,甚至可以了解愚蠢的内置日志记录处理程序DalvikLogging.loggerNameToTag如何将类别名称转换为标记(你必须为那些魔法属性和shell命令做些什么),但为什么要这么麻烦?记录的痛苦不够吗?

答案 1 :(得分:4)

通常使用android.util.Log来登录Android。使用该记录器有一些关键优势,例如能够使用adb logcat查看发送到这些日志的日志记录输出。

您可以尝试将logging.properties放在assets/res/raw/中。如果Android没有选择那些,那么可以使用java.util.logging.LogManagerreadConfiguration(java.io.InputStream)强制加载它。 (您可以使用Resources和AssetManager类将文件作为InputStream获取。)

答案 2 :(得分:2)

至少在Android 4.3上,如果使用

,则处理程序保持不变
adb shell setprop log.tag.YOURTAG DEBUG

您可以在logcat中看到最多以Level.FINE记录的消息。我还没有想出一种记录更高级别的方法,但这对我来说已经足够了。

答案 3 :(得分:1)

如果你们中的一个人只想从第三方库路由java.util.logging输出,那么使用SLF4J及其jul-to-slf4j bridge可以很容易地实现这一点。这适用于FINEFINEST日志语句,BTW。

这里是maven依赖

<dependency>
    <groupId>org.slf4j</groupId>
    <artifactId>jul-to-slf4j</artifactId>
    <version>${slf4j.version}</version>
</dependency>

要引导它,请将以下内容放在Application类,Roboguice模块中,或者在第一个日志语句之前将其执行到其他位置。 (不幸的是,在assets/logging.properties中配置此功能似乎不起作用。)

/*
 * add SLF4JBridgeHandler to j.u.l's root logger, should be done once
 * during the initialization phase of your application
 */
SLF4JBridgeHandler.install();

然后你可以

  • assets/logback.xml配置所有日志语句(使用logback-android)。有关日志级别的映射,请参阅here

  • 或只使用SLF4J-android将日志语句转发给logcat。为此,只需将以下依赖项添加到类路径中,无需进一步配置:

    <dependency>
        <groupId>org.slf4j</groupId>
        <artifactId>slf4j-android</artifactId>
        <version>${slf4j.version}</version>
    </dependency>
    

我使用

成功实现了这一点
<properties>
    <slf4j.version>1.7.6</slf4j.version>
</properties>

注意

  • 请仔细阅读与{strong>效果相关的jul-to-slf4j文档部分!
  • 如果您使用LogcatAppender,请务必记住JUL日志消息(级别比INFO更精细的消息除外)由android路由到logcat。因此,请务必使用适当的过滤器以避免重复。

答案 4 :(得分:1)

此处已修改answer of Christian Bauer

如果任何第三方库中的某个位置,您将看到类似以下内容的内容:

   final public class AnyClass {        
        private static final Logger logger = Logger.getLogger(AnyClass.class.getName());
         ...
            if (logger.isLoggable(Level.FINE)) {
                logger.fine("any log event");
            }
         ...
     }

在创建AnyClass.class的第一个实例后,将其添加到您的代码中:

SetupLogger.setup(Arrays.asList(
                new Pair<>(AnyClass.class.getName(), Level.FINEST),//AnyClass.class.getName() is because instance `logger` has his name
                new Pair<>(AnyOther.class.getName(), Level.FINEST)
        ));

SetupLogger .class

public class SetupLogger {

    static public void setup(List<Pair<String, Level>> loggerNames) {
        // suppress the logging output to the console
        AndroidLoggingHandler rootHandler = new AndroidLoggingHandler();
        AndroidLoggingHandler.reset(rootHandler );
        for (Pair<String, Level> pair : loggerNames) {
            Logger logger = Logger.getLogger(pair.first);
            logger.setLevel(pair.second);
        }
    }
}