2015年5月29日金曜日

Jenkins で ListView 内に存在する Job の数を Count する方法

概要

Countjobs Viewstabbarを使います

環境

  • CentOS 6.6 64bit
  • Jenkins 1.615
  • Countjobs Viewstabbar 1.0.0

インストール方法

Jenkins -> Jenkinsの管理 -> プラグインの管理

と進み

利用可能タブ -> 検索窓に「Countjobs Viewstabbar」を入力 -> チェック -> ダウンロードして再起動後にインストール

で再起動が完了すればOKです

設定

Jenkins -> Jenkinsの管理 -> システムの設定

と進み
「Views Tab Bar」を「CountJobs Views TabBar」に変更して保存

こんな感じ

jenkins_job_count.png

2015年5月28日木曜日

Capistrano で環境ごとに設定値を分ける手法

概要

Capistrano3ではcapコマンド実行時に環境を指定する必要があります
レシピ内で環境ごとに設定した値を参照する方法を紹介します
また今回紹介する方法以外にも様々な方法があるのであくまで参考程度に御覧ください

環境

  • CentOS 6.6 64bit
  • Capistrano 3.4.0

環境ごとの設定を記載する

cap installを使って初期設定をするとconfig/deploy/production.rbconfig/deploy/staging.rbというファイルができます
これに設定ごとの値を設定します

例えば以下の設定をそれぞれのファイルに記載してください

  • config/deploy/production.rb
set :env, "prd"
  • config/deploy/staging.rb
set :env, "stg"

「:env」というシンボルに値をsetします
この :env をレシピ側受け取って処理してみます

レシピ側で値を取得する

Capistranoのレシピは「lib/capistrano/tasks/sample.rake」に作成しているものとします
例えばあるレシピ上でシンボルを取得するには以下のようにします

namespace :test do

  desc 'this is test task'
  task :do_test do
    on roles :all do
      puts fetch(:env)
    end
  end

end

見ていただければ一目瞭然ですが、fetchというメソッドをタスク内で使用することで値を取得できます
以下のように書くことも可能です

puts "#{fetch(:env)}"

変数展開の形でも記載できます

こんな感じでconfig用のruby側で必要な値をsetしてそれをレシピ側でfetchするのが簡単です
そもそもsetするときにJsonから読み取ってsetするなんてこともできると思います

参考サイト

2015年5月27日水曜日

td-agent + Zabbix で Apache のレスポンスコードを監視する

概要

Apacheのログに出力されるレスポンスコードをZabbixで監視したいと思いました
Zabbixのログ監視 (log or logrt) でもいいかなと思ったのですがgrepルールを作成するのが面倒だったのでtd-agentを使って解決してみました

環境

  • CentOS 6.3 64bit
  • Zabbix Server 2.0.3
  • td-agent 0.12.7
  • fluent-plugin-zabbix 0.0.7
  • Apache Httpd 2.2.5

各種インストール

curl -L https://td-toolbelt.herokuapp.com/sh/install-redhat-td-agent2.sh | sh

上記のcurlコマンドでtd-agentをインストールした場合はyumコマンドでインストールしたことになっているので今後はrpmコマンドやyumコマンドから管理できるようになります

  • Apache Httpd
yum install httpd

全体的な流れ

簡単に今回紹介する作業の流れを記載します

  1. fluent-plugin-zabbix のインストール
  2. td-agent.conf の修正
  3. ACLの疎通確認
  4. Zabbix側にアイテムの登録
  5. 動作確認

という流れになります

fluent-plugin-zabbix のインストール

td-agentをインストールすると同時にtd-agent-gemというコマンドも利用できるようになります
これを使うとRubygemsで公開されているtd-agent用のプラグインを簡単に追加することができます

早速Zabbixと連携するためのプラグインをインストールします

td-agent-gem install fluent-plugin-zabbix fluent-plugin-datacounter

これでOKです
fluent-plugin-datacounterはZabbixにデータを送信する前に出現したステータスの回数をカウントするために使うので同時にインストールしておきます

td-agent.conf の修正

source

まずApacheのログファイルをtd-agentに入力させる設定を記載します

  • vim /etc/td-agent/td-agent.conf
<source>
  type tail
  format apache2
  path /var/log/httpd/access.log
  pos_file /var/log/td-agent/access.log.pos
  tag apache.log
</source>

今回はApacheのログはカスタマイズされていないデフォルトのログフォーマットを想定しています
もしログフォーマットが変更になっている場合はformatを独自のログパースフォーマットにしtime_formatを指定する必要があります
formatについてはこの記事の最後の方に作り方を紹介しているので参考にしてみてください

match

次に入力されたログからステータスコードの部分を取得しカウントする処理を記載します

  • vim /etc/td-agent/td-agent.conf
<match apache.log>
  type datacounter
  unit minute
  count_key code
  tag apache.status.count
  # patternX: X(1-9)
  pattern1 2xx ^2\d\d$
  pattern2 3xx ^3\d\d$
  pattern3 4xx ^4\d\d$
  pattern4 5xx ^5\d\d$
</match>

ここでfluent-plugin-datacounterを使います
Apacheのステータスコード+fluent-plugin-datacounterの組み合わせは定番と言っていいほど使われていると思います
Webでも検索すればサンプルはたくさん出てくると思います

unitパラメータで1分間で出現したステータスの量をカウントするようにしています
count_key<source>でパースしたログのステータスコードを表す部分のキーを設定してください
sourceでapache2を指定した場合はステータスコードの情報はcodeというキーに格納されるようです (参考)
ここも独自のフォーマットを作成した場合はそのフォーマットに合わせたキーを指定するようにしてください
patternXパラメータは1から指定していきます
ここで指定したパターンごとに値を集計してくれます

最後に集計したカウント結果をZabbixのアイテムとして登録する設定を記載します

<match apache.status.count>
  type zabbix
  zabbix_server zabbix_server
  host hostname
  name_key_pattern app.log_(unmatched|2xx|3xx|4xx|5xx)_count
</match>

zabbix_serverパラメータははZabbix ServerのIPアドレスまたはホスト名を入力します
hostパラメータは自信のホスト名を入力します

