laravelからslack通知
重要な概念
slack通知には以下2種類ある
- webhook url通知
- slack bot通知
ここではwebhook urlのみ取り上げる。
ドキュメントやらライブラリーの刷新などによりインターネットの海から拾ってきた情報をそのまま適用すると以外と動かないのがslack通知だ。ドキュメントの鮮度が古いのはあんま使われてないのからかもだけど、ちゃんとやると便利とは思うんですがね。
通知先channel作る
ここではaws-cost
とした。今awsのコスト通知アプリを作っていたからだけど、まあここはお好きに。
appを作る
https://api.slack.com/apps より適当に作る
incoming webhook作る
この辺から
このように複数のチャンネル通知用urlを1つのappから作成することもできる
curlでテストする
curl -X POST \
-H 'Content-type: application/json' \
--data '{"text":":tada: Slackへの通知テスト成功! from curl"}' \
https://hooks.slack.com/services/your/incoming/hook
ここまでがlaravel関係ない事前準備となる
laravelから使う
ライブラリー入れる
composer require laravel/slack-notification-channel
バージョン2とバージョン3で結構違う。ここではlaravel12の環境なのでバージョン3が入る。一度確認しておくこと
composer show laravel/slack-notification-channel
name : laravel/slack-notification-channel
descrip. : Slack Notification Channel for laravel.
keywords : laravel, notifications, slack
versions : * v3.5.0
...
ここではv3.5.0
が入ったのがわかる
notificationで使う
ここではlaravelの「通知」機能を使いコマンドからこの通知を呼び出す事でslackに送信する
コマンド → slack通知レイヤー → 実際にslackに通知
notificationを作成する
これはslack通知レイヤーであるわけだが、SlackNotify
という名前で作成する。
php artisan make:notification SlackNotify
すると app/Notifications/SlackNotify.phpができる
<?php
namespace App\Notifications;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Notifications\Messages\MailMessage;
use Illuminate\Notifications\Notification;
class SlackNotify extends Notification
{
use Queueable;
/**
* Create a new notification instance.
*/
public function __construct()
{
//
}
/**
* Get the notification's delivery channels.
*
* @return array<int, string>
*/
public function via(object $notifiable): array
{
return ['mail'];
}
/**
* Get the mail representation of the notification.
*/
public function toMail(object $notifiable): MailMessage
{
return (new MailMessage)
->line('The introduction to the notification.')
->action('Notification Action', url('/'))
->line('Thank you for using our application!');
}
/**
* Get the array representation of the notification.
*
* @return array<string, mixed>
*/
public function toArray(object $notifiable): array
{
return [
//
];
}
}
このように基本的にmailベースのテンプレートが出力されるので、これを変更していく、のだが、
まずvia()
をみてみよう
public function via(object $notifiable): array
{
// return ['slack'];
return [SlackWebhookChannel::class];
}
webを検索するとおそらく大多数のドキュメントがslack
をreturnしているはずだが、これを使うとslack bot(Block Kit)の方になっちゃうんだよな。つまり単純にwebhook urlを使いたいだけの場合これじゃ動かんからね。
+use Illuminate\Notifications\Channels\SlackWebhookChannel;
+
class SlackNotify extends Notification
{
@@ -14,10 +19,9 @@ class SlackNotify extends Notification
/**
* Create a new notification instance.
*/
- public function __construct()
- {
- //
- }
+ public function __construct(
+ protected string $message
+ ) {}
/**
* Get the notification's delivery channels.
@@ -26,7 +30,21 @@ public function __construct()
*/
public function via(object $notifiable): array
{
- return ['mail'];
+ // return ['slack'];
+ return [SlackWebhookChannel::class];
+ }
こんな風にSlackWebhookChannel
を指定してほいほい書き換えていく。なおコンストラーで通知メッセージを受けとれるようにしてる(php8のコンストラクタープロモーションで書いとる)
toSlack()を書く
そしたらtoMail()
と同じようにtoSlack()
を書いていく。
public function toSlack($notifiable)
{
return (new SlackMessage)
->content($this->message);
}
WebHookの場合channelを選びようがないので、基本的にcontent()
で送信するだけ、なんだけど、このSlackMessage
に関しては
// use Illuminate\Notifications\Slack\SlackMessage;
use Illuminate\Notifications\Messages\SlackMessage;
こっちを呼びこむ。コメントされているSlack/SlackMessage
は Block Kit API 対応の新しいクラス。Slack Bot + OAuth トークンで chat.postMessage API を使うため、これを使わないように!
Notification呼び出しコマンドを作る
make:command
で作ったコマンドから送ってみよう。
php artisan make:command SlackTestCommand
するとapp/Console/Commands/SlackTestCommand.phpが出来る。これはslack通知レイヤーを呼びだすためのコマンドと思ってもらえばok
ここでは全文記述する
<?php
namespace App\Console\Commands;
use Illuminate\Console\Command;
use Illuminate\Support\Facades\Notification;
use App\Notifications\SlackNotify;
class SlackTestCommand extends Command
{
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'app:slack-test-command';
/**
* The console command description.
*
* @var string
*/
protected $description = 'Command description';
/**
* Execute the console command.
*/
public function handle()
{
Notification::route('slack', 'https://hooks.slack.com/services/your/incoming/hook')
->notify(new SlackNotify('🚀 Slackへ通知が飛びました!'));
logger('Slack通知を送信しました!');
}
}
ここではslack webhook urlをベタに書いており非常に取り回しが悪いが、テストスクリプトならまあこんなもんでokだろう。
ログをslackに転送
.envを
LOG_CHANNEL=stack
LOG_STACK=single,slack
LOG_DEPRECATIONS_CHANNEL=null
LOG_LEVEL=debug
LOG_SLACK_WEBHOOK_URL=https://hooks.slack.com/services/your/debug/incoming/hook
LOG_SLACK_USERNAME="Laravel Log"
LOG_SLACK_EMOJI=":rotating_light:"
とかにする。hookのurlは通知のやつと分けてもいいし分けなくてもいいけど、webhookを使うと特定のchannelにしか送信できない。slackbotに関しては何も触れていないが、ここではbotは使う事は多分できないんじゃないかな
こんな感じでexceptionが飛んでくる。
productionで動かしているアプリケーションは言うまでもなく必ずこの手のエラーは拾わないといけない。ログに書きっぱなしは最悪ですからね。
実際の運用に関して
基本的にはシステム通知で使うものだろうと思う。もちろんユーザーごとにslack_hook_urlとかをDBののカラム作って収めてユーザーごとにそれぞれ通知とかやってもいいんだけど、基本的にはアプリからシステムへ通知するためのものだろう。従来はemailを使わざるを得なかったが、emailは今日日結構面倒くさいじゃないですか、SESとか経由するとかなるとさらに面倒くさい。なのでslackで通知しちゃった方がいいんじゃないですかね
上記で言及したような割と深刻なエラーを即座につかまえたいとなるとやはりslackの方が使い勝手がいいような気もします。ただ、量が多いとだるいけど、まあそれはメールにしてもそうなわけで。。。
Discussion