Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to enable wire logging for a java HttpURLConnection traffic?

I've used Jakarta commons HttpClient in another project and I would like the same wire logging output but using the "standard" HttpUrlConnection.

I've used Fiddler as a proxy but I would like to log the traffic directly from java.

Capturing what goes by the connection input and output streams is not enough because the HTTP headers are written and consumed by the HttpUrlConnection class, so I will not be able to log the headers.

like image 753
Serxipc Avatar asked Sep 18 '09 17:09

Serxipc


People also ask

What is the use of HttpURLConnection in Java?

HttpURLConnection class is an abstract class directly extending from URLConnection class. It includes all the functionality of its parent class with additional HTTP-specific features. HttpsURLConnection is another class that is used for the more secured HTTPS protocol.

Which method of HttpURLConnection class is used to retrieve the response status from server?

Call setRequestProperty() method on HttpURLConnection instance to set request header values, such as “User-Agent” and “Accept-Language” etc. We can call getResponseCode() to get the response HTTP code.

How do I turn off HttpURLConnection in Java?

To close the connection, invoke the close() method on either the InputStream or OutputStream object. Doing that may free the network resources associated with the URLConnection instance.


2 Answers

According to Sun's HttpURLConnection source there is some logging support via JUL.

Setup (adjust path as required):

-Djava.util.logging.config.file=/full/path/to/logging.properties 

logging.properties:

handlers= java.util.logging.ConsoleHandler java.util.logging.ConsoleHandler.level = FINEST sun.net.www.protocol.http.HttpURLConnection.level=ALL 

This will log to the console, adjust as required to e.g. log to a file.

Example output:

2010-08-07 00:00:31 sun.net.www.protocol.http.HttpURLConnection writeRequests FIN: sun.net.www.MessageHeader@16caf435 pairs: {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 pairs: {null: HTTP/1.1 200 OK}{Date: Sat, 07 Aug 2010 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} 

Note that this prints only headers without body.

See http://www.rgagnon.com/javadetails/java-debug-HttpURLConnection-problem.html for details.

There is also system property -Djavax.net.debug=all. But it's mainly useful for SSL debugging.

like image 52
Vadzim Avatar answered Sep 21 '22 01:09

Vadzim


I've been able to log all SSL traffic implementing my own SSLSocketFactory on top of the default one.

This worked for me because all of our connections are using HTTPS and we can set the socket factory with the method HttpsURLConnection.setSSLSocketFactory.

A more complete solution that enables monitoring on all sockets can be found at http://www.javaspecialists.eu/archive/Issue169.html Thanks to Lawrence Dol for pointing in the right direction of using Socket.setSocketImplFactory

Here is my not ready for production code:

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();             }         }     } } 
like image 40
Serxipc Avatar answered Sep 17 '22 01:09

Serxipc