ポイントはname_key_patternパラメータです
この後、Zabbixにアイテムを登録するのですが、Zabbixのアイテムのキーと同じパターンにしなければいけない他、datacounterプラグインで出力されるJsonのキーとも一致している必要がありそうです
fluent-plugin-zabbixのソースコードを読んでいないので予測ですがname_key_patternで指定したキー情報を元にJsonから情報を取得し、取得した情報をZabbixの指定したキーと合致するアイテムに登録しているのだと思います

fileやstdoutで一度表示してみるとわかると思います
unmatchedというパターンもありますが、datacounterで指定したパターンに一致しない場合にここに格納されます

Tips

Zabbixに送信する前に値がちゃんと集計されているか確認したい場合は最後のmatchを書く前に以下を代わりに書いてテストするといいと思います

<match apache.status.count>
  type file
  path /var/log/td-agent/apache_status_count.log
</match>

集計結果をファイルに吐くようにしています
これでApacheにアクセスしてみて結果がファイルにちゃんと出力されることを確認してからZabbixに転送するmatchを書き始めてもいいと思います
ファイルに吐くのも面倒なのであればstdoutを使うのもいいと思います
注意するのはunitパラメータがminuteなのでログに出力されるのも1分毎になります

Zabbix側にアイテムの登録

Zabbixにアイテムを登録します
ここで作成するアイテムに対してtd-agentからアクセスが来てデータが格納されていきます
ここではテンプレートにアイテムを追加する手順をベースに紹介します

設定 -> テンプレート -> アイテムを追加したテンプレートのアイテム一覧を選択 -> アイテムの作成

でアイテム作成画面を表示し必要な情報を入力していきます

  • 名前 : apache.log_2xx_count (なんでもOKです、わかりやすい情報を入力しましょう)
  • タイプ : Zabbixトラッパー
  • キー : apache.log_2xx_count (td-agent.confのtype zabbixで入力した値と同じ値を設定する必要があります)

今回は単純にステータスの出現カウントをZabbixで管理したいと思います
キーにはname_key_patternで指定したパターンと同じキーを指定します
なので上記の要領で「apache.log_2xx_count」「apache.log_3xx_count」「apache.log_4xx_count」「apache.log_5xx_count」「apache.log_unmatched_count」と5つ分のアイテムを登録してください

カウント以外にも「rate」と「percentage」という項目もtd-agent側は送ってくれているので「apache.log_2xx_rate」「apache.log_2xx_percentage」 … みたいなアイテムを追加すればそこにも値が入るようになります
rate と percentage は型を浮動小数点型にするといいです

ACLの疎通確認

今回Zabbixトラッパーを使うため

App in td-agent -> tcp/10051 -> Zabbix Server

の疎通が必要になります
通常のZabbix監視ではServerから監視対象のAppへの10050が通っていればアイテムを取得できますが今回は逆方向の通信が必要になります

動作確認

Zabbix Server, td-agent, Apache を起動してアクセスしてみて最終的にZabbix Serverにデータが登録されていればOKです
確認は最新データあたりから実施するといいと思います

問題になりそうなのはtd-agent.confの設定だと思います

  • <source>で指定したログがちゃんと存在するか、アクセス権限はあるか
  • <source>で指定したformatでちゃんとログがパースできているか
  • <match>のdatacounterの定義の部分でカウントするべきcount_keyが間違っていないか
  • <match>のdatacounterの定義の部分でpatternXがちゃんと設定されているか
  • <match>のdatacounterのあとでちゃんとデータが取得できているのか
  • <match>のzabbixの定義で疎通はちゃんとできているか
  • <match>のzabbixの定義でname_key_patternに指定しているパターンはdatacounterの出力パターンと一致しているか
  • <match>のzabbixの定義でname_key_patternに指定しているパターンはZabbixに登録したアイテムのパターンと一致しているか

などなど結構ハマリポイントはあると思います
また後述のTipsに記載しているのもハマリポイントだと思います(自分はハマリました)
対応方法としては1つ1つsourceやmatchを検証するのがいいと思います
いきなり全部を連結しようとするとうまく行かないので、まずはstdoutで出力してちゃんとデータが取れているか確認するといいと思います
あとは、td-agent.conf のログを詳細に出すようにして確認しながら解決していく感じでしょうか

Tips

当たり前なのかもしれないですが念のためメモしておきます
matchに該当する定義が複数ある場合はtd-agent.confの先に書かれているほうが優先されるようです

例えば

<source>
  type tail
  path /path/to/log
  tag access.log
  ...
</source>

<match access.*>
  type zabbix
  ...
</match>

<match access.log>
  type file
  ...
</match>

としている場合には先に書かれているmatchが優先されるためあとに書かれたfileのmatchは実行されません

P.S 20150527
type copyを使うと解決できます
http://papix.hatenablog.com/entry/2014/11/05/185449

最後に

どれもこれもOSSを使っているのでバージョンが上がれば手順は変わると思いますのでご注意ください

最終的に可視化されるようになると運用では便利なのでぜひ頑張って構築してみてください

参考サイト

2015年5月25日月曜日

au から softbank にMNP したので契約内容や手続き方法をメモ

概要

前回から2年、auの契約が満2年を迎えたのでsoftbankにMNPで乗り換えました
契約内容と手続き方法、初回設定で実施したことを紹介します

環境

  • au 時の契約情報は前回の記事を参照してください
  • softbank iPhone6 16GB

MNPするのに必要なこと

MNP予約番号が必要です
auの場合は電話か店頭に行って発行してもらうことになります
スマホを使っている場合はauのアプリから発行することはできないようです
発行したMNP予約番号は15日間有効です

契約時に必要なこと

今回はヨドバシカメラで契約手続きをしたのでそれをベースに紹介します
持ち物は

  • MNP予約番号
  • クレジットカード
  • 身分証明書

の3点になります
これだけあれば契約を進めることが可能です
ほしい機種が決まればあとは手続きを進めるだけです
softbankの場合、契約すべてiPadで電子情報ベースで進めます
紙で何か説明したり契約書をもらったりすることはありません
契約内容はアプリですべて確認します

