如何为java HttpURLConnection流量启用连线日志记录?
我在另一个项目中使用过,我希望使用相同的输出,但使用“标准”HttpUrlConnection 我使用了代理,但我想直接从java记录流量如何为java HttpURLConnection流量启用连线日志记录?,java,http,logging,httpurlconnection,Java,Http,Logging,Httpurlconnection,我在另一个项目中使用过,我希望使用相同的输出,但使用“标准”HttpUrlConnection 我使用了代理,但我想直接从java记录流量 捕获连接输入和输出流的内容是不够的,因为HTTP头是由HttpUrlConnection类编写和使用的,因此我将无法记录头。我认为您无法自动执行此操作,但您可以使用HttpUrlConnection的输出和输入流作为参数来子类化和。然后在写入/读取字节时,记录它们并将它们传递到底层流。我已经能够在默认的SSL流量之上记录所有实现我自己的SSL流量 这对我来说
捕获连接输入和输出流的内容是不够的,因为HTTP头是由HttpUrlConnection类编写和使用的,因此我将无法记录头。我认为您无法自动执行此操作,但您可以使用
HttpUrlConnection
的输出和输入流作为参数来子类化和。然后在写入/读取字节时,记录它们并将它们传递到底层流。我已经能够在默认的SSL流量之上记录所有实现我自己的SSL流量
这对我来说很有效,因为我们所有的连接都使用HTTPS,我们可以用这个方法设置套接字工厂
可以在以下位置找到一个更完整的解决方案,该解决方案支持对所有套接字进行监控:
感谢您指出了正确的使用方向
以下是我的尚未准备就绪的生产代码:
public class WireLogSSLSocketFactory extends SSLSocketFactory {
private SSLSocketFactory delegate;
public WireLogSSLSocketFactory(SSLSocketFactory sf0) {
this.delegate = sf0;
}
public Socket createSocket(Socket s, String host, int port,
boolean autoClose) throws IOException {
return new WireLogSocket((SSLSocket) delegate.createSocket(s, host, port, autoClose));
}
/*
...
*/
private static class WireLogSocket extends SSLSocket {
private SSLSocket delegate;
public WireLogSocket(SSLSocket s) {
this.delegate = s;
}
public OutputStream getOutputStream() throws IOException {
return new LoggingOutputStream(delegate.getOutputStream());
}
/*
...
*/
private static class LoggingOutputStream extends FilterOutputStream {
private static final Logger logger = Logger.getLogger(WireLogSocket.LoggingOutputStream.class);
//I'm using a fixed charset because my app always uses the same.
private static final String CHARSET = "ISO-8859-1";
private StringBuffer sb = new StringBuffer();
public LoggingOutputStream(OutputStream out) {
super(out);
}
public void write(byte[] b, int off, int len)
throws IOException {
sb.append(new String(b, off, len, CHARSET));
logger.info("\n" + sb.toString());
out.write(b, off, len);
}
public void write(int b) throws IOException {
sb.append(b);
logger.info("\n" + sb.toString());
out.write(b);
}
public void close() throws IOException {
logger.info("\n" + sb.toString());
super.close();
}
}
}
}
解决方案#1:使用装饰图案
您必须在类上使用以扩展其功能。然后重写所有HttpURLConnection方法,将操作委托给组件指针,并捕获所需信息并记录
还要确保重写父类:和:方法以返回装饰对象和对象
解决方案#2:使用自定义内存中http代理
编写一个简单的http代理服务器,并在应用程序启动和初始化期间在其单独的线程中启动。看
将应用程序配置为对所有请求使用上述HTTP代理。看
现在你们所有的流量都通过上面的代理,就像在fiddler中发生的一样。因此,您可以访问原始http流“从客户端到服务器”以及“从服务器返回到客户端”。您必须解释这些原始信息,并根据需要将其记录下来
更新:
使用HTTP代理作为基于SSL的Web服务器的适配器
== Client System ===============================
| |
| ------------------------------ |
| | | |
| | Java process | |
| | ---- | |
| | ---------- | | | |
| | | | -O | | |
| | | Logging | | | |
| | | Proxy <---HTTP-- | ----- |
| | | Adapter | | | | |
| | | Thread o------------------> | |
| | | o | | | | |
| | --------|- | | Log | |
| | | | ----- |
| ----------------|------------- |
| | |
=====================|==========================
|
|
HTTPS
SSL
|
== Server System ====|==========================
| | |
| ----------------|---------------- |
| | V | |
| | | |
| | Web Server | |
| | | |
| --------------------------------- |
| |
================================================
==客户端系统==========================================================
| |
| ------------------------------ |
| | | |
|| Java进程||
| | ---- | |
| | ---------- | | | |
|| | | |-O | | |
|| | | | | | |
|| |代理| |
|| | o | | | | |
||------------| | |日志| |
| | | | ----- |
| ----------------|------------- |
| | |
=====================|==========================
|
|
HTTPS
SSL
|
==服务器系统===============================================================
| | |
| ----------------|---------------- |
|| V | |
| | | |
|| Web服务器||
| | | |
| --------------------------------- |
| |
================================================
使用AspectJ插入切入点,在方法周围添加日志记录建议,怎么样?我相信AspectJ可以将它编织成私有/受保护的方法
sun.net.www.protocol.http.HttpURLConnection.writeRequest可能会调用sun.net.www.http.HttpClient.writeRequest,它将MessageHeader对象作为输入,从而成为您的目标
最终,这可能会起作用,但会非常脆弱,只能在Sun JVM上工作;实际上,你只能相信你正在使用的确切版本。如果你只对在线内容(标题、正文等)感兴趣,你可能想试一试 这样做的好处是不必更改任何代码,但如果您所追求的是通过代码启用日志记录,则此答案不适用。据了解,通过提供一些日志记录支持 设置(根据需要调整路径): logging.properties:
handlers= java.util.logging.ConsoleHandler
java.util.logging.ConsoleHandler.level = FINEST
sun.net.www.protocol.http.HttpURLConnection.level=ALL
这将记录到控制台,根据需要进行调整,例如记录到文件
示例输出:
2010-08-07 00:00:31 sun.net.www.protocol.http.HttpURLConnection writeRequests
FIN:sun.net.www。MessageHeader@16caf435配对:{GET/howto.html HTTP/1.1:null}{User-Agent:Java/1.6.0_20}{Host:www.rgagnon.com}{Accept:text/html、image/gif、image/jpeg、*;q=.2、*/*;q=.2}{Connection:keep-alive}
2010-08-07 00:00:31 sun.net.www.protocol.http.HttpURLConnection getInputStream
FIN:sun.net.www。MessageHeader@5ac0728配对:{null:HTTP/1.1200 OK}{Date:Sat,2010年8月7日04:00:33 GMT}{Server:Apache}{Accept Ranges:bytes}{Content Length:17912}{Keep-Alive:timeout=5,max=64}{Connection:Keep-Alive}{Content-Type:text/html}
请注意,这只打印标题而不打印正文
有关详细信息,请参阅
还有一个系统属性
-Djavax.net.debug=all
。但主要是。在Linux中,您可以在strace下运行VM:
strace-o strace.out-s 4096-e trace=network-f java…要使用java 8环境刷新: 下面是@sleske的答案
System.setProperty("javax.net.debug","all");
对我来说,这是开箱即用的
还有@weberjn的建议
strace -o strace.out -s 4096 -e trace=network -f java
但如果处理
strace -o strace.out -s 4096 -e trace=network -f java