ログインしてさらにmixiを楽しもう

コメントを投稿して情報交換!
更新通知を受け取って、最新情報をゲット!

Javaの課題丸投げコミュのWEBサーバアクセスログ集計プログラムの開発

  • mixiチェック
  • このエントリーをはてなブックマークに追加
WEBサーバアクセスログ集計プログラムを開発して、
ソースを書くという課題が出ました。

問:以下の仕様に適合したWEBサーバアクセスログ集計プログラムを開発せよ。

1 開発の背景
 簡易WEBサーバ開発プロジェクトにおいて、WEBサーバの応答時間を集計し、レポートして出力するツールを開発することになった。WEBサーバはアクセスログとして、応答完了時刻、アクセスされたURL、応答時間(ms)を出力している。

2 アクセスログのフォーマット
 アクセスログは1行=1HTTPアクセスのログとなっている。1行の中には3つの項目が出力されており、どの項目も省略されることはなく、必ず3項目出力される。また、各項目は1つのタブ文字により区切られている。
 以下に各項目の詳細を示す。

項目順序 『 項目名 』 フォーマット・備考

1 『 応答完了時刻 』 YYYY/MM/DD hh:mm:ss形式でWEBサーバが応答完了した時刻を、年月日、時分秒まで出力する。

2 『 URL 』 アクセスされたURL

3 『 応答時間 』 数字のみで構成。WEBサーバがリクエストを受けた時間からレスポンスを返すまでの時間をミリ秒単位で出力する。


 アクセスログ例
2008/11/13 14:03:22 /path/url/top.html 245
2008/11/13 14:12:45 /cgi-bin/top.cgi 54
2008/11/13 18:01:07 /sale/item.jsp 790

3 レポートの集計内容
 5分単位でアクセスログを集計し、応答時間ごとの度数・平均応答時間を出力する。各項目はタブ文字で区切り、1行=5分間隔の集計結果を出力する。出力は00:00〜23:55まで5単位で出力を連続して行う。つまり、集計結果が無くとも出力を行う。
 以下に出力項目の詳細を示す。


項目順序 『 項目名 』 フォーマット・備考
1  『 集計時刻 』 hh:mm形式。例えば2:20〜2:25までのアクセスログ
の集計時刻は02:20となる。

2  『 応答時間1秒未満 』 数字のみで構成。応答時間が1秒未満のアクセス
回数。アクセス回数が0回の場合も0を出力する。

3  『 応答時間1秒以上、5秒未満 』 数字のみで構成。応答時間が1秒以上、
5秒未満のアクセス回数。アクセス回数が0回の場
合も0を出力する。

4  『 応答時間5秒以上 』 数字のみで構成。応答時間が5秒以上のアクセス
              回数。アクセス回数が0回の場合も0を出力する。

  5  『平均応答時間』 数字のみで構成。集計した時間帯の平均応答時間
              をms単位で出力する。小数点以下は切り捨て。
              また集計した時間帯のアクセス数が0回の場合は、
              0を出力する。

4 レポートの出力
 全て標準出力に出力する。

 レポート出力例
00:00 0 2 1 32
00:05 0 0 0 0
00:10 6 1 0 3

5 実行時パラメータ
 第一パラメータとして集計するアクセスログファイル名を指定する。指定できるアクセスログファイル名は1つのみとする。

6 前提条件
(ア) システムの改行コードはLFである。
(イ) アクセスログファイルは日付単位に出力されており、
1つのアクセルログの中に複数の日付のログ出力が混ざることは無い。
(ウ) ログファイルの文字コードはEUC-JPで出力されているものとする。
また、レポートの出力文字コードもECU-JPとする。


以上の課題です。
よろしくお願いします。

コメント(8)

こりきに CR-X さん

ありがとうございます。
awk でも教えて頂けたら助かります。
こんな感じ。
エラー処理がかなり適当。
ちゃんとテストしてないから、もしかしたら間違ってるかも。
あと、標準出力に出すのに文字コード指定ってのは、javacのオプションいじるくらいしか思いつかないんだけど、簡単な方法ってあるのかな…?


public class LogItem {
public LogItem(Date aDate, String aPath, int aResponseTime){
mDate = aDate;
mPath = aPath;
mResponseTime = aResponseTime;
}

private Date mDate;
private int mResponseTime;
private String mPath;

public Date getDate(){
return mDate;
}

public int getResponseTime(){
return mResponseTime;
}
public String getPath(){
return mPath;
}
}
↑ importコピーするの忘れた。 適時追加してね。


import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.Reader;
import java.nio.charset.Charset;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.TimeZone;