契約の手続き

契約の流れは

  • 身分証の登録
  • クレジットカードの登録
  • Tポイントカードとの連携
  • iPhone6のアクティベーション
  • softbank専用の一括設定

身分証の登録やクレジットカードの登録は特に何も注意することはないです
店員の方がガツガツ進めてくれます

契約時にTポイントカードを持っていればソフトバンクの月額料金と連携することができ、月額料金の何%かがTポイントとして加算されます

iPhone6のアクティベーションとsoftbank専用の一括設定はちょっと気をつけたほうがいいかもしれません

アクティベーションも基本店員がやってくれますがドンドンすすめるのでtouchIDやAppleIDの登録はスルーされるので、あとで自分で実施する必要があります
一括設定はsoftbank専用のアプリを強制的にインストールされます
たぶんこれは必須作業ですが、一括設定の内容も不明でドンドン進められるので何をやっているか気になる方はその場で聞いたほうがいいかもしれません

契約内容

今回はiPhone6は一括で支払いました

本体価格は83,040円
でそこから割引が58,000円分発生しました
割引の内容は20,000ポイントのヨドバシポイント付与と38,000ポイントの追加でのヨドバシポイント発生でした
20,000ポイントは必ずついてくるのですが、追加の38,000ポイントは2台同時で契約したためについてくる特典でした
いい忘れましたが、今回2台をMNPでsoftbankに乗り換えています
ということで一括で支払った価格は

83,040 - 58,000 = 25,040
25,040 x 2 = 50,080円

をその場で支払いました
ヨドバシポイントが5%分付いてきました (2,500pt)

そして月額の契約内容ですが

  • 通話し放題プラン -> 2,700円
  • データ定額パック・標準 5GB -> 5,000円
  • S!ベーシックパック -> 300円
  • ユニバーサルサービス料 -> 2円
  • 月々割 -> -2,635円
  • のりかえ割 -> -926円
  • 消費税 -> 355円

で合計 税込4,796円(になるはずです)
※P.S 20150703
金額修正しました、これで確定です
また、契約初月の金額について、契約内容の最後に記載しました
※P.S 20150803
すいません、割引適用の初月分が確定したので再度修正しました
消費税の課税額は (通話し放題プラン + データ定額パック・標準 5GB + S!ベーシックパック + ユニバーサル料 - 月々割 - のりかえ割) = 4,441 の金額の8%になるみたいです

Webで契約内容がまだ詳細に確認できないので間違っていたら修正します
自分の場合だけかもしれませんが一発目の契約では「かけ放題」のプランに入会させられました
月額1,000円の「ホワイトプラン」に変更したい場合は契約後、プラン変更する必要があります(後日、ホワイトプランに変更後の契約内容も追記したいと思います)
※P.S 20150607
「初回入会時のプランについて」にプランの変更について記載しました、かなり重要なのことを書いています

また強制的に入会させられる有料オプションは全部その日に解約しました
解約したオプションサービスは後述しているのでそちらを参照してください
のりかえ割はその場では適用されません、どうやら審査があるらしく審査が通ると後日ソフトバンクからメールが来るので、そのメールからのりかえ割を適用します
のりかえ割はソフトバンクカードのポイント10,800pt分か1,000円の割引10ヶ月分かを選択することができるのでお好きな方をお選びください

あとはauでのMNP予約番号の事務手数料が2,160円
softbankの契約事務手数料が3,240円
が別途最終月および初月の請求に上乗せされます
また、ポイントして初月は「のりかえ割」と「月々割」が適用になりません
http://faq.mb.softbank.jp/detail.aspx?cid=81920&id=e6b46417351337632386236306c4e483068506f7931673d3d
なので契約初月の請求金額満額は

  • 通話し放題プラン -> 2,700円
  • データ定額パック・標準 5GB -> 5,000円
  • S!ベーシックパック -> 300円
  • 事務手数料 -> 3,000円
  • ユニバーサルサービス料 -> 2円
  • 消費税 -> 880円

で合計 税込11,882円
になります (高い!)
満額と記載しているのは通話し放題プランとS!ベーシックパックは日割りになるので契約日によって金額が前後するのでご注意ください

初回入会時のプランについて

今回契約はヨドバシカメラで行いました
その際に「通話し放題」+「データ定額パック・標準 5GB」で半ば強制的に入会させられました
理由としては一括購入時の追加ポイント 38,000pt 分の 20,000pt 分が上記プランでないと適用されないため(だったような気がしています)
そして、そのときに後でプランをホワイトプランに変更できることは説明されました

で、ポイントはここからで今回 au からの MNP なので 10 ヶ月分の「のりかえ割」という月額割引が発生します
この「のりかえ割」がプランを変更すると失効してしまいます(これが大事)
なので、初回に契約時に入会した「通話し放題」+「データ定額パック・標準 5GB」を「ホワイトプラン」に変更しようとしたら割引が失効してしまいます

正直ガッガリしました
その仕様を知らなかった自分が悪いと言えばそうですが、契約時にちゃんと説明してほしいと感じました
まぁこれが家電量販店の罠というやつでしょうか

仕方ないのでプランはそのままにして、10ヶ月後に割引が終了したあとで、もしホワイトプランが残っていたらホワイトプランに乗り換えたいと思います

※P.S 20150617
データ定額パック・標準5GBの場合「快適モード」というモードが別途存在しています
これは簡単にいうと「5GBを超えそうになったら勝手に課金して、通信速度を維持しますよー」という、うんこ機能です
デフォルトでONになっているため5GBを超えそうになると課金する旨のメールが届いて勝手に課金された上で通信速度を維持してくれます
勝手に課金しないために、「快適モード」を「制限モード」に変更しておきましょう
これも MySoftbank から設定可能です

契約確認 -> データ通信量 -> ご利用状況の確認

で制限モードに変更

