本記事はSlack Advent Calendar 2017の1日目の記事です。

概要

Kibanaを用いてSlackの過去ログから統計情報の可視化と全文検索を行う方法を紹介します。
Slackの過去ログをELKのような全文検索エンジンに入れることで、以下のメリットが得られます。

  1. Slackの提供していない統計情報の可視化
  2. 無料版Slackのメッセージ数制限を超えて全ての過去ログから全文検索

本記事では、簡単のためDockerでELKスタックを立ち上げ、自作したスクリプトでSlackの過去ログを流し込み、Kibanaから可視化と全文検索を行う方法を解説します。

Slackの過去ログのexport

過去ログのexportは、workspaceのadminのみが行えます

Slackの過去ログは https://my.slack.com/services/export からzip形式でダウンロードできます。無料版でもメッセージ数の制限なく全てのメッセージがダウンロードできますが、プライベートチャンネルやDMは含まれていません。

複数のworkspaceに所属していて、上記URLでは目的のworkspaceのページにリダイレクトされなかった場合には "my." の部分を目的のworkspaceのサブドメインに変える必要があります。

ELKスタックを立てる

ELKスタックは全部入りのDocker Composeもあり、これを用いればコマンド一発で立ち上げることができます。Dockerで立てた場合、通常の方法で立てた場合よりもパフォーマンスや拡張性、安定性において劣るものの、今回はワンタイムの用途なので立ち上げと処分の手軽さのためDockerを使う方法を紹介します。今回は docker-elk を用いる方法を解説します。

docker-elk

基本設定

docker-elkのリポジトリをGitHubからcloneしてきます。

$ git clone https://github.com/deviantony/docker-elk

設定を少し変更します。デフォルトのヒープサイズは少ないのでこれを増やし、Logstashは今回不要なのでその部分を消します。

docker-compose.yml
diff --git a/docker-compose.yml b/docker-compose.yml
index c923261..21beb31 100644
--- a/docker-compose.yml
+++ b/docker-compose.yml
@@ -13,27 +13,10 @@ services:
       - "9200:9200"
       - "9300:9300"
     environment:
-      ES_JAVA_OPTS: "-Xmx256m -Xms256m"
+      ES_JAVA_OPTS: "-Xmx4g -Xms4g"
     networks:
       - elk

-  logstash:
-    build:
-      context: logstash/
-      args:
-        ELK_VERSION: $ELK_VERSION
-    volumes:
-      - ./logstash/config/logstash.yml:/usr/share/logstash/config/logstash.yml
-      - ./logstash/pipeline:/usr/share/logstash/pipeline
-    ports:
-      - "5000:5000"
-    environment:
-      LS_JAVA_OPTS: "-Xmx256m -Xms256m"
-    networks:
-      - elk
-    depends_on:
-      - elasticsearch
-
   kibana:
     build:
       context: kibana/

kuromoji analysis pluginを入れる

Elasticsearchの日本語形態素解析プラグインであるkuromojiを入れます。これは、後述する日本語の全文検索やタグクラウドを作る上で役に立ちますが、統計情報を可視化したいだけであれば入れる必要はないので、飛ばしても問題ありません。

ElasticsearchのDockerfileに以下の一行を加えます。

elasticsearch/Dockerfile
diff --git a/elasticsearch/Dockerfile b/elasticsearch/Dockerfile
index f2f4f56..b08bc18 100644
--- a/elasticsearch/Dockerfile
+++ b/elasticsearch/Dockerfile
@@ -5,3 +5,5 @@ FROM docker.elastic.co/elasticsearch/elasticsearch-oss:${ELK_VERSION}

 # Add your elasticsearch plugins setup here
 # Example: RUN elasticsearch-plugin install analysis-icu
+
+RUN elasticsearch-plugin install analysis-kuromoji

最後に docker-elk を立ち上げます。

$ docker-compose up

以下のコマンドでhealth checkをして、statusがredになっていたりしなければ大丈夫です。

$ curl 'localhost:9200/_cat/health?v'
epoch      timestamp cluster        status node.total node.data shards pri relo init unassign pending_tasks max_task_wait_time active_shards_percent
1511987763 20:36:03  docker-cluster yellow          1         1      1   1    0    0        1             0                  -                 50.0%

ログをElasticsearchに流し込む