public class LogParser {
public LogParser(Charset aCharset) {
mCharset = aCharset;
}

private Charset mCharset;
private static final DateFormat DATE_FORMAT = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss");
{
DATE_FORMAT.setTimeZone(TimeZone.getTimeZone("GMT+0"));
}

public List<LogItem> parse(File aFile) throws IOException, ParseException {
Reader tReader = null;
try {
tReader = new InputStreamReader(new FileInputStream(aFile), mCharset);
return parse(tReader);
} finally {
if (tReader != null)
tReader.close();
}
}

public List<LogItem> parse(Reader aReader) throws IOException, ParseException {
BufferedReader tReader = new BufferedReader(aReader);
List<LogItem> tResult = new ArrayList<LogItem>();
String tLine;
while ((tLine = tReader.readLine()) != null) {
tResult.add(parseLine(tLine));
}

return tResult;
}

private LogItem parseLine(String aLine) throws ParseException {
String[] tValues = aLine.split("\t");
Date tDate = DATE_FORMAT.parse(tValues[0]);
String tPath = tValues[1];
int tResponseTime = Integer.parseInt(tValues[2]);

return new LogItem(tDate, tPath, tResponseTime);
}
}
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Collections;
import java.util.Comparator;
import java.util.Date;
import java.util.List;
import java.util.TimeZone;

public class LogAggregator {
/**
*
* @param aLogs 集計対象ログ
*/
public LogAggregator(List<LogItem> aLogs) {
// 一応、時間でソートする
Collections.sort(aLogs, new Comparator<LogItem>() {
@Override
public int compare(LogItem aLeft, LogItem aRight) {
return aLeft.getDate().compareTo(aRight.getDate());
}
});

mLogs = aLogs;
}

/**
* ミリ秒で表した1日
*/
private static final long DAY_AS_MIL = 3600 * 24 * 1000;
private static final DateFormat DATE_FORMAT = new SimpleDateFormat("HH:mm");
{
DATE_FORMAT.setTimeZone(TimeZone.getTimeZone("GMT+0"));
}

private List<LogItem> mLogs;

public void printAggregate(long aAggregateSpan) {
long tCurrentTime = 0;
long tAggregateSpan = aAggregateSpan;

List<LogItem> tLogs = mLogs;
int tLogCount = tLogs.size();
int tIndex = 0;

for (tCurrentTime = 0; tCurrentTime < DAY_AS_MIL; tCurrentTime += tAggregateSpan) {
int tRangeCount1 = 0;
int tRangeCount2 = 0;
int tRangeCount3 = 0;
int tSum = 0;

while (tIndex < tLogCount) {
LogItem tItem = tLogs.get(tIndex);
long tLogTime = tItem.getDate().getTime() % DAY_AS_MIL;
if (tLogTime - tCurrentTime < tAggregateSpan) {
tIndex++;

int tResponseTime = tItem.getResponseTime();
tSum += tResponseTime;
if (tResponseTime < 1000)
tRangeCount1++;
else if (tResponseTime < 5000)
tRangeCount2++;
else
tRangeCount3++;
} else {
break;
}
}

int tTotalCount = tRangeCount1 + tRangeCount2 + tRangeCount3;
int tAverage = 0;
if (tTotalCount != 0)
tAverage = tSum / tTotalCount;

printAggregate(tCurrentTime, tRangeCount1, tRangeCount2, tRangeCount3, tAverage);
}
}

private void printAggregate(long aTime, int aCount1, int aCount2, int aCount3, int aAverage) {
String tTimeString = DATE_FORMAT.format(new Date(aTime));
String tOutput = String.format("%s\t%d\t%d\t%d\t%d", tTimeString, aCount1, aCount2, aCount3, aAverage);

System.out.println(tOutput);
}
}
import java.io.File;
import java.nio.charset.Charset;
import java.util.List;

public class Main {

/**
* @param args
*/
public static void main(String... aArgs) {
if (aArgs.length != 1) {
System.out.println("ログファイルをひとつだけ指定してください");
return;
}

File tFile = new File(aArgs[0]);
if (!tFile.exists()) {
System.out.println("対象ファイルがみつかりません");
return;
}

Charset tCharset = Charset.forName("EUC-JP");
try {
List<LogItem> tLogs = new LogParser(tCharset).parse(tFile);
new LogAggregator(tLogs).printAggregate(5 * 60 * 1000);
} catch (Exception e) {
e.printStackTrace();
}
}

}
以上、4クラス。
同じパッケージに入れてね。

ログインすると、みんなのコメントがもっと見れるよ

mixiユーザー
ログインしてコメントしよう!

Javaの課題丸投げ 更新情報

Javaの課題丸投げのメンバーはこんなコミュニティにも参加しています

星印の数は、共通して参加しているメンバーが多いほど増えます。

人気コミュニティランキング