情シス向けの問い合わせ用 Slack チャンネルがすごい勢いで流れていきます。(とりあえず聞いてみよう、が多いです。)対策の一環として自動応答するチャットボットを作成中で、ボットで返せそうな定型的な問い合わせを確認しようと当該チャンネルのメッセージ履歴をエクスポートしてみました。が、データが JSON 形式で見づらかったので、 CSV 形式に変換するツールを作成しました。
- 作成したツール
- Slack のエクスポートデータの構造
- 取得対象のデータ
- Go で JSON をパースする
- Go のクロスコンパイル
- Windows での time.LoadLication 実行エラーへの対応
- まとめ
作成したツール
要件
作成にあたっての要件は以下の通りです。
- Slack からエクスポートしたメッセージ履歴を、 JSON 形式から CSV 形式に変換してファイルに出力する
- 必要最低限の情報のみ出力する
- 対象はメッセージのみとする(添付ファイル等は対象外)
- スレッド内でのやりとりは、どのメッセージ(どの問い合わせ)に対するものなのか識別できるようにする
- メッセージの投稿者の名前を表示する
- メッセージ内のメンション相手(ユーザ名)を表示する
- 社内の誰もがサクッと使えるようにしたい
「同じ事をしたい!」と別チームからも声があがったため、利用する PC の環境に左右されないよう Go でツールを作成しました。
使い方
Slackのエクスポート機能 でデータをエクスポートし、目的のチャンネル名のディレクトリにツールを配置・実行すると、同一ディレクトリ内に CSV ファイルを出力します。詳細は README を参照してください。
作成された CSV ファイルは Google スプレッドシートにインポートして扱っています。
ピボットテーブル機能で整形すると、スレッド単位で集約できて文脈が追いやすくなります。
以下、ツールの作成中に調べたことやハマったことを備忘録として残しておきます。
Slack のエクスポートデータの構造
ワークスペースのデータをエクスポートすると以下のようにデータが出力されます。
<Workspace Name> Slack export <term> ├ user.josn ├ channels.json ├ integration_logs.json ├ channel-01 │ ├ yyyy-mm-dd.json │ └ yyyy-mm-dd.json └ channel-02 └ yyyy-mm-dd.json ※ フリー / スタンダードプランの場合
Slack をプラスプラン以上で契約していると、 DM や プライベートチャンネル内のメッセージも取得できるようです。
本ツールではメッセージ履歴である yyyy-mm-dd.json
とユーザ情報の user.js
をインプットとして扱います。
各種ファイルについて丁寧に説明されている記事がありますので、紹介させていただきます。
取得対象のデータ
各ファイルから取得するデータは以下のとおりです。
yyyy-mm-dd.json
ts
: タイムスタンプ( UnixTime )thread_ts
: スレッドの ID に相当( 親スレッドのts
の値)user
: メッセージを投稿したユーザの IDtext
: 投稿したメッセージ
user.json
id
: ユーザ IDprofile.real_name
: ユーザ名(詳細は後述)profile.display_name
: ユーザ名(詳細は後述)
ts
、 thread_ts
、 profile.real_name
、profile.display_name
について補足します。
ts
メッセージの投稿時刻のタイムスタンプです。 UnixTime で表現されているので、わかりやすいよう JST に変換して CSV ファイルに出力します。
thred_ts
メッセージがスレッド形式となった場合に生成されます。
親メッセージの ts
の値がスレッド内の全メッセージの thred_ts
に割り当てられるため、どのスレッドに投稿されたメッセージであるかを識別することができます。
{ "messages": [ { "type": "message", "user": "U061F7AUR", "text": "island", "thread_ts": "1482960137.003543", "reply_count": 3, "subscribed": true, "last_read": "1484678597.521003", "unread_count": 0, "ts": "1482960137.003543" }, { "type": "message", "user": "U061F7AUR", "text": "one island", "thread_ts": "1482960137.003543", "parent_user_id": "U061F7AUR", "ts": "1483037603.017503" }, { "type": "message", "user": "U061F7AUR", "text": "two island", "thread_ts": "1482960137.003543", "parent_user_id": "U061F7AUR", "ts": "1483051909.018632" }, ...
conversations.replies method | Slack
Slack の公式ヘルプでも、thread_ts
をスレッド ID と表現しています。
If you’re replying to a threaded message, you’ll pass the thread_ts ID of the message you’re replying to.
Basic Usage — Slack Developer Kit for Python
ユーザ名に関する情報
yyyy-mm-dd.json
内ではユーザメンションが <@user_id>
と表現されるため、 user.json
を使って ID からユーザ名への変換処理を行います。
ユーザ名に関するキーが複数あって何を採用すべきか悩みましたが、「 realname
/ display_name
」という形式に変換することにしました。
キー | 値 |
---|---|
name |
アカウント登録時のメールアドレスから、ドメイン部分を除外した文字列 |
real_name |
プロフィールの [氏名] 欄に登録した文字列( Unicode ) |
profile.real_name |
real_name と同一 |
profile.display_name |
real_name と同一だが、非ラテン文字は除外される |
profile.real_name_normalized |
プロフィールの [表示] 欄に登録した文字列( Unicode ) |
profile.display_name_normalize |
profile.display_name と同一だが、非ラテン文字は除外される |
profile.first_name |
real_name 内のファーストネーム(スペースがデリミタ) |
profile.last_name |
real_name 内のファミリーネーム(スペースがデリミタ) |
※ ~_normalize
は非ラテン文字(アルファベット)以外は除外されると公式 に説明がありますが、手元の環境で試してみるとひらがな・カタカナ・漢字も除外されずに出力されました。(カタカナは半角表示になりました。)
Go で JSON をパースする
JSON 形式のデータ取り込む場合、 Go では構造体を定義してパースします。 JSON のキーにマッチするよう構造体のフィールドを定義します。
JSON 形式のデータをペーストすると、 Go の構造体に変換してくれるツールです。
※業務の本番データ等、機密性の高いデータを使わないようご注意ください。
users.json
の中身をペーストしてみました。
取り込むデータに含まれる全ての JSON のキーを定義する必要はないため、ツール内では扱いたい対象のみを定義しています。
type User struct { ID string `json:"id"` Profile struct { RealName string `json:"real_name"` DisplayName string `json:"display_name"` } `json:"profile"` }
Go のクロスコンパイル
go build
コマンドでプログラム実行に必要なライブラリを含める形でコンパイルし、実行ファイルを生成します。
その際に環境変数の値を変更することで、 Mac 上で Windows 用の実行ファイルにビルドすることができます。具体的にには GOOS
( OS の種類)と GOARCH
(アーキテクトの種類) を使います。
今回は make
コマンドでビルドしており、 Makefile
で以下のように環境変数の値を変更して x86 ベース ( 64bit )アーキテクチャの Widows および macOSで動作する実行ファイルを用意しました。
# Makefile build: # macOS GOOS=darwin GOARCH=amd64 go build -o ./bin/darwin64/parseSlackMessage ./main.go # Windows GOOS=windows GOARCH=amd64 go build -o ./bin/windows64/parseSlackMessage.exe ./main.go
GOOS
、 GOARCH
に関する情報はこちらで確認できます。
Windows での time.LoadLication
実行エラーへの対応
ts
の値を Unixtime から JST へ変換するために time.LoadLocation
関数を使ったのですが、 Windows 環境での実行時にエラーとなりました。
# loc, err := time.LoadLocation("Asia/Tokyo") Error:The system cannot find the path specified.
Github で Issue がたっていますが、処理中に参照する $GOROOT/lib/time/zoneinfo.zip
が( Go をインストールしていない) Windows 環境には存在しないことによるエラーでした。
Go をインストールすることで実行可能(ファイルが配置される)となるようですが、利用者にその手間を強いるのではなく、外部パッケージをインポートして対応する方が良さそうです。
zoneinfo.zip is a mere 366776 bytes, a small number amongst friends. I think of a typical go binary as a 10MB +/- 5MB affair, and I would happily increase that by 366KB (3% of the mean, but small compared to the standard deviation) to have my binaries be portable to windows.
こちらの記事でも紹介されていた tz
パッケージをインストールすることで解決しました。
import ( ... "4d63.com/tz" ) ... # loc, err := time.LoadLocation("Asia/Tokyo") loc, err := tz.LoadLocation("Asia/Tokyo")
まとめ
- Slack のエクスポートデータ(チャンネル内のメッセージ履歴)を、 JSON 形式から CSV 形式に変換するツールをつくった
- Go を使うことで、実行環境の構築が不要でマルチプラットフォーム( Windows , macOS )で動作するようにできた
Go といえばテストですが、テストコードを書かずに作ってしまったので、後追いでテストコードも整備したいと思います。