fluent-plugin-s3 + fluent-plugin-dstatのフォーマットで保存されていたS3上のログをEmbulkを使ってMySQLに投入してみた

というわけでEmbulkを使ってみたのでメモです。

対象のログ

  • Fluentdで収集
  • dstatの情報を fluent-plugin-dstat で取得
  • fluent-plugin-s3 を利用してS3に保存
  • gzip圧縮

つまりこんなログです。

2016-01-31T15:24:42Z  examplekey  {"hostname":"example.com","dstat":{"total cpu usage":{"usr":"0.201","sys":"0.134","idl":"99.532","wai":"0.134","hiq":"0.0","siq":"0.0"},"mem\
ory usage":{"used":"1212170240.0","buff":"313139200.0","cach":"2034069504.0","free":"246816768.0"},"load avg":{"1m":"0.090","5m":"0.080","15m":"0.090"},"net/total":{"recv":"108.\
867","send":"212.200"}}}

Embulkのインストール

まずはEmbulkをインストールします。

$ brew cask install java
$ brew install embulk

次に必要そうなPluginをインストールします。

以下は、とりあえず最終的に必要になったもの。

$ embulk gem install embulk-input-s3
$ embulk gem install embulk-output-mysql
$ embulk gem install embulk-parser-fluent-s3-log
$ embulk gem install embulk-filter-expand_json
$ embulk gem install embulk-filter-column

inとoutを適当にかいて embulk guess

まずは in がS3なのはわかります。

github.com

tmp.yml とかに

in:
  type: s3
  bucket: my-logs
  path_prefix: web/
  access_key_id: XXXXXXXXXXXXXXXXXXXXXX
  secret_access_key: XXXXXXXXXXXXXXXXXXXXXX
out:
  type: stdout

くらいを書いて

$ embulk guess tmp.yml -o config.yml

と実行するとあら不思議、「いい感じに」設定用ファイルのフォーマットを config.yml として生成してくれます。

Embulkの半分は優しさでできているのか?

生成された config.yml をPluginのドキュメントを見ながら修正して、 embulk preview config.yml でプレビュー。うまくいかないときは embulk guess で微調整していきます。

fluent-plugin-s3のフォーマットのファイルをいい感じにパースしてくれる embulk-parser-fluent-s3-log

fluent-plugin-s3で保存したログのフォーマットはタイムスタンプ、キー、JSONと並んでいたので、さてどうしたものかと思ったら「まさに」なプラグインがありました。

github.com

in:
  type: s3
  bucket: my-logs
  path_prefix: web/
  access_key_id: XXXXXXXXXXXXXXXXXXXXXX
  secret_access_key: XXXXXXXXXXXXXXXXXXXXXX
  decoders:
  - {type: gzip}
  parser:
    type: fluent-s3-log
    columns:
      - {name: hostname, type: string}
      - {name: dstat, type: string}
out:
  type: stdout

ネストされたJSONを展開してくれるembulk-filter-expand_json

カラム dstat の部分はネストしたJSONのままなので展開する必要があります。

こちらも「まさに」なプラグインがありました。

github.com

今回は dstat カラム部分を展開するので以下のように記述しました。

in:
  type: s3
  bucket: my-logs
  path_prefix: web/
  access_key_id: XXXXXXXXXXXXXXXXXXXXXX
  secret_access_key: XXXXXXXXXXXXXXXXXXXXXX
  decoders:
  - {type: gzip}
  parser:
    type: fluent-s3-log
    columns:
      - {name: hostname, type: string}
      - {name: dstat, type: string}
