Slack 上のエンジニア同士の会話を増やした一つの工夫 + ちょっとした OSS の紹介

こんにちは、技術部開発基盤グループの小室 (id:hogelog) です。

最近エンジニアが全員集まる Slack のチャンネルからデプロイ通知等の機械的な通知を排除したらエンジニア同士のコミュニケーションがほぼ毎日発生するようになり満足しています。自分のような無名なペーペーエンジニアも業界に名を馳せる著名エンジニアもフラットに属しているチャンネルが通知で埋まっていて人間の会話がまったく発生しないなんてもったいないですからね。Slack のチャンネルをどう運用するか会社によって文化の違いがあると思いますが、良い運用は参考にしたいので各社どんどん発信してほしいのでよろしくおねがいします。

さてそんな話で終わっても良いのですが、ここは開発者ブログだしせっかくなので最近開発した Slack 関連のアプリケーションを紹介します。

tokite で GitHub から Slack への通知をカスタマイズ

クックパッドでは GitHub Enterprise (以下 GHE) 上で日々開発やレビューなどをおこなっています。そこで生まれる Issue や Pull Request などを Slack に通知するためのツールとして tokite というツールを実装しました。

https://github.com/hogelog/tokite

今までは主にメールとJasper *1 等を利用して GHE 上でのレビューやコミュニケーションを進めていました。 Slack 通知も利用していましたが、GitHub の Slack 通知はリポジトリ毎の設定しか存在せず、自分が見たい通知のみを特定のチャンネルに流すといったことはできませんでした。

それを解決するため作成したのがユーザ毎のルールで通知を設定できる tokite というツールです。

f:id:hogelog:20170719111939p:plain

tokite のルール

tokite ではユーザ毎に任意個数の通知ルールを設定します。ルールにはそれぞれクエリと通知先等を設定し、どのようなイベントを Slack のどのチャンネルに流したいかを決められます。

社内で運用している tokite に自分が設定しているルールは以下の3つです。

ルール名クエリ解説
opsrepo:tech-dept/ops開発基盤グループのタスク管理リポジトリの Issue を流すルール
呼ばれたbody:/sunao-komuro|dev-infra|hogelog/メンション等で自分のアカウント名、グループが呼ばれた時に流すルール
dev-infra-memberuser:/XXX|YYY|ZZZ/チームメンバーの発言を流すルール

また通知先のチャンネルは自分専用の通知チャンネルとして運用し、全発言が Notification を出すように設定しているためこれらのルールにマッチするイベントが発生すれば Slack 経由で通知が届くようになっています。

tokite の動作

tokite は各リポジトリの Webhook を元に、それぞれのイベントにマッチするルールがあれば Slack の対象チャンネルに通知するという動きをします。 ルールのクエリ実装はなにか既存のライブラリやフォーマットがないものだろうか、と少し探したのですがちょうど良いものが見当たらなかったため parslet *2 という PEG ライクなパーサライブラリを利用しました。PEG ベースのパーサライブラリは使ったことがなかったのですが、ドキュメントも丁寧で使いやすいライブラリでした。 ユーザ認証には GitHub を利用していて Webhook 追加も各ユーザのトークンをそのまま利用しています。

tokite で得られたもの

tokite を使うことでリアクションが必要な GHE 上で発生する同僚の行動 (Pull Request, Issue, Issue Comment) の通知をほぼ Slack に集約し、すぐに気付けるようになりました。

tokite を使う前でもメール、Jasper 等の経路でそれらの行動を観測することはできていました。ただし、僕にとってはそれはどうもかなり意識的におこなわなければできないことで、見逃しも度々ありました。一方で自分は Slack の通知ならばすぐに気づき自然に読み始めることができています*3。tokite による通知だけで完結するという程には至らずメールの通知や Jasper に頼っているところもあるのですが、Slack という経路が一つ増やせたのは割と実装した意味があったなと思っています。

今後の予定

tokite はある方が便利だなと感じていますが、今のところ機能は色々と足りていません。今後も OSS の形で公開しながら改善を続けていこうと思うので、よろしくおねがいします。

https://github.com/hogelog/tokite

*1:http://techlife.cookpad.com/entry/2017/03/14/100000

*2:http://kschiess.github.io/parslet/

*3:何故だろう。Slack のアプリケーションがよくできているからというのが大きい気がしている

ファイルを直接読み込んで集計する

こんにちは。マーケティングプロダクト開発部の中村です。今回は大量のデータを対象に集計できる Hive の使い方について説明しようと思います。

前提

私が所属しているマーケティングプロダクト開発部では広告配信も行っています。その広告配信では大量のアクセスログを蓄積しています。通常ですとそのログは Amazon Redshift で簡単に集計できます。しかし、ログファイルを直接集計しなければならない場合が稀にあります。その際に使用しているのが Amazon EMR です。今回は Hive を用いてその集計を手元の端末で試してみます。

