Help us understand the problem. What is going on with this article?

commander.jsでらくらく集計バッチ作成

More than 5 years have passed since last update.

簡単なログファイルの処理にはshell scriptやperlなどを使っていましたが、大きくなく、かつ、大したことがない処理にnode.jsでちゃちゃっと書くことが増えて来ました。

その理由として、d3.jsがcsvやt svをparseしてくれたり、配列の集計などのメソッドが揃っているがあります。

この投稿では、下記2つのモジュールの使い方をご説明します。

  1. commander.js
  2. d3.js

d3.js

d3.jsはmike bostock氏による集計+SVG操作ツールです。
この投稿ではSVG操作は利用しません。

data = d3.csv.parse csvString

として、Object Arrayに変換し、その後、
coffeescript:
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種類あります。

  1. 引数なしのフラグ .option('-v, --verbose', 'description')
  2. 引数が必要なオプション .option('-u,--url <url>', 'url', String)
  3. 引数がオプショナルなオプション .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の行が全部入ってる }] }
#   }
# ]
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away