filters:
  - type: expand_json
    json_column_name: dstat
    root: "$."
    expanded_columns:
      - {name: "['total cpu usage'].usr", type: double}
      - {name: "['total cpu usage'].sys", type: double}
      - {name: "['total cpu usage'].idl", type: double}
      - {name: "['total cpu usage'].wai", type: double}
      - {name: "['total cpu usage'].hiq", type: double}
      - {name: "['total cpu usage'].siq", type: double}
      - {name: "['memory usage'].used", type: double}
      - {name: "['memory usage'].buff", type: double}
      - {name: "['memory usage'].cach", type: double}
      - {name: "['memory usage'].free", type: double}
      - {name: "['load avg'].1m", type: double}
      - {name: "['load avg'].5m", type: double}
      - {name: "['load avg'].15m", type: double}
      - {name: "['net/total'].recv", type: double}
      - {name: "['net/total'].send", type: double}
out:
  type: stdout

MySQLカラム名に合わせるために in 側のカラム名のリネーム

カラム名"['total cpu usage'].usr" のままだとMySQLカラム名にするのには微妙なので、カラム名をリネームします。

こちらも「まさに」なプラグインがありました。

github.com

in:
  type: s3
  bucket: my-logs
  path_prefix: web/
  access_key_id: XXXXXXXXXXXXXXXXXXXXXX
  secret_access_key: XXXXXXXXXXXXXXXXXXXXXX
  decoders:
  - {type: gzip}
  parser:
    type: fluent-s3-log
    columns:
      - {name: hostname, type: string}
      - {name: dstat, type: string}
filters:
  - type: expand_json
    json_column_name: dstat
    root: "$."
    expanded_columns:
      - {name: "['total cpu usage'].usr", type: double}
      - {name: "['total cpu usage'].sys", type: double}
      - {name: "['total cpu usage'].idl", type: double}
      - {name: "['total cpu usage'].wai", type: double}
      - {name: "['total cpu usage'].hiq", type: double}
      - {name: "['total cpu usage'].siq", type: double}
      - {name: "['memory usage'].used", type: double}
      - {name: "['memory usage'].buff", type: double}
      - {name: "['memory usage'].cach", type: double}
      - {name: "['memory usage'].free", type: double}
      - {name: "['load avg'].1m", type: double}
      - {name: "['load avg'].5m", type: double}
      - {name: "['load avg'].15m", type: double}
      - {name: "['net/total'].recv", type: double}
      - {name: "['net/total'].send", type: double}
  - type: column
    columns:
      - {name: time}
      - {name: key}
      - {name: hostname}
      - {name: cpu_usr, src: "['total cpu usage'].usr"}
      - {name: cpu_sys, src: "['total cpu usage'].sys"}
      - {name: cpu_idl, src: "['total cpu usage'].idl"}
      - {name: cpu_wai, src: "['total cpu usage'].wai"}
      - {name: cpu_hiq, src: "['total cpu usage'].hiq"}
      - {name: cpu_siq, src: "['total cpu usage'].siq"}
      - {name: mem_used, src: "['memory usage'].used"}
      - {name: mem_buff, src: "['memory usage'].buff"}
      - {name: mem_cach, src: "['memory usage'].cach"}
      - {name: mem_free, src: "['memory usage'].free"}
      - {name: load_1m, src: "['load avg'].1m"}
      - {name: load_5m, src: "['load avg'].5m"}
      - {name: load_15m, src: "['load avg'].15m"}
      - {name: net_recv, src: "['net/total'].recv"}
      - {name: net_send, src: "['net/total'].send"}
out:
  type: stdout

out の設定

outMySQLなので、MySQLでテーブルを作成して、設定したら終わりです。

github.com

以下が最終形態の config.yml です。

in:
  type: s3
  bucket: my-logs
  path_prefix: web/
  access_key_id: XXXXXXXXXXXXXXXXXXXXXX
  secret_access_key: XXXXXXXXXXXXXXXXXXXXXX
  decoders:
  - {type: gzip}
  parser:
    type: fluent-s3-log
    columns:
      - {name: hostname, type: string}
      - {name: dstat, type: string}
