GAS で Slack bot 作ってみた

こんにちは、サイオステクノロジーの馬場です。

私の携わっているプロジェクトでは、 Slack にエラーログを流しています。

もし、ヤバめのエラーログが流れてきても、
誰かが「あぁ、またあの問題だ。落ち着け」とサポートしてくれたら、心強いですよね。
残念ながら、私には、そんな誰かは見当たりませんでした。

この記事では、そんな私がとった行動を時系列で晒しつつ、最後に、成果物も晒します。

「あるある」的な共感を得られれば幸いです。

時系列

アイディア

ヤバめのエラーログが流れてきたら、
(ヤバいと分かっているということは、既知の問題であって、その対処法も決まってるんだろうから)
その対処法を発言してくれるボット がいれば良い、

…というアイディアです。

標準の Slackbot を試す

まず、標準の Slackbot ( slack.com/customize/slackbot ) を活用するつもりでした。

slack-custom-response

Slackbot なら誰でもメンテナンスできるし、ナイスアイディア!

…と思ったんですが、
テスト発言 (自分のアカウントでの発言) には上手く反応するのに、
エラーログ (ボット/アプリで流している) には、なぜか反応しませんでした。

原因として、以下を考えました:

  • A. そもそも、 Slackbot は他のボットには反応しない?
    • 代わりのボットを自作すればイケるかもしれない。
  • B. エラーの詳細が attachments に入ってるから?
    • attachments じゃなくて text に入れればイケるかもしれない。

エラーを attachments じゃなくて text に入れる

エラーログは Elasticsearch から流しています。

Elasticsearch を担当しているメンバーは、 dynamic_attachments という仕組みを活用して、
何行かのエラーログを attachments としてキレイにまとめてくれていました。

https://www.elastic.co/guide/en/elastic-stack-overview/current/actions-slack.html#formatting-slack-messages

彼に事情を説明したら、エラーを本文 ( text ) に入れるように変更してくれました。

しかし、結果として、これだけでは Slackbot が反応するようには、なりませんでした

ということは、

  • A. そもそも、 Slackbot は他のボットには反応しない?

…ってことですよね。

えー、せっかく変更してもらったのに…
Slackbot の代わりのボットを自作すればイケるかもしれないけど、環境とか面倒そう (知らんけど) …

Slack のボットの作り方をググる

ググりました。
そして、なんと、GAS (Google Apps Script) でもイケるらしいことを知ります。

  • スタンドアロンの GAS
  • コンテナ (スプレッドシートなど) に紐付いた GAS

があるようですが、今回は Slackbot のキーワード⇔レスポンスみたいな対応表が必要なので、
スプレッドシートに紐付いた GAS を書くことになるかな…と方向性が見え始めました。

Incoming Webhook を理解する

Slack の親切なガイドにしたがって、 Incoming Webhook を作って curl で試しましたが、

うっかり、コピペしたままで試したので #general に投稿されてしまいました。

slack-shame

しかも、Slack 上で普通には消せないんですよね。
試行錯誤中は IncomingWH を #sandbox というチャンネルに流すことにしました。

GAS から発言してみる

GAS を書き始めました。
ググって出てきたサンプルとかを参考にしたら簡単に発言できたので、
「よしよし!」と喜びました。

Outgoing Webhook を理解する

「Incoming / Outgoing は、 Slack からみた方向性なんだな、へー」
「”引き金となる言葉” は “いずれかで始まる行がある場合に” なんだ、へー」

「そして Outgoing の URL に GAS の URL を指定すれば良いっポイ。なるほど!」
と鼻息荒く、さきほどの GAS を開きました。

OutgoingWH → GAS → IncomingWH でエコーしてみる

GAS に OutgoingWH を受ける機能を書きました。

OutgoingWH を受けるには、 GAS をウェブアプリとして公開すれば良いことを知りました。
GAS を更新する度に、プロジェクトバージョンを上げる必要があることを知りました。

ググって出てきたサンプルとかを参考にしたら、
とりあえず #sandbox から #sandbox へ、エコーさせることに成功しました。

しかし、ボットが自分の発言にも応答するので、エコーが無限ループしました。

slack-shame2

うすうす予想してたことではありますが、慌てて Outgoing の URL を空っぽにしたりしながら、
Slackbot が他のボットに応答しないのは、この手の問題を回避するためだろう、と確信しました。

かつ、このボットはボット(自分)の発言に応答しているので、ということは、

  • A. そもそも、 Slackbot は他のボットには反応しない?

の Slackbot の代替として、このボットが機能すると確信しました。

なお、Outgoing から受け取れるデータに attachments は入っていなかったので、
2. エラーの詳細を attachments じゃなくて text に入れる」も無駄ではありませんでした。

つまり、

  • A. そもそも、 Slackbot は他のボットには反応しない?
  • B. エラーの詳細が attachments に入ってるから?

の複合要因だった、というわけです。

作り込む

まず、無限ループすると恥ずかしいので、エコーしないようにしました。

次に、 console.log すれば、
Apps Script ダッシュボード https://script.google.com/home に出力されることを知りました。

そこで、 DEBUG == true ならば、適所で console.log したり、
Outgoing で受け取ったボットの発言の JSON を Incoming するようにしました。

で、メインの処理
Outgoing から受け取った内容にキーワードがあったら、対応するレスポンスを Incoming へ投げる
を実装しました。

その際、スプレッドシートから読み込んだデータの扱いがかったるいので、
GAS のライブラリという仕組みで underscore.js を使うようにしました。

あとは、微調整 (スプレッドシート上 # で始まる行、空行を無視するなど) をして、
いよいよ、実際のエラーログをみるように Outgoing のチャンネルを変更しました。

ただし Incoming のチャンネルは #sandbox のままとし、
DEBUG == true で、しばらく反応の頻度や内容を見ながら、
発言内容や、 Incoming の名前やアイコンなどを、じっくり調整しました。

デビュー

現在、この GAS bot は稼働しています。

本当に重要なキーワードにしか反応しないようにしてあるので、
まだほんの数回しか役に立ってないですが、ちゃんとメンテナンスすれば役に立つはず、と信じています。

成果物

実際に使っている GAS から、プロジェクト固有の ID など除去したものを、閲覧専用で晒します:

https://docs.google.com/spreadsheets/d/1cI9ZsZ_KpIXXMLWcsqGAnncvBIlTk0MqPVrblxiPGK8/edit?usp=sharing

GAS-slack-bot

その気があれば、コピーして試したりできると思います。

次回予告

今回、初投稿でしたが、また、そのうち、
何かやってみた時の行動を時系列で晒しつつ、最後に成果物も晒す というフォーマットで、書こうと思います。
(=「◯◯てみた」シリーズ)

 

ご覧いただきありがとうございます! この投稿はお役に立ちましたか?

役に立った 役に立たなかった

2人がこの投稿は役に立ったと言っています。

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です