インストール

まずは動作環境を作るために Hive をインストールします。

brew install hive

集計する前の準備

Hive は任意のディレクトリを作業ディレクトリとすることができます。まず、その作業ディレクトリを作成し、そのディレクトリに移動しておきます。

mkdir -p /tmp/cookpad/logs
cd /tmp/cookpad

次に、その作業ディレクトリで使用する Schema の種類を指定する必要があります。今回は資料でデフォルトで使われてる derby を選択します。

schematool -initSchema -dbType derby

ここまでの作業で、ローカルで起動させるための準備ができました。次に、実際に起動させてみます。

hive

Hive のコンソールが立ち上がれば成功です。

集計してみる

次にサンプルをもとに簡単に集計します。今回は Nginx のアクセスログをサンプルとして集計してみようと思います。具体的には以下の内容のファイルを /tmp/cookpad/logs/nginx.log として、先程作成したディレクトリ以下に保存します。

172.17.0.1 - - [14/Jul/2017:07:48:37 +0000] "GET / HTTP/1.1" 304 0 "-" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.115 Safari/537.36" "-"
172.17.0.1 - - [14/Jul/2017:07:48:38 +0000] "GET / HTTP/1.1" 304 0 "-" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.115 Safari/537.36" "-"
172.17.0.1 - - [14/Jul/2017:07:48:38 +0000] "GET / HTTP/1.1" 304 0 "-" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.115 Safari/537.36" "-"
172.17.0.1 - - [14/Jul/2017:07:49:19 +0000] "GET / HTTP/1.1" 304 0 "-" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.115 Safari/537.36" "-"
172.17.0.1 - - [14/Jul/2017:07:49:40 +0000] "GET /hoge HTTP/1.1" 404 571 "-" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.115 Safari/537.36" "-"
172.17.0.1 - - [14/Jul/2017:07:49:42 +0000] "GET /hoge HTTP/1.1" 404 571 "-" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.115 Safari/537.36" "-"
172.17.0.1 - - [14/Jul/2017:07:49:51 +0000] "GET /piyo HTTP/1.1" 404 571 "-" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.115 Safari/537.36" "-"
172.17.0.1 - - [14/Jul/2017:07:49:52 +0000] "GET /piyo HTTP/1.1" 404 571 "-" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.115 Safari/537.36" "-"
172.17.0.1 - - [14/Jul/2017:07:49:53 +0000] "GET /piyo HTTP/1.1" 404 571 "-" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.115 Safari/537.36" "-"

次にそのファイルを集計するクエリを用意します。なお Hive は起動時にクエリをファイルから読み込めるため、ファイルに書いた方が後から参照できて便利です。具体的には以下の内容で /tmp/cookpad/sample.q として保存します。

drop table nginx_logs;

create external table nginx_logs (
    remote_addr string
    , remote_user string
    , time_local string
    , method string
    , path string
    , protocol string
    , status int
    , body_bytes_sent int
    , http_referer string
    , http_user_agent string
)
row format serde
  'org.apache.hadoop.hive.serde2.RegexSerDe'
with serdeproperties (
    "input.regex" = "([0-9\\.]+) - ([^ ]*) \\[([^\\]]*)\\] \"([^ ]*) ([^ ]*) ([^ ]*)\" ([0-9]*) ([0-9]*) \"(.*)\" \"(.*)\""
)
location
    'file:///tmp/cookpad/logs'
;

select
    *
from
    nginx_logs
where
    path = '/hoge'
;

その保存したファイルを指定して Hive を起動します。

cd /tmp/cookpad/
hive -f /tmp/cookpad/sample.q

クエリが実行されてアクセスログが表示されれば成功です。

UDF を書いて Hive に組み込む

Hive には様々な関数が組み込まれています。通常の集計ではその関数で充分なのですが、時折複雑な条件で集計したくなります。そのようなときは関数を自作して組み込んで使用することができます。

実際に関数を組み込んで集計してみます。ただし、少し準備することが多いので事前にコードは GitHub に用意しておきました。以下のリポジトリを任意の場所に clone してください。

https://github.com/devisualy/udf

そのクローンした場所に移動してビルドします。具体的には以下のコマンドを実行します。

mvn package

ビルド成功すると target/devisualy_udf.jar ができるはずなので Hive の作業ディレクトリに配置します。

cp target/devisualy_udf.jar /tmp/cookpad/devisualy_udf.jar

Hive を起動して組み込んでみます。

cd /tmp/cookpad
hive
hive> ADD JAR /tmp/cookpad/devisualy_udf.jar;
hive> CREATE TEMPORARY FUNCTION converter as 'devisualy.Converter';

