java - 以编程方式为 JDK 类启用日志记录

标签 java logging

好的,情况很简单。我需要能够以编程方式启用/禁用 JDK 类 (HttpURLConnection) 的日志记录。

public class HttpLoggingTest {

    /**
      Just a dummy to get some action from HttpURLConnection
    */
    private static void getSomething(String urlStr) throws MalformedURLException, IOException {
        System.out.println("----- " + urlStr);
        HttpURLConnection conn = (HttpURLConnection) new URL("http://www.google.com").openConnection();

        for (Entry<String, List<String>> header : conn.getHeaderFields().entrySet()) {
            System.out.println(header.getKey() + "=" + header.getValue());
        }
        conn.disconnect();

    }

    public static void main(String[] args) throws MalformedURLException, IOException {

        // HERE : Enable JDK logging for class
        // sun.net.www.protocol.http.HttpURLConnection
        getSomething("http://www.goodle.com");

        // HERE: Disable JDK logging for class
        // sun.net.www.protocol.http.HttpURLConnection
        getSomething("http://www.microsoft.com");           
    }        
}

换句话说:在第一次 URL 调用之前,必须启用日志记录,然后在下一次调用之前禁用。

这就是挑战!
我不知道该怎么做。

必须使用 Java 7。

备注:

我可以使用配置文件 logging.properties 来做到这一点:

sun.net.www.protocol.http.HttpURLConnection.level = ALL

但我想要一个程序化的解决方案。

更新

下面是在 Java 6 中有效但在 Java 7 中无效的代码:

import java.io.IOException;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.List;
import java.util.Map.Entry;
import java.util.logging.ConsoleHandler;
import java.util.logging.Handler;
import java.util.logging.Level;
import java.util.logging.Logger;    

public class HttpLoggingTest {

    /**
      Just a dummy to get some action from HttpURLConnection
    */
    private static void getSomething(String urlStr) throws MalformedURLException, IOException {
        System.out.println("----- " + urlStr);
        HttpURLConnection conn = (HttpURLConnection) new URL("http://www.google.com").openConnection();

        for (Entry<String, List<String>> header : conn.getHeaderFields().entrySet()) {
            System.out.println(header.getKey() + "=" + header.getValue());
        }
        conn.disconnect();            
    }

    private static void enableConsoleHandler() {
        //get the top Logger
        Logger topLogger = java.util.logging.Logger.getLogger("");

        // Handler for console (reuse it if it already exists)
        Handler consoleHandler = null;
        //see if there is already a console handler
        for (Handler handler : topLogger.getHandlers()) {
            if (handler instanceof ConsoleHandler) {
                //found the console handler
                consoleHandler = handler;
                break;
            }
        }

        if (consoleHandler == null) {
            //there was no console handler found, create a new one
            consoleHandler = new ConsoleHandler();
            topLogger.addHandler(consoleHandler);
        }
        consoleHandler.setLevel(Level.ALL);
    }

    public static void main(String[] args) throws MalformedURLException, IOException {

        enableConsoleHandler();

        final Logger httpLogger = Logger.getLogger("sun.net.www.protocol.http.HttpURLConnection");


        // Enable JDK logging for class
        //sun.net.www.protocol.http.HttpURLConnection
        httpLogger.setLevel(java.util.logging.Level.FINE);
        getSomething("http://www.goodle.com");

        // Disable JDK logging for class
        // sun.net.www.protocol.http.HttpURLConnection
        httpLogger.setLevel(java.util.logging.Level.INFO);
        getSomething("http://www.microsoft.com");           
    }        
}

更新2

为了确保解决方案能够从我们的目标类(而不是所有种类的其他 JDK 内部类)启用输出,我创建了这个最小的 JAXB 示例。这里的 JAXB 只是“其他东西”的一个示例,它可能是 JDK 中也使用 PlatformLogger 的任何其他部分。

import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Marshaller;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;

/**
 * Minimal dummy JAXB example. Only purpose is to provoke
 * some JAXB action. Non-prod quality!
 */
@XmlRootElement(name = "book")
public class Celebrity {

    @XmlElement
    public String getFirstName() {
        return "Marilyn";
    }

    @XmlElement
    public String getLastName() {
        return "Monroe";
    }

    public void printXML() {
        JAXBContext context;
        try {
            context = JAXBContext.newInstance(Celebrity.class);
            Marshaller m = context.createMarshaller();
            m.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);
            m.marshal(this, System.out);
        } catch (JAXBException ex) {
        }
    }
}

实例化Celebrity 类的实例并调用printXML()。将其放入 getSomething() 方法中。这不能生成 JAXB 内部日志记录输出……否则您启用日志记录的时间超出了您的想象。

最佳答案

偶然发现 PlatformLoggingMXBean另一天。我需要尝试类似的方法:

PlatformLoggingMXBean platformLoggingMXBean = 
    ManagementFactory.getPlatformMXBean(PlatformLoggingMXBean.class);
platformLoggingMXBean.setLoggerLevel(
    "sun.net.www.protocol.http.HttpURLConnection", "FINE");

并查看它是否有效。

关于java - 以编程方式为 JDK 类启用日志记录,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21031110/

相关文章:

java - Log4j2 中 AsyncLogger 和 AsyncAppender 的区别

java - 错误 <interface declaration>, <parcelable declaration>, AidlTokenType.import or AidlTokenType.package expected, got '.' in Android Studio

java - 字符串池——字符串总是存在于常量池中吗?

Java:SQL 和统计/机器学习

java - 通过注释快速添加日志记录(例如用于 getter/setter 的 lombok) - 有可用的解决方案吗?

java - 如何将控制台日志重定向到 Mac OS X 中的 Java Web Start 文件?

java - 将字符串数组添加到二维数组中

java - 在 Android 中创建硬链接(hard link)和符号链接(symbolic link)

node.js - winston 每日轮换删除 .GZIP 文件

sharepoint - 使用 NLog 集中日志记录的最佳方法是什么?