動機
ネットワーク転送量をキャプチャしたいときってあるよね。
そんなとき、Commons HttpClient なら可能です。
概要
ネットワーク転送量は、HttpConnection インスタンスのgetMetrics() メソッドで取得できるHttpConnectionMetrics インスタンスに記録されています。
HttpConnection インスタンスは、HttpContext インスタンスのgetAttribute(ExecutionContext.HTTP_CONNECTION)で取得できます。
HttpContext インスタンスを取得するには、HttpRequestInterceptor インターフェースとHttpResponseInterceptor インターフェースを実装したクラスを、addRequestInterceptor() メソッドとaddResponseInterceptor() メソッドを使用してHttpClient(正確には AbstractHttpClient) インスタンスに登録してやります。
実装例
下にHttpRequestInterceptor インターフェースとHttpResponseInterceptorインターフェースの実装を示します。
class InterceptorImpl implements HttpRequestInterceptor, HttpResponseInterceptor {
private static final Logger LOG = LoggerFactory.getLogger(InterceptorImpl.class);
private ThreadLocal<HttpConnectionMetrics> threadLocalMetrics = new ThreadLocal<HttpConnectionMetrics>();
@Override
public void process(HttpRequest request, HttpContext context) throws HttpException, IOException {
// context インスタンスから、HttpConnection インスタンスを取得
final HttpConnection connection = (HttpConnection)context.getAttribute(ExecutionContext.HTTP_CONNECTION);
// HttpConnection インスタンスからHttpConnectionMetricsを取得
final HttpConnectionMetrics metrics = connection.getMetrics();
// サーバにアクセスする前のメトリックをスレッドローカルに保存
threadLocalMetrics.set(new HttpConnectionMetrics() {
private final long requestCount = metrics.getRequestCount();
private final long responseCount = metrics.getResponseCount();
private final long sentBytesCount = metrics.getSentBytesCount();
private final long receivedBytesCount = metrics.getReceivedBytesCount();
@Override
public long getRequestCount() {
return this.requestCount;
}
@Override
public long getResponseCount() {
return responseCount;
}
@Override
public long getSentBytesCount() {
return sentBytesCount;
}
@Override
public long getReceivedBytesCount() {
return receivedBytesCount;
}
@Override
public Object getMetric(String metricName) {
return null;
}
@Override
public void reset() {
}
});
}
@Override
public void process(HttpResponse response, HttpContext context) throws HttpException, IOException {
// context インスタンスから、HttpConnection インスタンスを取得
final HttpConnection connection = (HttpConnection)context.getAttribute(ExecutionContext.HTTP_CONNECTION);
// HttpConnection インスタンスからHttpConnectionMetricsを取得
final HttpConnectionMetrics postMetrics = connection.getMetrics();
// サーバにアクセスする前のメトリックを取得
final HttpConnectionMetrics prevMetrics = threadLocalMetrics.get();
threadLocalMetrics.remove();
// リクエスト回数
final long requestCount = postMetrics.getRequestCount() - prevMetrics.getRequestCount();
// レスポンス回数
final long responseCount = postMetrics.getResponseCount() - prevMetrics.getResponseCount();
// 送信バイト数
final long sentBytesCount = postMetrics.getSentBytesCount() - prevMetrics.getSentBytesCount();
// 受信バイト数
final long receivedBytesCount = postMetrics.getReceivedBytesCount() - prevMetrics.getReceivedBytesCount();
// ログに出力
LOG.info("requestCount={}, responseCount={}, sentBytesCount={}, receivedBytesCount={}",
totalRequestCount.get(), totalResponseCount.get(), totalSentBytesCount.get(),
totalReceivedBytesCount.get());
}
}
InterceptorImpl
クラスは次のようにして使用します。
public static void main() {
// タイムアウトを設定してやる
HttpParams httpParams = new BasicHttpParams();
HttpConnectionParams.setConnectionTimeout(httpParams, 5000);
HttpConnectionParams.setSoTimeout(httpParams, 30000);
// HttpClient インスタンス作成
SystemDefaultHttpClient httpClient = new SystemDefaultHttpClient(httpParams);
// Interceptor の登録
Interceptor interceptor = new Interceptor();
httpClient.addRequestInterceptor(interceptor);
httpClient.addResponseInterceptor(interceptor);
// サーバにアクセス
HttpGet request = new HttpGet("http://www.yahoo.co.jp/");
httpClient.exeucte(request);
}
プログラム実行後、ログに出力された値を Excel で集計すれば総量や平均が求まります。
InterceptorImpl
から出力されるログを別ファイルにしておけば集計しやすいでしょう。
本実装例は Commons HttpClient 4.2 で確認しています。4.3 でも Deprecation の警告がでますがいけるはず。