OK のような表示が出れば成功しています

UDF を使って集計する

上記までで Hive 上で自作の関数を使う準備は整いました。次に実際にクエリを投げてその関数を使ってみます。具体的には以下のようなクエリを Hive のコンソール上で実行します。

select method, converter(method) from nginx_logs limit 1;

クエリ内で同じ method を参照していますが converter という関数の戻り値が method とは異なっているのを確認できます。

これまでの作業でできるようになったこと

上記までの作業で以下のことができるようになりました。

  • 集計対象ファイルを Hive で読み込めるようになった
  • そのファイルに対してクエリを投げられるようになった
  • そのクエリから自作の関数を呼べるるようになった

その中でも自作の関数を呼べるようになったのは強力です。クエリだけではなかなか表現しきれないビジネスロジックを表現できます。また UDF ファイルを共有することにより他人がその表現を簡単に流用することができます。

まとめ

Hive の基本的な使い方について説明しました。前提にも書きましたが、私が所属しているマーケティングプロダクト開発部では広告配信も行っているため、大量のアクセスログを蓄積しています。そのログに対してローカルで Hive を使うということは無く Amazon EMR を使って高速にログを集計しています。

AWS には、似たようなことが簡単に可能な Amazon Athena というサービスもあります。しかし、集計対象のデータが大きいと料金が高くなるため Amazon EMR を使ったほうが良い場合もあるかと思います。

これらの技術により、大量のデータを高速にかつ簡単に集計できるようになりました。次はその集計結果をどのように活用できるかです。いつかログからユーザーを想像できるようになれればいいなと思っています。

Cookpad Ruby Hack Challenge

f:id:koichi-sasada:20170629153022p:plain

技術部の笹田です。Ruby インタープリタの開発をしています。最近は Fiber まわりを10年ぶりにいじってます。

2017/08/30, 31 に、Cookpad Ruby Hack Challenge というイベントを行いますので、その宣伝をさせてください。

Cookpad Ruby Hack Challenge とは

クックパッドで Ruby インタプリタを Hack しよう!

クックパッドをはじめ、多くのウェブアプリケーション開発でプログラミング言語 Ruby が利用されています。Ruby で書かれたプログラムを動かすときは Ruby インタプリタで実行します。

Cookpad Ruby Hack Challenge は、この Ruby インタプリタに対して機能を追加したり、改良したり、性能向上させたりする方法、つまり Ruby インタプリタを Hack する方法を、二日間かけてお伝えするイベントです。

イベント概要

二日間かけて、Ruby インタプリタをハックします。一日目は共通課題として、用意する資料を手順どおりに進めて頂きます。二日目は発展課題として、Ruby インタプリタに残る未解決問題に取り組んで頂きます。両日とも、講師は Ruby コミッタの笹田が務めます。

また、二日目には特別企画として、クックパッド以外の Ruby 開発者とも交流できる場を用意したいと思っています。Ruby という言語や、Ruby インタプリタに対する疑問や意見がある人は、この機会にぜひ議論してもらえればと思います。

学生の方には、ぜひ夏休みのアクティビティの一つとして楽しんで貰えると幸いです。

なお、本イベントは、以前ご紹介した社内イベント Hackarade: MRI Internal Challenge を、よりわかりやすくブラッシュアップしたものになります。

こんな方に来てほしい

  • Ruby インタプリタの Hack がしてみたい方
  • Ruby プログラムは書けるけど、どうやって動いているのか知りたい方
  • プログラミング言語 Ruby および Ruby インタプリタを普段開発しているような人達が、何を考えているのか知りたい方
  • 難易度の高いプログラミングに挑戦してみたい方
  • 夏休みの思い出が欲しい方

共通課題(1日目)のゴール

  • Ruby のソースコードの構造を知る
  • Ruby のビルドができるようになる
  • Ruby の中身を弄ることができるようになる

発展課題(2日目)のゴール(できれば)

  • 未解決問題を解決する
  • 実際に Ruby インタプリタへの貢献を体験する
  • 開発コミュニティへの参加を体験する

スケジュール

注意:時間等は変わる可能性があります。

開催前

  • 7/27 (木) 募集締め切り
  • 7/29 (土) 参加者抽選決定
  • Gitter を用いたオンライン予習サポート(希望者)

8/30 (水) 一日目

  • 10:00 オープニング
  • 10:30 ハックに必要となる事前知識の講義
  • 12:00 ランチ
  • 13:00 共通課題
  • 16:00 発展課題の紹介と割り振り

8/31 (木) 二日目

  • 10:00 発展課題の開始
  • 11:30 まつもとゆきひろ氏 特別講演
  • 12:00 Ruby開発者を交えてのランチ
  • 13:00 Ruby開発者との Q&A セッション
  • 14:00 発展課題の再開
  • 18:00 打ち上げパーティー

