ログ専用DiscordBOT作ってみた ~HTTPで簡単発言BOT~
こんにちはRcatです。
最近Pythonでいろいろ作っているのですが、たまにうまく動いてなかったり、通常運転中にちゃんと動いているか気になったりするんですよね…。
様々なアプリを作る中でいちいち一個ずつログを見るのも面倒ですし…。
あ、リアルタイムでチャットアプリに出力すればいいんだ!
というわけでやっていきます。
はじめに
利用規約
情報や作品の活用時は事前に利用規約をご確認ください。
コメントについて
利用規約のガイドラインを確認の上コメントしてください
概要と簡単な説明
さて、今回作るのは外部から入力された文字列をそのまま発言するDiscordのbotです。
タイトルではログ専用と言っていますが、それにかかわらず様々な使い道があると思っています。
動作説明
具体的な動作は次の通りです。
発言したいチャンネルとテキストを添えて、専用のURLにアクセスする
Discord内の指定したチャンネルに指定したテキストが発言される
いたってシンプルです。
こうすることで何ができるのかというと、例えばサーバー上で動いている様々なプログラムに何かあった時のログ出力として、このURLにアクセスするという機能を持たせるとどうでしょうか?
何かあったらリアルタイムでログが通知として飛んでくるという仕組みの構築ができます。
それでは使い方の方を見ていきましょう。
具体的な使い方(GET)
まず、最初に最も簡単なGETを使ったログ出力の方法を説明します。
GETというのは簡単に言ってしまえば普通のアクセスです。
ただし、この時にURLの後ろにパラメーターを指定することができます。
具体的にはURLの最後に"?"を書き、その後キーと値を"="でつなげて書いていきます。
実際の例がこちら。
チャンネルとしてlogtest、ログの内容としてlogを指定しています。
このURLに対してアクセスするとDiscordでは次のような状態になります。

今回製作したbotは指定されたチャンネルがない場合、自動的に作成する機能もついているので、事前準備が楽々です。
指定したlogtestチャンネルが作成され、その中に指定したメッセージである"テストのログです"というメッセージが投稿されています。

ボットを介して何かを操作するというのでなければ、こういったbotを1台作っておくだけで色々できそうですね。
具体的な使い方(POST)
次はポストです。
URLには長さの上限があるため、場合によってはログが長すぎてエラーになってしまう可能性があります。
そのため、100文字を超えるようであればポストにして投稿した方が無難です。
パラメーターはGetの時と同じでJSONボディとして送り付けます。
なお、Discordのメッセージ文字数上限は2000です。これは超えないようにしてください。
Pythonで書くと次のようになります。
import requests
url = "http://localhost:25055/log"
data = {
"channel":"posttest",
"log":"POSTのテストメッセージです"
}
requests.post(url, json=data)こちらを実行すると新しくチャンネルが作成され、ログが投稿されていることが確認できます。

BOTの導入
まず、最初にDiscordのボットを作ってサーバーに導入してください。
出力に必要なチャンネルなどは自動で作成するため、事前に用意する必要はありません。逆にそういった権限がないとエラーになってしまいますのでご注意ください。私の面倒なので管理者で入れました。
ボットアカウントの作り方については、以下の記事で紹介していますので、参考にしてください。
配布しているパッケージの内容は以下の通りです。
初期の作成はWindowsで稼働はLinuxで行っています。

