簡単なログファイルの処理にはshell scriptやperlなどを使っていましたが、大きくなく、かつ、大したことがない処理にnode.jsでちゃちゃっと書くことが増えて来ました。
その理由として、d3.jsがcsvやt svをparseしてくれたり、配列の集計などのメソッドが揃っているがあります。
この投稿では、下記2つのモジュールの使い方をご説明します。
d3.js
d3.jsはmike bostock氏による集計+SVG操作ツールです。
この投稿ではSVG操作は利用しません。
data = d3.csv.parse csvString
として、Object Arrayに変換し、その後、
d3.nest().key((d)-> d.key).entries(data)
とするだけで、簡単にkeyでの集計を行うことができます。
また、タグの回数の集計などで利用したObjectも簡単に配列にすることができます。
d3.entries({"node.js": 32, "hadoop": 43})
# [{key: "node.js", value: 32}, {key: "hadoop", value: 43}]
ただ、こちらは、coffeeを利用している場合は、下記と等価な処理となります。
({ key: key, value: value} for key, value of {"node.js": 32, "hadoop": 43})
commander
commander.jsはTJによって開発された、コマンドラインのためのヘルパーモジュールです。
例えば引数としてファイルのパスを取るような場合は、下記のように記述するだけです。
fs = require 'fs'
commander = require 'commander'
program = commander.version('0.0.0')
.parse(process.argv)
[filename] = program.args
program.help() unless filename
program.help()
と書くと使い方を表示した上で、process.exitでプロセスを終了してくれます。
また、オプションを取るときには、次のように記述します。
fs = require 'fs'
commander = require 'commander'
program = commander.version('0.0.0')
.option('-v,--verbose', 'url')
.option('-u,--url <url>', 'url', String)
.option('-o,--option [optional]', 'url', String)
.parse(process.argv)
[filename] = program.args
url = program.url
program.help() unless filename or url
オプションの書き方は3種類あります。
- 引数なしのフラグ
.option('-v, --verbose', 'description')
- 引数が必要なオプション
.option('-u,--url <url>', 'url', String)
- 引数がオプショナルなオプション
.option('-o,--option [optional]', 'url', String)
まとめ
2つのモジュールを利用することで、csvでもtsvでも、もちろん、JSONでも、簡単に取り込んで集計処理を書くことができます。
サンプル
例えば、アクセスログのCSV(これをどうやって入手したか、があれですが)が会ったとすると
fs = require 'fs'
commander = require 'commander'
program = commander.version('0.0.0')
.parse(process.argv)
[filename] = program.args
program.help() unless filename
lines = d3.csv.parse fs.readFileSync filename, 'utf8'
d3.nest().key((d)-> d.status).entries lines
# [
# { key: 200, values: [ {status 200の行が全部入ってる }] }
# { key: 404, values: [ {status 404の行が全部入ってる }] }
# { key: 500, values: [ {status 500の行が全部入ってる }] }
# ]
# 時間あたりのステータスの割合の場合は`.key()`をchainします。
lines = d3.csv.parse fs.readFileSync filename, 'utf8'
hour = d3.time.format("%Y%m%d%H0000")
d3.nest().key((d)-> hour(d.time)).key((d)-> d.status).entries lines
# [
# { key: 20130524120000, values: [
# { key: 200, values: [ {status 200の行が全部入ってる }] }
# { key: 404, values: [ {status 404の行が全部入ってる }] }
# { key: 500, values: [ {status 500の行が全部入ってる }] }
# }
# { key: 20130524130000, values: [
# { key: 200, values: [ {status 200の行が全部入ってる }] }
# { key: 404, values: [ {status 404の行が全部入ってる }] }
# { key: 500, values: [ {status 500の行が全部入ってる }] }
# }
# { key: 20130524140000, values: [
# { key: 200, values: [ {status 200の行が全部入ってる }] }
# { key: 404, values: [ {status 404の行が全部入ってる }] }
# { key: 500, values: [ {status 500の行が全部入ってる }] }
# }
# ]