ExportしたSlackの過去ログzipの中身は、チャンネルごとにディレクトリに分けられたjsonファイル群です。これを一つ一つパースし、少し加工してElasticsearchにbulk indexしていくスクリプト
(https://github.com/shinkbr/slack-export-shipper) を書きました。これを使って流し込んでいきます。

$ git clone https://github.com/shinkbr/slack-export-shipper.git
$ cd slack-export-shipper
$ bundle install

kuromoji用のmappingを設定する

kuromojiを使わない場合、この手順は不要です。
kuromojiで形態素解析を行う場合、最初のindexを作る前に解析対象のフィールドに対するmappingを設定する必要があります。先程cloneしたリポジトリに同梱の、以下のjsonファイルをPUTすることでmappingを設定します。

template/slack.json
{
  "template": "slack-*",
  "settings":{
    "index": {
      "analysis":{
        "analyzer":{
          "kuromoji":{
            "type":"custom",
            "tokenizer":"kuromoji_tokenizer",
            "char_filter": [
              "url_filter",
              "mention_filter"
            ],
            "filter":[
              "ja_stop",
              "kuromoji_baseform",
              "pos_filter"
            ]
          }
        },
        "filter": {
          "pos_filter": {
            "type": "kuromoji_part_of_speech",
            "stoptags": [
              "助詞-並立助詞",
              "助詞-係助詞",
              "助詞-副助詞/並立助詞/終助詞",
              "助詞-副詞化",
              "助詞-接続助詞",
              "助詞-格助詞",
              "助詞-格助詞",
              "助詞-格助詞-一般",
              "助詞-格助詞-引用",
              "助詞-格助詞-連語",
              "助詞-終助詞",
              "助詞-連体化",
              "助詞-間投助詞",
              "助動詞",
              "動詞-接尾",
              "動詞-非自立",
              "接続詞"
            ]
          }
        },
        "char_filter": {
          "url_filter": {
            "type": "pattern_replace",
            "pattern": "<http[^>]+>",
            "replacement": ""
          },
          "mention_filter": {
            "type": "pattern_replace",
            "pattern": "<@[a-zA-Z0-9]+>",
            "replacement": ""
          }
        }
      }
    }
  },
  "mappings": {
    "slack-message": {
      "dynamic_templates":[
        {
          "texts": {
            "match_mapping_type": "string",
            "match": "text",
            "mapping": {
              "type": "text",
              "analyzer": "kuromoji",
              "fielddata": true
            }
          }
        }
      ]
    }
  }
}
  • stoptags の部分は(多分)アグレッシブに品詞をstripしていますが、調整の余地があると思います。
  • kuromoji_baseform を使うことで、文章中の活用された単語を基本形で検索できるようになります。 (「行く」で「行った」を検索するなど)
  • url_filtermention_filter はメッセージ中の <http://...><@U12345678> のようなURLとメンションを集計と検索から除くもので、後に記述するタグクラウドの見栄えを意識して入れたものですが、filterしない方が検索の上では望ましいかもしれません。

先程cloneしたslack-export-shipperのルートディレクトリにて以下のコマンドを実行し、上記ファイルをPUTします。

$ curl -X PUT 'localhost:9200/_template/slack' -H 'Content-Type:application/json' -d @template/slack.json

{"acknowledged":true} というレスポンスが返って来ればOKです。

流し込む

最初にダウンロードしたログzipを適当なディレクトリにunzipします。

$ unzip -d /path/to/unzip your_slack_log.zip

先程cloneしたslack-export-shipperというリポジトリのルートディレクトリにて以下を実行します。 /path/to/unzip は先程unzipしたディレクトリです。

$ bundle exec rake ship logdir=/path/to/unzip

これを行うと、Elasticsearchに slack-YYYY.MM.DD という命名規則のindexが作成されます。
ログのメッセージ数やホストのスペック次第ですが、これには数十分から数時間かかる可能性があります。

何もエラー無くrakeタスクの実行が終われば、あとはブラウザからKibanaをポチポチするだけです。

Kibanaで検索・可視化を行う

※以下に示す画像では、チャンネル名およびユーザー名はランダムな地名や人物名に変更してあります

ブラウザで http://localhost:5601 にアクセスして、Kibanaを触っていきます。

Index patternの設定

初回アクセス時に "Configure an index pattern" と聞かれたら Index patternに
slack-* , Time filter field nameに @timestamp を指定します。

検索

Kuromojiをインストールしていれば、日本語が綺麗に形態素に分割されて検索されます。また、本記事の設定だと、 kuromoji_baseform フィルタにより活用形の単語も基本形で検索してヒットするようになっています。

search.png

可視化

Kibanaでは様々な方法で可視化が行えます。例えば、以下は一人のユーザーのチャンネルごとの投稿数の棒グラフ / 時系列グラフ、時間毎 / 曜日ごとの投稿数の積み上げ棒グラフ、チャンネルごとの投稿の割合の円グラフです。

per_user.png

もちろん、一人のユーザーではなくworkspace全体の統計情報もグラフ化することができます。

all_channels.png

また、kuromojiを設定していれば以下のように比較的綺麗なタグクラウドを作ることができます。
以下の例は、「示し合わせて東京都内でご飯を食べよう」という主旨のチャンネルから作られたタグクラウドです。

tokyo.png

まとめ

ELKスタックはセットアップからデータのindex、可視化までが簡単に行えます。今回はDockerを使用する方法を紹介しましたが、Elasticの公式リポジトリをパッケージマネージャに追加してインストールするのも同じぐらいに簡単です。もしもSlackの過去ログなどの手頃なデータがあれば、一度遊んでみてはいかがでしょうか。