本作は自動環境構築対応です。
OSに合わせて、それぞれに用意したstartのバッチを使って起動してください。自動で環境構築から立ち上がりまでが行われます。
詳しくは以下のPythonのインストール方法で解説しています。
まだPythonをインストールしていないという方もこちらを見てインストールしてください。
事前準備としては、一番下のトークンのファイルにボットのトークンを書き込んでおいてください。これがないと起動できません。
ボットがオンラインになったことを確認したら、先に進んでください。
クライアント側の導入
専用クライアントの使用
上に説明しているように、自分でアクセスできる人はそれでも構いません。
プログラムに埋め込むにあたり、専用のクラスを作成しました。
使い方は以下の通りです。
まず最初にインポートしてインスタンスします。
インスタンス時には、チャンネルの名前とボットが稼働しているサーバーのアドレスを入力します。
ボットの方でWebサーバーのポート番号を変えている場合は、ポートの設定も必要です。
そしてインスタンスオブジェクトのlogメソッドを叩くだけ
>>>import loggingbot_client as LC
>>>l = LC.LoggingbotClient(Name="RcatTest",Server="192.168.0.4")
>>>l.log("てすとだよ~ん☆")実行結果がこちら
自動的にチャンネルが作成され、そこに発言されています。

ちなみにクラスの中身は次のようになっています。
Discordのbotが非同期なので、そういった都合のプログラムに対応できるようにaiohttpを使った関数をベースに作成しているのが特徴です。
ですので、他のbotの中から使う場合などは"await log_async()"のような形で使うこともできます。

また、上の方で説明していませんでしたが、実はログの文章はプレーンテキストのものではなく、base64にしてから送るということもできます。
ポストだと平気かもしれませんが、どんな文字が送られたとしても正常に受信できるようにという思いがあります。
デコレートで戻り値をログへ
上の方法はログを出力したい場合、関数にログ出力を追加する必要があります。
しかし今回からデコレーターを導入しました。これを使うことで関数を一切変更することなく、ログ出力できる可能性があります。
以下がサンプルです。これ実行するとどうなると思いますか?

通常の実行順で言えば、テスト1関数で"Nekoかわいい"がプリントされ終了ですが、今回@loggingbotというデコレーターが関数の前にありますね。
デコレーターは指定された関数の前後に追加の処理を設けられる機能です。
今回は関数が終わった後の戻り値をそのまま先ほど紹介したlog関数に渡してボットに発言させる機能が追加できます。
なお、仕様上文字列型限定です。
つまり、文字列型を返す関数であれば、このデコレーターを追加してログに戻り値を出力させることができます。
先ほどのクラスを定義したモジュールの末尾に先ほどのサンプルを記述して実行すると以下のようにボットの方にも文字列が出力されます。

このように関数に一切手を加えずに追加の機能を与えることができるのがデコレーターです。
全く新しく作るプログラムでは、最初からこのログ出力を考慮してもいいかもしれませんが、既存のものに追加機能として組み込みたい場合は利用してみてください。
履歴機能で連投防止(V1.1アップデート)
例えば何かしらの問題が発生した時にログを出力するとしたとします。
そしてその問題が続いてる間、ずっとログが出力されてしまったらなかなか大変なことになりますよね。
というわけでメッセージ履歴を残して、特定のインターバル以内の連投は無視するような設計にしました。
今回のアップデートで変更した箇所だけをハイライトしています。
具体的にはメッセージをキーとして、辞書に発言時刻を保持しています。
ただ、メッセージをそのまま使うとものすごい長いキーになってしまう可能性もあるので、今回はMD5ハッシュを利用しました。
このハッシュはファイルのチェックサムなどにも用いられているもので、一定の長さの唯一のキーを生成するのにちょうどいいと考えました。

実際に使ってみるとこんな感じで連打しても全く言うことを聞いてくれず、指定した時間が来ない限り送信されません。

このアップデートにより初期化の引数が増えていますのでご注意ください。
インターバルを秒で指定することで、その時間に送信された同じメッセージを無視するようになります。

loggingライブラリ用ハンドラー(V1.2アップデート)
Pythonの標準ライブラリであるloggingライブラリを使ったログ出力に本作をハンドラとして追加できるようにしました。
詳しくは以下の記事をご確認ください。
配布情報
配布URL
以下のURLで配布しています。
利用規約に同意の上、ご利用ください。
配布情報は下記をご確認ください。
いいなと思ったら応援しよう!
情報が役に立ったと思えば、僅かでも投げ銭していただけるとありがたいです。