filters:
  - type: expand_json
    json_column_name: dstat
    root: "$."
    expanded_columns:
      - {name: "['total cpu usage'].usr", type: double}
      - {name: "['total cpu usage'].sys", type: double}
      - {name: "['total cpu usage'].idl", type: double}
      - {name: "['total cpu usage'].wai", type: double}
      - {name: "['total cpu usage'].hiq", type: double}
      - {name: "['total cpu usage'].siq", type: double}
      - {name: "['memory usage'].used", type: double}
      - {name: "['memory usage'].buff", type: double}
      - {name: "['memory usage'].cach", type: double}
      - {name: "['memory usage'].free", type: double}
      - {name: "['load avg'].1m", type: double}
      - {name: "['load avg'].5m", type: double}
      - {name: "['load avg'].15m", type: double}
      - {name: "['net/total'].recv", type: double}
      - {name: "['net/total'].send", type: double}
  - type: column
    columns:
      - {name: time}
      - {name: key}
      - {name: hostname}
      - {name: cpu_usr, src: "['total cpu usage'].usr"}
      - {name: cpu_sys, src: "['total cpu usage'].sys"}
      - {name: cpu_idl, src: "['total cpu usage'].idl"}
      - {name: cpu_wai, src: "['total cpu usage'].wai"}
      - {name: cpu_hiq, src: "['total cpu usage'].hiq"}
      - {name: cpu_siq, src: "['total cpu usage'].siq"}
      - {name: mem_used, src: "['memory usage'].used"}
      - {name: mem_buff, src: "['memory usage'].buff"}
      - {name: mem_cach, src: "['memory usage'].cach"}
      - {name: mem_free, src: "['memory usage'].free"}
      - {name: load_1m, src: "['load avg'].1m"}
      - {name: load_5m, src: "['load avg'].5m"}
      - {name: load_15m, src: "['load avg'].15m"}
      - {name: net_recv, src: "['net/total'].recv"}
      - {name: net_send, src: "['net/total'].send"}
out:
  type: mysql
  host: localhost
  user: username
  password: userpassword
  database: my_s3_logs
  table: dstat
  mode: insert

実行

$ embulk run config.yml

約80万レコードをS3からの取得から開始して数十分でMySQLに投入できました。これは早い(自分で書かなくてよかった。。。)。

Embulk便利!!

プラグインも今あるもので大抵のことは実現出来そうです。

これからは積極的使っていこうと思います。

今日のCakePHP3

  • 初めてのfind()
  • logQuery(true) 良い。
<?php
    $conn = \Cake\Datasource\ConnectionManager::get('test');
    $conn->logQueries(true);
  • namespaceによるいい感じのクラスの差し替え良い。holiday_jp-php を使って、Timeクラスに isHoliday() メソッドを生やすなどした。
  • Collection良い。
    • HtmlHelper::tableCells() とかと合わせても活用できそう。
  • 早速、Validatorを拡張したくなっているのだけれども、どうしたものか。

遅れに遅れて今更CakePHP3を触りはじめた

まだまだ、全然わかっていない状況です。

社内では既にいろいろと地雷は踏み潰され、さらにPluginもいろいろできている状況からの最後尾スタート。

とりあえず、今日の感想は

  • ビルドインサーバ最高。Vagrantがいらない。Mac上でカジュアルに開発できるの面白い。
  • MigrationsはPhinxを既につかっていたので、面白みがない。使っていなければよかった(感動的な意味で)。
  • ルーティングされるURLが今までと違って焦った。DashedRoute がデフォルトで「なんだこのルーティング???」となってた(CakePHP2っぽいのは InflectedRoute)。ビルドインサーバのせいだと思って「ビルドインサーバ使えないのか。。」とか落ち込んでたらビルドインサーバのせいではなかった。

これから頑張る。

github.com

AWSなコマンドラインツールをつくるときにAWS CLIと同じようにAWSアクセスキーやリージョン情報を取得できるライブラリ awsecrets

を作って、awspeckumomeで使っています。

github.com

使い方

例えば、EC2インスタンスの情報をただ取得するコマンドラインツールを作るとき Awsecrets.load メソッドを利用して