すぐに実施した初期設定

  • AppleIDの設定
    • 設定 -> iTunes&AppStore
  • iCloudの設定
    • 設定 -> iCloud
  • Touch IDの設定
    • 設定 -> Touch IDとパスコード
  • Gmailと連絡先の同期
    • 設定 -> メール/連絡先/カレンダー -> アカウントを追加 -> CardDAV でGoogleアカウントを認証
  • 各種パスワードの保管
    • Softbankのネットワークパスワード(数字4桁)
    • SoftBankID
  • Softbankのアカウント設定
    • MySoftBankにログインしてPWの変更
    • メールアドレスの設定(softbank.ne.jp, i.softbank.jp は携帯からMySoftbankアプリで実施する)
  • 自動で登録されてしまったオプションサービスの解除
    • iPhone基本パックR
    • アニメ放題
    • あんしん保証パック(i)プラス
    • UULA(別途パスワードが必要)
    • ディズニーマーケット・オン・ソフトバンク(QRコードの読み込みから実施)
    • とく放題(M)
  • その他端末設定
    • Wi-Fi
    • 電池のパーセント表示
    • 目覚し時計の設定
    • iPhoneの名前設定
  • 一括設定でインストールされたアプリの削除
  • 必要なアプリのインストールと設定

2015年5月18日月曜日

log4j2 で出力した Json ログを LogStash でパースしてみた

概要

第一弾としてElasticSearch + LogStash の連携を紹介しました
第二弾ではlog4j2でJson形式のログを出力できるようにしました
そして今回第三弾としてlog4j2で出力したJsonログをLogStashで拾ってElasticSearchに投げるところまでやってみたいと思います

環境

  • CentOS 6.6 64bit
  • Java 1.8.0_25
  • ElasticSearch 1.5.2
  • LogStash 1.4.2
  • log4j2 2.3

事前準備

ElasticSearch + LogStashのインストールおよび設定は第一弾の記事を参考に構築してください
log4j2のJSONLayoutの設定は第二弾を参考にコーディングしてください
今回は上記が完了している体で話を進めます

log4j2でファイルにJsonログを出力できるようにする

log4j2.xmlappendersタグに以下を追加します

<RollingFile name="RollingFile" fileName="logs/rolling_app.json" filePattern="logs/rolling_app_%d{yyyy-MM-dd}.json">
  <JSONLayout compact="true" eventEol="true" locationInfo="true">
  </JSONLayout>
  <Policies>
    <TimeBasedTriggeringPolicy />
  </Policies>
</RollingFile>

このAppenderはJsonのログを出力する専用のAppenderになります
日時でローテートするように設定しています

loggersには「RollingFile」という名前のappenderを参照するloggerを定義しましょう

<appender-ref ref="RollingFile" />

パッケージやログレベルは適宜調整してください

これを定義した状態で一度実行してみましょう
うまくいっていればプロジェクト配下に logs/rolling_app.json ができています

messageのフォーマットを決定する

今回はJava側でロギングするときにはスペースで区切らたデータをロギングするようにします
例えば以下のような感じで3つの項目をロギングするようにします

log.trace("kakakikikeke 20 Japan");

(この辺がだいぶいけてないのですが)上記のようにロギングすると「message」というフィールドの値としてJson出力されます
値は必ず文字列として出力されます

LogStash でJsonログをパースするconfigファイルを作成する

Java側が出力するJsonログをパースするconfigファイルは以下のような感じです

input {
  file {
    type => 'my-type'
    path => '/path/to/log/rolling_app.json'
    codec => json
  }
}

