i would like to track the data usage of my app, but to do that, I need to be able to get the full size of an HttpUriRequest
and HttpResponse
. Simply getting the size of the HttpEntity
isn't enough because both the request and response have more data being transferred (headers, params, the actual URL being transmitted, etc). So, is there a way to find the full amount of data that's being transmitted both ways?
Thanks.
If you just want metrics "afterwards" you can just supply your own subclass of a suitable ClientConnectionManager
implementation and fetch the relevant HttpConnectionMetrics
after the request is returned to the manager.
As a simple (and slighty sh*tty) example, subclass SingleClientConnManager
, like so:
class MeasuringClientConnManager extends SingleClientConnManager {
private long mReceivedBytes = -1;
private long mSentBytes = -1;
public MeasuringClientConnManager(HttpParams params, SchemeRegistry schreg) {
super(params, schreg);
}
@Override
public void releaseConnection(ManagedClientConnection conn,
long validDuration, TimeUnit timeUnit) {
HttpConnectionMetrics metrics = conn.getMetrics();
mReceivedBytes = metrics.getReceivedBytesCount();
mSentBytes = metrics.getSentBytesCount();
metrics.reset();
super.releaseConnection(conn, validDuration, timeUnit);
}
public long getReceivedBytes() {
return mReceivedBytes;
}
public long getSentBytes() {
return mSentBytes;
}
}
and just cram it into your HTTP client like so:
BasicHttpParams params = new BasicHttpParams();
SchemeRegistry schreg = new SchemeRegistry();
schreg.register(new Scheme("http", PlainSocketFactory.getSocketFactory(), 80));
// Add SSL here if you need it
MeasuringClientConnManager conman = new MeasuringClientConnManager(params, schreg);
DefaultHttpClient client = new DefaultHttpClient(conman, params);
client.execute(new HttpGet("http://www.google.com"));
System.out.println(conman.getSentBytes());
System.out.println(conman.getReceivedBytes());
Edit: Alternative example that uses logging session input & output buffers alongside a mangled wire log + adding a listener interface.
class MeasuringClientConnManager extends SingleClientConnManager {
interface WireListener {
void onUpdate(long sent, long recv);
}
private WireListener mListener;
private long mReceivedBytes = -1;
private long mSentBytes = -1;
private Wire mWire = new Wire(null) {
public boolean enabled() { return true; };
// Time to override a bunch of methods (otherwise Wire will crash)
public void input(byte[] b) throws IOException {mReceivedBytes += b.length; rxtx();};
public void input(byte[] b, int off, int len) throws IOException {mReceivedBytes += len; rxtx();}
public void input(InputStream instream) throws IOException {mReceivedBytes += count(instream); rxtx();}
public void input(String s) throws IOException {mReceivedBytes += s.length(); rxtx();};
public void input(int b) throws IOException {mReceivedBytes++; rxtx();}
public void output(byte[] b) throws IOException {mSentBytes += b.length; rxtx();}
public void output(byte[] b, int off, int len) throws IOException {mSentBytes += len; rxtx();}
public void output(int b) throws IOException {mSentBytes++; rxtx();}
public void output(String s) throws IOException {mSentBytes += s.length(); rxtx();}
public void output(InputStream outstream) throws IOException {mSentBytes += count(outstream); rxtx();};
private int count(InputStream is) throws IOException {
int result = 0;
byte[] b = new byte[1024 * 8];
int count;
while ((count = is.read(b)) > -1) {
result += count;
}
return result;
}
};
public MeasuringClientConnManager(HttpParams params, SchemeRegistry schreg) {
super(params, schreg);
}
public void setWireListener(WireListener wl) {
mListener = wl;
}
/**
* {@inheritDoc}
*/
@Override
protected ClientConnectionOperator createConnectionOperator(
SchemeRegistry schreg) {
final ClientConnectionOperator actual = super.createConnectionOperator(schreg);
ClientConnectionOperator wired = new ClientConnectionOperator() {
@Override
public void updateSecureConnection(OperatedClientConnection conn,
HttpHost target, HttpContext context, HttpParams params)
throws IOException {
actual.updateSecureConnection(conn, target, context, params);
}
@Override
public void openConnection(OperatedClientConnection conn, HttpHost target,
InetAddress local, HttpContext context, HttpParams params)
throws IOException {
actual.openConnection(conn, target, local, context, params);
}
@Override
public OperatedClientConnection createConnection() {
DefaultClientConnection conn = new DefaultClientConnection() {
@Override
protected SessionInputBuffer createSessionInputBuffer(
Socket socket, int buffersize, HttpParams params)
throws IOException {
return new LoggingSessionInputBuffer(super.createSessionInputBuffer(socket, buffersize, params), mWire);
}
@Override
protected SessionOutputBuffer createSessionOutputBuffer(
Socket socket, int buffersize, HttpParams params)
throws IOException {
return new LoggingSessionOutputBuffer(super.createSessionOutputBuffer(socket, buffersize, params), mWire);
}
};
return conn;
}
};
return wired;
}
void rxtx() {
WireListener l = mListener;
if (l != null) {
l.onUpdate(mSentBytes, mReceivedBytes);
}
}
}
Usage is very similar, but now with wire updates as stuff is sent:
BasicHttpParams params = new BasicHttpParams();
SchemeRegistry schreg = new SchemeRegistry();
schreg.register(new Scheme("http", PlainSocketFactory.getSocketFactory(), 80));
// Add SSL here if you need it
MeasuringClientConnManager conman = new MeasuringClientConnManager(params, schreg);
conman.setWireListener(new MeasuringClientConnManager.WireListener() {
@Override
public void onUpdate(long sent, long recv) {
System.out.println("WIRE sent: " + sent + ", recv: " + recv);
}
});
DefaultHttpClient client = new DefaultHttpClient(conman, params);
client.execute(new HttpGet("http://www.thirdbase.se"));