#!/usr/bin/env ruby
require 'awsecrets'
Awsecrets.load
ec2_client = Aws::EC2::Client.new
puts ec2_client.describe_instances({ instance_ids: [ARGV.first] }).reservations.first.instances.first

というコマンドラインツール ec2sample を書いたら、

$ ec2sample i-1aa1aaaa --profile mycreds --region ap-northeast-1

$ AWS_ACCESS_KEY_ID=XXXXXXXXXXXXXXXXXXXX AWS_SECRET_ACCESS_KEY=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX AWS_REGION=ap-northeast-1 ec2sample i-1aa1aaaa

$ cat <<EOF > secrets.yml
region: ap-northeast-1
aws_access_key_id: XXXXXXXXXXXXXXXXXXXX
aws_secret_access_key: XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
EOF
$ ec2sample i-1aa1aaaa

など、AWS CLIと同じような感じでAWSアクセスキーやリージョンを取得して Aws::config にセットしていい感じに aws-sdk を活用できます。中身はaws_config.gemとaws-sdk.gemでできています。

使いドコロは難しいですが、RubyAWSコマンドラインツールをつくるときには是非ご検討ください。

AWS CloudWatchのメトリクスをCLIからカジュアルに確認できるツールkumomeを作った

AWSのCloudWatchのメトリクスをCLIからカジュアルに確認したいと思ってツールを作り始めている - Copy/Cut/Paste/Hatena

の続きです。kumome という名前でリリースしました。

github.com

asciicast

これは何?

AWS CloudWatchのメトリクスをCLIから確認するためのツールです。特徴としてコマンドオプションをYAMLファイルで拡張できます。

インストールは

$ gem install kumome

デフォルトの設定では ec2 rds elb のメトリクスを取得可能になっています。

$ kumome --ec2=i-123ab45c,i-890ed12c --rds=my-rds --elb=my-elb --profile mycreds

デフォルトの設定は以下。kumome config で現在の設定を出力可能です。

---
resources:
  ec2:
    namespace: AWS/EC2 # required
    dimensions_name: InstanceId # required
    metrics:
      cpu:
        metric_name: CPUUtilization # required
        statistic: Average # required
        unit: Percent
        alarm: '>=50' # "metric alarm name" or "operator and number"
      netin:
        metric_name: NetworkIn
        statistic: Average
        unit: Bytes
      netout:
        metric_name: NetworkOut
        statistic: Average
        unit: Bytes
  rds:
    namespace: AWS/RDS
    dimensions_name: DBInstanceIdentifier
    metrics:
      cpu:
        metric_name: CPUUtilization
        statistic: Average
        unit: Percent
        alarm: '>=50'
      read:
        metric_name: ReadIOPS
        statistic: Average
        unit: Count/Second
      write:
        metric_name: WriteIOPS
        statistic: Average
      conn:
        metric_name: DatabaseConnections
        statistic: Average
        unit: Count
        alarm: '>=50'
  elb:
    namespace: AWS/ELB
    dimensions_name: LoadBalancerName
    metrics:
      req:
        metric_name: RequestCount
        statistic: Sum
      400:
        metric_name: HTTPCode_Backend_4XX
        statistic: Sum
      500:
        metric_name: HTTPCode_Backend_5XX
        statistic: Sum

例えばAWS Lambdaのメトリクスを取得したいときには、以下のようなコンフィグを記述します。

---
resources:
  lambda: # "command option name"
    namespace: AWS/Lambda # required
    dimensions_name: FunctionName # required
    metrics:
      count:
        metric_name: Invocations # required
        statistic: Sum # required
        unit: Count
        alarm: '>=100' # "metric alarm name" or "operator and number"
      error:
        metric_name: Errors
        statistic: Sum
        unit: Count
        alarm: '>=5'
      duration:
        metric_name: Duration
        statistic: Average

そうすれば新たに ---lambda オプションをつくることができます。

