H2Databaseを追っかけていたりしたブログ

H2 database のリリースノートを読んだりとか。

ltsvなログをSQLで集計する

javaのltsvなパーサー見当たらなかったから作ってみた、と思ったらもうあった。こんにちは。

でも、SQLでltsvを操作できるってのは無いだろうと言うことで、まぁ。

package com.karatebancho.h2tools;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.Types;
import java.util.ArrayList;
import java.util.List;
import java.util.StringTokenizer;
import org.h2.tools.SimpleResultSet;

public class LTSV {
    public static ResultSet read(Connection conn, String fileName) throws Exception {
        BufferedReader reader = new BufferedReader(new FileReader(new File(fileName)));
        String record;
        SimpleResultSet rs = new SimpleResultSet();
        try {
            boolean isFirstRecord = true;
            while ((record = reader.readLine()) != null) {
                addRow(rs, record, isFirstRecord);
                if(isFirstRecord){
                    String url = conn.getMetaData().getURL();
                    if (url.equals("jdbc:columnlist:connection")) {
                        return rs;
                    }
                    isFirstRecord = false;
                }
            }
        } finally {
            reader.close();
        }
        return rs;
    }

    protected static void addRow(SimpleResultSet rs, String record, boolean addColumn) {
        List<Object> row = new ArrayList<Object>();
        StringTokenizer rt = new StringTokenizer(record, "\t");
        while (rt.hasMoreTokens()) {
            String field = rt.nextToken();
            String[] labelValue = parseField(field);
            if (addColumn) {
                rs.addColumn(labelValue[0].toUpperCase(), Types.VARCHAR, Integer.MAX_VALUE, 0);
            }
            row.add(labelValue[1]);
        }
        rs.addRow(row.toArray());
    }

    protected static String[] parseField(String field) {
        if (field == null || field.length() == 0) {
            return null;
        }
        int pos = field.indexOf(':');
        if (pos < 0) {
            return new String[] { field, "" };
        }
        return new String[] { field.substring(0, pos), field.substring(pos + 1) };
    }
}

適当にjarに固めて、みんな大好きh2databaseと一緒に起動します。

java -cp h2-1.3.170.jar:h2tools-1.0-SNAPSHOT.jar org.h2.tools.Shell -url jdbc:h2:mem:

Welcome to H2 Shell 1.3.170 (2012-11-30)
Exit with Ctrl+C
Commands are case insensitive; SQL statements end with ';'
help or ?      Display this help
list           Toggle result list / stack trace mode
maxwidth       Set maximum column width (default is 100)
autocommit     Enable or disable autocommit
history        Show the last 20 statements
quit or exit   Close the connection and exit

エイリアスとして登録します。

sql> create alias ltsv for "com.karatebancho.h2tools.LTSV.read";

好きなようにSQLでなんやかやします。

sql> select host,count(*) from ltsv('/path/to/ltsv/test.log') group by host;
HOST        | COUNT(*)
127.0.0.1   | 3
192.168.1.1 | 1
192.168.1.2 | 2
192.168.1.3 | 2
(4 rows, 15 ms)
sql> 

ログファイルはSQLで処理できると色々捗るよ。

追記:

githubにあげました。

https://github.com/ysobj/h2tools

mavenizeされているので、mvn package でh2tools-1.0-SNAPSHOT.jarができます。