なんでクックパッドで開催するの?

前節までは、募集ページそのままの内容でした。これだけではなんなので、本イベントを開催する動機について、少し触れておきます。

いくつかあるのですが、まずは IT エンジニアコミュニティへの還元です。クックパッドは「毎日の料理を楽しみにする」という目標のために、多くの IT 技術を活用しています。我々は OSS としてプロダクトを公開したり、この開発者ブログでの情報発信をすることで、エンジニアコミュニティへの還元を行っていますが、本イベントはその一環です。おそらく、本イベントに興味を持つ方は、向上心があり、これからのエンジニアコミュニティを牽引して下さる、かもしれない、方々だと思うので、そのような方々へ支援することは大事なことだと思っています。

笹田個人の動機としては、このようなイベントをきっかけに言語処理系といったシステムソフトウェア開発に興味を持つ人が少しでも増えてくれたり、優秀な Ruby コミッタが増えてくれると嬉しいです(Ruby にはまだまだ改良の余地がありますが、人手が足りていません)。最近、システムソフトウェアといったコンピュータの「裏方」に興味を持ってくれる人が少なくなっているような気がします。いろいろな理由があるかと思いますが、一つは難しそう、といった「とっつきづらさ」があるのではないかと思います。本イベントを通して、そのようなハードルを越えるお手伝いができればと思っています。

このような思いを実現するためには、長期的に継続して活動を行っていく必要があると考えており、本イベントはその第一歩です。うまくいけば、第二弾や、別テーマでの開催も検討できるのではないかと思っています。そもそも、クックパッド1社でやってもスケールしないので、もっと広げたいと思っており、夢(だけ)は広がります。というわけで、まずは本イベントがうまくいくといいなぁ。

おわりに

というわけで、Cookpad Ruby Hack Challenge のご紹介でした。 ご興味とお時間がある方は、ぜひご応募ください。

/* */ @import "/css/theme/report/report.css"; /* */ /* */ body{ background-image: url('http://cdn-ak.f.st-hatena.com/images/fotolife/c/cookpadtech/20140527/20140527163350.png'); background-repeat: repeat-x; background-color:transparent; background-attachment: scroll; background-position: left top;} /* */ body{ border-top: 3px solid orange; color: #3c3c3c; font-family: 'Helvetica Neue', Helvetica, 'ヒラギノ角ゴ Pro W3', 'Hiragino Kaku Gothic Pro', Meiryo, Osaka, 'MS Pゴシック', sans-serif; line-height: 1.8; font-size: 16px; } a { text-decoration: underline; color: #693e1c; } a:hover { color: #80400e; text-decoration: underline; } .entry-title a{ color: rgb(176, 108, 28); cursor: auto; display: inline; font-family: 'Helvetica Neue', Helvetica, 'ヒラギノ角ゴ Pro W3', 'Hiragino Kaku Gothic Pro', Meiryo, Osaka, 'MS Pゴシック', sans-serif; font-size: 30px; font-weight: bold; height: auto; line-height: 40.5px; text-decoration: underline solid rgb(176, 108, 28); width: auto; line-height: 1.35; } .date a { color: #9b8b6c; font-size: 14px; text-decoration: none; font-weight: normal; } .urllist-title-link { font-size: 14px; } /* Recent Entries */ .recent-entries a{ color: #693e1c; } .recent-entries a:visited { color: #4d2200; text-decoration: none; } .hatena-module-recent-entries li { padding-bottom: 8px; border-bottom-width: 0px; } /*Widget*/ .hatena-module-body li { list-style-type: circle; } .hatena-module-body a{ text-decoration: none; } .hatena-module-body a:hover{ text-decoration: underline; } /* Widget name */ .hatena-module-title, .hatena-module-title a{ color: #b06c1c; margin-top: 20px; margin-bottom: 7px; } /* work frame*/ #container { width: 970px; text-align: center; margin: 0 auto; background: transparent; padding: 0 30px; } #wrapper { float: left; overflow: hidden; width: 660px; } #box2 { width: 240px; float: right; font-size: 14px; word-wrap: break-word; } /*#blog-title-inner{*/ /*margin-top: 3px;*/ /*height: 125px;*/ /*background-position: left 0px;*/ /*}*/ /*.header-image-only #blog-title-inner {*/ /*background-repeat: no-repeat;*/ /*position: relative;*/ /*height: 200px;*/ /*display: none;*/ /*}*/ /*#blog-title {*/ /*margin-top: 3px;*/ /*height: 125px;*/ /*background-image: url('http://cdn-ak.f.st-hatena.com/images/fotolife/c/cookpadtech/20140527/20140527172848.png');*/ /*background-repeat: no-repeat;*/ /*background-position: left 0px;*/ /*}*/