filter {
  date {
    match => [ "timeMillis", "UNIX_MS" ]
    target => "@timestamp"
    locale => "ja"
    timezone => "Asia/Tokyo"
  }
  grok {
    match => [ "message", "%{GREEDYDATA:username} %{GREEDYDATA:age} %{GREEDYDATA:country} ]
  }
}

output {
  stdout {
    codec => rubydebug
  }
  elasticsearch {
    host => localhost
  }
}

ポイントはfilter -> grok -> matchの部分です
Jsonロギングされたmessageフィールドの情報を正規表現を使ってマッチさせることができます
今回はスペースで区切られたフィールドをパースするだけなので正規表現は使っていません
「GREEDYDATA」の部分はパースした値の型を指定することができます
今回は全部 GREEDYDATA を指定していますが数字ならば「NUMBER」短い単語ならば「WORD」なども使うことができます
試していて「_grokparsefailure」のエラーになる場合は全部「GREEDYDATA」にしておけばOKかと思います
(もしかしたらちゃんと型を指定することで何かしらの恩知が受けれるかもしれません)

各種起動

ElasticSearch -> LogStash -> log4j2 の順番で起動していきます
ElasticSearchは特に設定ファイル等は何もいじっていないのでそのまま起動すればOKです
LogStashは作成した上記の設定ファイルを指定して起動しましょう

ElasticSearch と LogStash が起動できたらJsonロギングできるJavaアプリを起動させてJsonロギングさせてみましょう
LogStashは「rubydebug」しているのでログをうまくパースできればコンソール上に表示されると思います
最終的にはElasticSearchにちゃんとデータが入っているか確認したほうがいいでしょう

curl 'http://localhost:9200/_search?pretty'

とりあえずこれでデータが入っていればひと通りの連携は完了です

最後に

いけてないのはJsonロギングするJava側が必ず同じフォーマットでロギングしなければいけない点です
今回は3項目出力しましたが、これが4つとかになったらコードを改修しなければいけないですしLogStash側のconfigファイルも修正が必要です
ネットを調べているとmessageフィールドにJSONオブジェクトを出力させてLogStash側でRubyスクリプトを組んでログをパースする方法が紹介されていました
http://kapaski.github.io/blog/2014/07/24/logstash-to-parse-json-with-json-arrays-in-values/
これ自体もかなり力技なのですが、log4j2を使ってJson出力するとmessageフィールドが必ず文字列で出力されてしまいます
なので上記の方法すら使うことができません

またLogStash側のgrokもmessageフィールド以外をパースすることができない(?)みたいでlog4j2のThreadContextを使って別のフィールドにJsonオブジェクトを出力してもそれをパースすることができません
(ちょっとこの辺は調査不足かもしれませんが自分はできずに諦めました)

という理由もあって今回はスペースで区切った値をロギングをすることでそれをLogStash側でパースしたのですが、そもそもスペースで区切るならロギングするJava側もJsonで出力する必要はなかったんですよね
スペース区切りのロギングをしてそのファイルをLogStash側でパースするだけなので
わざわざJsonにして良かった点はLogStashのinputのcodecにjsonが使えたことくらいでしょうか

2015年5月17日日曜日

log4j2 を使って Json 形式のログを出力してみた

概要

log4j2を使ってJson形式のログを1行ずつ出力してみました
Githubで昔公開したlog4j2のサンプルソースを使って解説します

環境

  • Windows7 64bit
  • Eclipse 4.4 Luna
  • Java 1.8.0_25
  • log4j2 2.3

各種インストールと設定

Githubで公開しているサンプルプロジェクトはMavenを使っているのでMavenも使えるようにしておいてください
Eclipseのm2eの組み込みのMavenでもOKです
サンプルプロジェクトを使う場合はgit cloneしてEclipseのEGitでプロジェクトをEclipseに読み込んでからインポートしてください
.projectファイルと.classpathファイルもコミットしているのでインポートすれば特に設定せずに使えると思います

もちろん自分で開発しているプロジェクトでもOKです

必要なライブラリのインストール

log4j2を使うためのライブラリをインストールします
また、Json形式のログを出力できるようにするためにJacksonを使います

pom.xmlのdepenciesタグ内に以下を追記します

<!-- for log4j2 -->
<dependency>
    <groupId>org.apache.logging.log4j</groupId>
    <artifactId>log4j-api</artifactId>
    <version>2.3</version>
</dependency>
<dependency>
    <groupId>org.apache.logging.log4j</groupId>
    <artifactId>log4j-core</artifactId>
    <version>2.3</version>
</dependency>
<!-- for log4j2 of JSONLayout -->
<dependency>
  <groupId>com.fasterxml.jackson.core</groupId>
  <artifactId>jackson-core</artifactId>
  <version>2.5.3</version>
</dependency>
<dependency>
  <groupId>com.fasterxml.jackson.core</groupId>
  <artifactId>jackson-databind</artifactId>
  <version>2.5.3</version>
</dependency>

これでlog4j2でJson形式のログを出力するためのライブラリのインストールは完了です
記載したら自動でビルドされると思いますが一旦プロジェクトをクリーンするといいと思います

log4j2.xml の編集

サンプルのプロジェクトだと「src/main/java/log4j2.xml」になります
今回は標準出力にJson形式のログを出力してみます
Json形式のログを出力するためにはJSONLayoutというAppenderを利用します
以下のような感じでlog4j2.xmlのappendersタグ内に記載します

<appenders>
  <Console name="Console" target="SYSTEM_OUT">
    <JSONLayout>
    </JSONLayout>
  </Console>
</appenders>

JSONLayoutは<patter>タブを使って出力形式を設定しません
設定すると「JSONLayoutでは<patter>タグは使えないよ」という感じのERRORが出ると思います
あとは上記のConsole Appenderを参照するloggersを追加してあげればOKです

Javaからの使い方

特にJsonLayoutだからと言って特別な使い方はありません
いつも通りロギング用のオブジェクトを生成してlog.debugとかを呼び出せばOKです

サンプルだと以下のような感じで使っています

package com.kakakikikeke.sample;

import org.apache.logging.log4j.Logger;
import org.apache.logging.log4j.LogManager;

public class Log4j2Sample {

    private static Logger log;

    public Log4j2Sample() {
        log = LogManager.getLogger(Log4j2Sample.this);
    }

    public static void main(String[] args) {
        new Log4j2Sample();
        log.error("This is error messages");
        log.trace("下記以降はlog4j2.xmlファイルがクラスパスに通っていないと表示されません");
        log.trace("This is trace messages");
    }

}

出力されるログのサンプル

これで準備は整いました
サンプルのプロジェクトを使っている場合はcom.kakakikikeke.sample.Log4j2Sample.javaを右クリックしてRun As -> Java ApplicationとすればOKです

出力のサンプルは以下のとおりです

{
  "timeMillis" : 1431667419708,
  "thread" : "main",
  "level" : "ERROR",
  "loggerName" : "com.kakakikikeke.sample.Log4j2Sample",
  "message" : "This is error messages",
  "endOfBatch" : false,
  "loggerFqcn" : "org.apache.logging.log4j.spi.AbstractLogger"
}

こんな感じでlog.errorとかでロギングした行ごとにJsonが出力されます
自身でしていしたログメッセージはmessageフィールドとして出力されるようです

Tips

これでとりあえずJson形式のログを出力することはできました
ですがこのままだとログを1行ずつ処理するときに非常に面倒です
なので、1Jsonログを1行で出力するための設定を追加します

<JSONLayout compact="true" eventEol="true">

compacteventEolというパラメータをtrueで設定してあげます
すると改行されてきれいに見えていたJsonが1行ごとに改行されて出力されるようになります
ログ解析を目的としているならこのパラメータを付与してあげるのがいいと思います

最後に

いろいろ調べてやってみたのですがJSONLayoutのlog4j2.xmlのサンプルがなかったり、JavaのサンプルのコードがなかったりとWebに情報が少ないよういに感じました
まだ少ないだけなのかJavaでそもそもJson形式のログを吐くこと自体需要がないのか
はたまた、Java自体に需要がないのか・・・

まぁとりあえずJson形式のログが吐けるようになったのであとはtd-agentやlogstashでログを飛ばして可視化してみたいと思います
その辺の連携も紹介できればしたいと思います

参考サイト

2015年5月15日金曜日

Android で default で使える drawable 一覧

概要

drawableはボタンやアイコンにするいわゆる画像のことです
普通は「drawable-hdpi」や「drawable-mdpi」といったフォルダに .png ファイルを配置して「@drawable/hoge」みたいな感じで png ファイルを参照します

ただ、よく使うアイコンはAndroid SDKにデフォルトで搭載されています
デフォルトで搭載されているアイコンを使えば、いちいち自分で画像を作成する手間も省けます

環境

  • Mac OS X 10.10.3
  • Android SDK 24.1.2

使えるアイコンの一覧

全ては上記に記載されています
ここに記載されているリソースはデフォルトで使用できます
例えばお気に入りとかで使用する星アイコンは以下のように参照することができます

<item
  android:id="@+id/favorite"
  android:icon="@android:drawable/star_off"
  android:showAsAction="ifRoom"
  android:orderInCategory="20"
  android:title="@string/favorite"/>

上記の例はオプションメニュー(ActionBar)内で表示する項目にアイコンを設定する際にデフォルトのアイコン「star_off」を使った例です
「android:」の部分はもしかしたら不要かもしれません

ポイントは冒頭に紹介した一覧にあるアイコンしかデフォルトでは使えないということです
Webで調べると「ic_menu_refresh」などがデフォルトで使えるという記載があるのですが、コンパイルエラーになります
自分も一覧を見るまでは使えると思っていたのですがいざ使ってみるとコンパイルエラーとなり確かに一覧にも載っていませんでした

なのでコンパイルエラーになる場合はまず一覧に存在するアイコンなのか調べてみるといいと思います
残念なのは一覧にリソース名でしか紹介がないので、どんなアイコンなのかは実際に使ってみるか、リソース名でGoogleで画像検索とかするとわかると思います

最後に

デザインできない開発者にとってはこういうアイコン集をデフォルトで用意してくれるのは嬉しいです
また、デフォルトで用意されているアイコンは他のアプリで使われている可能性も高いのでUX的にもいいと思います
そのアイコンのコンテキストが implicit で理解されているとわざわざラベルをつける必要もなくなると思います

2015年5月12日火曜日

ElasticSearch + LogStash の連携を検証してみる

概要

ElasticSearch + Logstash の連携を検証してみました
本当に触りの部分だけ試しています

環境

  • CentOS 6.6 64bit
  • Java 1.8.0_31
  • ElasticSearch 1.5.2
  • LogStach 1.4.2

Javaインストール

yum -y install java-1.8.0-openjdk
echo 'export JAVA_HOME=/usr/lib/jvm/java/' >> ~/.bashrc
source ~/.bashrc

ElasticSearch インストール

cd /var/tmp
wget 'https://download.elastic.co/elasticsearch/elasticsearch/elasticsearch-1.5.2.zip'
unzip elasticsearch-1.5.2.zip
mv elasticsearch-1.5.2 /usr/local/
cd /usr/local/
ln -nfs elasticsearch-1.5.2 elasticsearch
echo 'export PATH=$PATH:/usr/local/elasticsearch/bin' >> ~/.bashrc
source ~/.bashrc

LogStash インストール

cd /var/tmp
wget 'https://download.elastic.co/logstash/logstash/logstash-1.4.2.zip'
unzip logstash-1.4.2.zip
mv logstash-1.4.2 /usr/local/
cd /usr/local/
ln -nfs logstash-1.4.2/ logstash
echo 'export PATH=$PATH:/usr/local/logstash/bin' >> ~/.bashrc
source ~/.bashrc

ElasticSearchとLogStashの連携

LogStashでアプリのログをElasticSearchに投げてみたいと思います
今回はElasticSearchもLogStashも同一ホストで動作することを想定しています

ElasticSearch起動

elasticsearch

今回はsupervisorなどでデーモン化はしていません
起動中はターミナルを閉じないようにしてください
9200番でLISTENしていることを確認してください

LogStashからログを投げてみる

logstash -e 'input { stdin { } } output { elasticsearch { host => localhost } }'

とすることでインタラクティブモードで起動し入力した文字列をElasticSearchに投げてくれます
起動したら適当な文字列を入力してみてください

そしたらElasticSearchにデータが投入されているか確認してみます

curl 'http://localhost:9200/_search?pretty'

これで確認すると入力したデータが格納されていることがわかると思います

Tips

「-e」で渡した設定はファイルに記載することも可能です

  • cat interactive_input.conf
input {
  stdin {
  }
}
output {
  elasticsearch {
    host => localhost
  }
}

こんな感じで設定ファイルには記載して「-f」オプションを使ってファイルを指定します

  • logstash -f interactive_input.conf

これでもOKです

最後に

インストールはzipをダウンロードし適当なディレクトリに配置することで実施しましたがyumとapt用のリポジトリも用意されているようです
http://www.elastic.co/guide/en/logstash/current/package-repositories.html

普通に使う場合はログを解析して使うことになると思います
ログ連携はまた別の記事で紹介できればと思います

参考サイト

2015年5月8日金曜日

Maven でビルド時に CheckStyle を実行する

概要

Mavenビルド時に CheckStyle を適用したいと思います
CodeStyleの目的は

  • ソースの可読性をあげる
  • 無駄なコードを排除する
  • 複数人で開発している場合に変数名やクラス名などに統一性を持たせる

などあります
ビルド時に実施することで強制的にスタイルを合わせることができるので間違いも発見しやすくなります

今回はEclipseを使って基本的な設定から独自のルール設定をする方法まで紹介したいと思います

環境

  • Windows7 64bit
  • Java 1.8.0_25
  • Maven 3.2.2
  • maven-checkstyle-plugin 2.1.5
  • Eclipse 4.4 Luna
  • Eclipse CheckStyle Plugin 6.5.0

maven-checkstyle-plugin のインストール

pom.xmlを編集します
<build> -> <plugins>配下に以下を追記することでインストール可能です

<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-checkstyle-plugin</artifactId>
    <version>2.15</version>
    <executions>
        <execution>
            <phase>test</phase>
            <goals>
                <goal>check</goal>
            </goals>
        </execution>
    </executions>
    <configuration>
        <configLocation>checkstyle.xml</configLocation>
        <encoding>UTF-8</encoding>
        <consoleOutput>true</consoleOutput>
        <failsOnError>true</failsOnError>
        <linkXRef>false</linkXRef>
    </configuration>
</plugin>

Mavenビルド時のtestフェーズでCheckstyleを実施します
<configLocation>に独自のCheckstyleルールを設定することができます
ここを指定しないとデフォルトで提供されるconfig/sun_checks.xmlというルールが適用されます
それを使っても問題ないのですが、ルールが結構厳しいので今回はもう少し緩めのルールを使いたいと思います

checkstyle.xmlを作成する

その緩めのルールを作成したいと思います
ルールはデフォルトで用意されているものをコピーして作成したいと思います
デフォルトのルールをコピーするのにEclipseの「Checkstyle Plug-in」をインストールします

Checkstyle Plug-inのインストール

Help -> Eclipse Marketplace -> Search

で「checkstyle」と入力してください
以下のプラグインが検索されるのでInstall -> Finishとしてインストールしましょう
install_checkstyle_plugin.png

途中利用規約に同意してEclipseの再起動を求められるので再起動してください

再起動が完了すればインストールが完了です

デフォルトで用意されているのcheckstyle.xmlをコピーする

Window -> Preferences -> Checkstyle

と移動します
デフォルトで用意されているCheckstyleのルールが表示されます

プラグインのバージョンにもよると思いますが3種類のデフォルトルールがありました
そのうち「Google Checks」というルールがプラグインではデフォルトで使われているようです
今回はこれではなく「Sun Checks (Eclipse)」のルールを元にcheckstyle.xmlを作成します
list_default_checkstyle.png

上記の画面から「Sun Checks (Eclipse)」を選択した状態で「Copy」をクリックしてください
Typeに「External Configuration File」を選択します
Locationにはcheckstyle.xmlを保存するパスを指定します
今回はプロジェクトのカレントディレクトリを指定しましょう
create_checkstyle.png

こんな感じで入力してOKをクリックしましょう
するとプロジェクトの直下に「checkstyle.xml」というファイルができていると思います
これがCheckstyleするときに適用されるルールになります

ビルドしてみる

この状態でMavenビルドすればCheckStyleをかけることができます
testフェーズで実施されるのでmvn packageあたりでビルドすればOKです

初回はプラグインのダウンロード等が発生するので遅いですが2回目以降はスムーズに終了すると思います
maven-checkstyle-pluginのログの部分だけ抜粋すると以下のようになっていました

[INFO] --- maven-checkstyle-plugin:2.15:check (default) @ test-webapp ---
[INFO] Starting audit...
Audit done.

最終的にはBUILD SUCCESSになっていればOKです

ルールを独自に編集してみる

ルールの詳細はこちらを御覧ください

今回用意したcheckstyle.xmlはかなり緩く、そして結構謎なチェックルールが多いです
ほとんどコーティングしていない環境であれば警告はほぼでないと思いますが、結構開発していてコード量も多い場合は平気で1000とかの単位で警告が出ます
そんな場合はルールを変更して警告を無視するようなことをよくやります

例えば以下のようなコードを追加するだけで結構な警告が出るようになります

package test;

public class Test {

    private String name;

    public Test(String name) {
        super();
        this.name = name;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

}

出現する警告は以下の通り

[INFO] --- maven-checkstyle-plugin:2.15:check (default) @ test-webapp ---
[INFO] Starting audit...
C:\Users\kakakikikeke\workspace\test-webapp\src\main\java\test\Test.java:0: warning: Missing package-info.java file.
C:\Users\kakakikikeke\workspace\test-webapp\src\main\java\test\Test.java:3: warning: Javadoc コメントがありません。
C:\Users\kakakikikeke\workspace\test-webapp\src\main\java\test\Test.java:5:5: warning: Javadoc コメントがありません。
C:\Users\kakakikikeke\workspace\test-webapp\src\main\java\test\Test.java:7:5: warning: Javadoc コメントがありません。
C:\Users\kakakikikeke\workspace\test-webapp\src\main\java\test\Test.java:7:17: warning: Parameter name should be final.
C:\Users\kakakikikeke\workspace\test-webapp\src\main\java\test\Test.java:7:24: warning: 'name' がフィールドを隠しています。
C:\Users\kakakikikeke\workspace\test-webapp\src\main\java\test\Test.java:12:5: warning: Javadoc コメントがありません。
C:\Users\kakakikikeke\workspace\test-webapp\src\main\java\test\Test.java:12:5: warning: メソッド 'getName' は拡張するように設計されていません - abstract か final か空である必要があります。
C:\Users\kakakikikeke\workspace\test-webapp\src\main\java\test\Test.java:16:5: warning: Javadoc コメントがありません。
C:\Users\kakakikikeke\workspace\test-webapp\src\main\java\test\Test.java:16:5: warning: メソッド 'setName' は拡張するように設計されていません - abstract か final か空である必要があります。
C:\Users\kakakikikeke\workspace\test-webapp\src\main\java\test\Test.java:16:25: warning: Parameter name should be final.
C:\Users\kakakikikeke\workspace\test-webapp\src\main\java\test\Test.java:16:32: warning: 'name' がフィールドを隠しています。
Audit done.

今回の設定の場合は緩いルールを使っているので警告として怒られるのでビルド自体は最後までいきます
主に怒られるのはJavadoc系になると思います
Eclipse等のIDEで開発している場合IDE自体がある程度フォーマットしてくれるのでスペースがない等のエラーはあまり見ないと思います
ではこの警告の一部を無視する設定を紹介します

Checkstyleの警告を無視する設定を追加する

設定はEclipseであればGUIを使って行うことができます
もちろんcheckstyle.xmlを直接編集してXMLを書き直すでもOKです

Window -> Preferences -> Checkstyle

でプラグインに登録されているルールの一覧を表示したら今回のプロジェクトが使っているルールをダブルクリックしてください
するとルールを設定するウィンドウが表示されるのでここで

Javadoc Comments -> Package Javadoc

のチェックボックスをOFFにしてください
OFFにしたらOKでウィンドウを閉じてください
ignore_package_info_warning.png

これでcheckstyle.xmlの方にも設定を反映することができます
一旦ウィンドウを閉じて再度mvn packageでビルドしてみてください

再度ビルドしてみる

ビルドの結果を見てみましょう
すると先ほど警告されていた先頭の

warning: Missing package-info.java file.

が警告されなくなっているのがわかると思います

こんな感じでルールの編集を行うことができます
GUIからだと割りと直感的にルールを編集することができます
それでも英語のkeywordから何を設定しているのかを読み解く部分も出てくると思いますので
その場合はドキュメントを読むなりWebで調べるなりする必要が出てきます

最後に

導入自体は割りと簡単に行えますが導入後に自分でルールを調整しなければいけなく、XMLとの戦いを避けられないのが辛いところです

それでも一度導入できてしまえば再度変更することはほとんどないと思うので、それと比較するとCheckStyleを導入する恩知は大きいと思います

個人で開発する分には導入するメリットはそれほど無いかもしれませんが、チームで開発していたりオープンソースとして公開することを目標にしているのであれば
むしろ導入は必須と言っていいかもしれません

2015年5月7日木曜日

buildnumber-maven-plugin を使って war ファイル内の Manifest.MF にリビジョン情報を埋め込む

概要

作成したwarの中にgitのリビジョン情報があると何かと便利です
いつのコミットから生成されたwarなのか知りたいケースは多いと思います
Mavenを使ってリビジョン情報を埋め込むことができたので紹介します

環境

  • Windows7 64bit
  • Java 1.8.0_25
  • Maven 3.2.2
  • buildnumber-maven-plugin 1.3
  • maven-war-plugin 2.6

Mavenでサンプル用のWebアプリプロジェクトを作成

適当に作成すればOKです
すでにmvn packageでwarが作成できるプロジェクトがあればそれでもいいです
ない場合はこちらを参考に作成してください
Eclipseの場合はMavenプロジェクトを作成する際にアーティファクトIDにmaven-archetype-webappを選択してサンプルプロジェクトを作成してください

また、今回はプロジェクト自体がgitリポジトリで管理されていることを想定しているのでプロジェクトをgit化してください
リモートリポジトリはなくてもいいのでgit initできていればOKです
Eclipseの場合は

Team -> Share Project -> Git -> Use or create repository in parent folder or project -> Create Repository

としてgit化してください

そしてgit add->git commitとしてはじめのコミットを作成しておきましょう

buildnumber-maven-pluginの設定

pom.xmlを編集します
<build> -> <plugins>タグ内に以下のプラグインを追加します

<plugin>
    <groupId>org.codehaus.mojo</groupId>
    <artifactId>buildnumber-maven-plugin</artifactId>
    <version>1.3</version>
    <executions>
        <execution>
            <phase>validate</phase>
            <goals>
                <goal>create</goal>
            </goals>
        </execution>
    </executions>
    <configuration>
        <doCheck>false</doCheck>
        <doUpdate>false</doUpdate>
    </configuration>
</plugin>

上記を記載することでbuildnumber-maven-pluginが有効になります

ポイントはdoCheckdoUpdateのタグの部分です
falseを設定することで以下の効果があります

  • git statusを使って差分チェックをしなくなります
  • git pullをして最新のソースをremoteからマージしなくなります

上記が有効だとmvnビルドするのにいちいちgitコミットしなければいけないのとgit pullをするための認証情報の設定を別途記載する必要があります
trueでも設定さえちゃんとされていればビルドは次に進みますが個人的にはyak shavingしているだけの印象だったのでfalseを設定しました
また、falseを設定することでgitコマンド自体が不要になるのでEclipse上でmvnビルドしている場合は

[ERROR] ‘git’ は、内部コマンドまたは外部コマンド、操作可能なプログラムまたはバッチ ファイルとして認識されていません。

というエラーが出るのを回避することもできます

warをアーカイブするときにManifest.MFを拡張

Manifest.MFを拡張するにはmaven-war-pluginを定義し直します
pom.xmlを編集します
<build> -> <plugins>タグ内に以下のプラグインを追加します

<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-war-plugin</artifactId>
    <version>2.6</version>
    <executions>
        <execution>
            <phase>package</phase>
            <goals>
                <goal>war</goal>
            </goals>
        </execution>
    </executions>
    <configuration>
        <archive>
            <manifestEntries>
                <Implementation-ScmBranch>${scmBranch}</Implementation-ScmBranch>
                <Implementation-Build>${buildNumber}</Implementation-Build>
            </manifestEntries>
        </archive>
    </configuration>
</plugin>

ポイントは<archive> -> <manifestEntries>内の2つの宣言で特にvalueの変数が重要です
buildnumber-maven-pluginを有効にすることで${scmBranch}${buildNumber}という変数が使えるようになります
ここで指定するタグは何でもOKです
記載したタグ情報がそのままManifest.MFに記載されることになります

scm の設定を追記

どこのgitのリビジョン情報を参照するのかpom.xml内に記載する必要があります
この設定は<project>タグ直下に記載してください

この定義がないとcreate failed: The scm url cannot be null.という言われて怒られます
以下の設定をpom.xmlに記載します

<scm>
    <connection>scm:git:file://.</connection>
    <developerConnection>scm:git:file://.</developerConnection>
    <url>scm:git:file://.</url>
    <tag>HEAD</tag>
</scm>

今回の想定はプロジェクト自体がgitで管理されていることを想定しています
なのでプロジェクト自体を指し示すようにscmを定義します
もちろんここにはGithubのURLやイントラネット内にあるgitリポジトリを指定することも可能です

ビルドしてみる

ここまで設定できたらビルドしてみましょう
コマンドで実行する場合は
mvn package
でOKです

Eclipseで実行する場合はRun As -> Maven build でgoalsにpackageを指定して実行しましょう

ビルドが成功するとtargetディレクトリ配下にwarファイルが作成できています
このwarファイルを解凍してMETA-INF/Manifest.MFを見てみましょう
以下のようにリビジョン情報とビルドしたブランチ情報が追記されていればOKです

Manifest-Version: 1.0
Built-By: kakakikikeke
Build-Jdk: 1.8.0_25
Implementation-ScmBranch: master
Created-By: Apache Maven 3.2.1
Implementation-Build: 29fb55a9daa2afc3961b9759d0f4e50ca3cac281
Archiver-Version: Plexus Archiver

紹介は以上です
今回はリビジョン情報を埋め込みましたがManifest.MFには他にもいろいろな情報を埋め込めるので好きな情報を埋め込むといいと思います

参考サイト