$ kumome --config=./custom.yml --lambda=my-lambda-func-name,hook-lambda-func-name --profile mycreds

カスタムメトリクス用のコマンドオプションも作り放題です。

というわけで

自分は、プロジェクトごとにconfig.ymlを作成しておいて、何かあったときは、Amazon Management Consoleにログインして確認するのではなく、まず kumome でざっと確認するようにしています。

カジュアルに確認できるので、心理的に良いです。

まだ、作り始めたばかりですので機能も少ないですが是非お試し下さい。 Pull Requestお待ちしています。

KickstarterでサポートしていたRoost Laptop Standが届いた

届いた!

www.kickstarter.com

出資から届くまで

Roostの存在をRebuildで知る

rebuild.fm

おお、2014/10。。。

2015/05 ふとポチる

Kickstarter経由でRoostから経過報告をもらう

大体1ヶ月に1〜2回メールが届いていました。

途中に送付先住所の登録とか、別の商品の紹介とかもありました。

で、その瞬間だけ思い出して、メールを眺めて、あとは忘れていました。

2015/12/30 Roostから出荷の連絡が

DHL Expressという配達会社経由で送付したのこと、出荷追跡もできるようになっていました。

ここから楽しみになってきました。

無事受け取り

ずっと、不在通知がきている状況でしたが、なんとか今日受け取ることができました!

届くまで結構長かったので、予想外のプレゼントみたいでうれしい。

開けてみて

f:id:k1LoW:20160109151207j:plain

意外に小さめ。専用ポーチ付き。

f:id:k1LoW:20160109210004j:plain

15inchもしっかりホールドできています。ホールドする部分のギミックがとても良い

f:id:k1LoW:20160109210109j:plain

軽い。丈夫そうですが、とりあえずこれから使ってみてみようと思います。

AWSのCloudWatchのメトリクスをCLIからカジュアルに確認したいと思ってツールを作り始めている

asciicast

やりたいこと

  • 何か問題が発生した時に、手元のターミナルでAWSリソースの状況をカジュアルに確認したい
    • 初動を早くしたい
    • プロジェクトが多すぎて「ディスプレイで常に見える化」みたいなのは無理

現状

  • インスタンスIDとかRDSのIDを指定したらCloudWatchのメトリクス情報を *stat ライクに表示する
  • YAMLファイルでCloudWatchで取得するメトリクス情報を実質的にいくらでも拡張可能(YAMLファイルでオプションを拡張する実装)

ちなみにデフォルトのYAMLファイルは以下のような感じ。

---
resources:
  ec2:
    namespace: AWS/EC2
    dimensions_name: InstanceId
    metrics:
      cpu:
        metric_name: CPUUtilization
        statistic: Average
      netin:
        metric_name: NetworkIn
        statistic: Average
      netout:
        metric_name: NetworkOut
        statistic: Average
  rds:
    namespace: AWS/RDS
    dimensions_name: DBInstanceIdentifier
    metrics:
      cpu:
        metric_name: CPUUtilization
        statistic: Average
      read:
        metric_name: ReadIOPS
        statistic: Average
      write:
        metric_name: WriteIOPS
        statistic: Average
  elb:
    namespace: AWS/ELB
    dimensions_name: LoadBalancerName
    metrics:
      req:
        metric_name: RequestCount
        statistic: Sum
      400:
        metric_name: HTTPCode_Backend_4XX
        statistic: Sum
      500:
        metric_name: HTTPCode_Backend_5XX
        statistic: Sum

TODO / 検討事項

  • *stat ライクに定期間隔で追記出力(最短で1分間隔だけど。。。)
  • どれくらい行を出すかの設定(時間?最大行?)
  • CloudWatchアラームの状態で数値の色を変える?それともYAMLで設定?
  • テーブル表示がちょっと冗長なのでなんとかしたい。現在は tj/terminal-table · GitHub を利用
  • awstat という名前で作っているけれどもAWStatsとレーベンシュタイン距離が1