1. 序章

Slackは、世界中の人々や企業が使用する人気のチャットシステムです。 これを非常に人気のあるものの1つは、単一のSlack内で人やチャネルと対話できる独自のカスタムプラグインを作成できることです。 これはHTTPAPIを使用します。

Slackは、Javaでプラグインを作成するための公式SDKを提供していません。 ただし、使用する公式に承認されたコミュニティSDKがあります。 これにより、APIの正確な詳細を気にすることなく、JavaコードベースからほぼすべてのSlackAPIにアクセスできます。

これを利用して、小さなシステム監視ボットを構築します。 これにより、ローカルコンピュータのディスク領域が定期的に取得され、ドライブがいっぱいになっている場合は警告が表示されます。

2. APIクレデンシャルの取得

Slackで何かを行う前に、新しいアプリとボットを作成してチャネルに接続する必要があります。

まず、https://api.slack.com/appsにアクセスしてみましょう。 これは、Slackアプリを管理するためのベースです。 ここから、新しいアプリを作成できます。

これを行うときは、アプリの名前と、アプリを作成するためのSlackワークスペースを入力する必要があります。

これが完了すると、アプリが作成され、作業できるようになります。 次の画面では、ボットを作成できます。 これは、プラグインが機能する偽のユーザーです。

通常のユーザーと同様に、これに表示名とユーザー名を付ける必要があります。 これらは、Slackワークスペース内の他のユーザーがこのボットユーザーと対話した場合に表示される設定です。

これで、サイドメニューから[アプリのインストール]を選択し、アプリをSlackワークスペースに追加できます。 これを実行すると、アプリはワークスペースと対話できるようになります。

これにより、プラグインがSlackと通信するために必要なトークンが得られます。

 

異なるSlackワークスペースと対話する各ボットには、異なるトークンのセットがあります。 アプリケーションを実行するときは、「ボットユーザーOAuthアクセストークン」の値が必要です。

最後に、ボットをに関与する必要のあるチャネルに招待する必要があります。 これは、チャネル(この場合は @system_monitoring )からメッセージを送信するだけで機能します。

3. プロジェクトにSlackを追加する

使用する前に、まずSlackSDKの依存関係pom.xmlファイルに追加する必要があります。

<dependency>
    <groupId>com.hubspot.slack</groupId>
    <artifactId>slack-base</artifactId>
    <version>${slack.version}</version>
</dependency>
<dependency>
    <groupId>com.hubspot.slack</groupId>
    <artifactId>slack-java-client</artifactId>
    <version>${slack.version}</version>
</dependency>

3. アプリケーション構造

私たちのアプリケーションの中核は、システムのエラーをチェックする機能です。 これをエラーチェッカーの概念で表現します。 これは、エラーをチェックして報告するためにトリガーされる、単一のメソッドを備えたシンプルなインターフェイスです。

public interface ErrorChecker {
    void check();
}

また、見つかったエラーを報告する手段も必要です。 これは、問題ステートメントを受け取り、それを適切に報告するもう1つの単純なインターフェースです。

public interface ErrorReporter {
    void reportProblem(String problem);
}

ここでインターフェースを使用すると、問題を報告するさまざまな方法が可能になります。 たとえば、メールを送信したり、エラー報告システムに連絡したり、Slackシステムにメッセージを送信してすぐに通知を受け取ったりするものがあるとします。

この背後にある設計は、各ErrorCheckerインスタンスに使用する独自のErrorReporterが与えられることです。 これにより、一部のエラーが他のエラーよりも重要になる可能性があるため、さまざまなチェッカーにさまざまなエラーレポーターを使用できる柔軟性が得られます。 たとえば、ディスクが90 % f ullを超えている場合、Slackチャネルへのメッセージが必要になる可能性がありますが、ディスクが98 % f ullを超えている場合は、代わりに特定の人にプライベートメッセージを送信することができます。

4. ディスク容量の確認

エラーチェッカーは、ローカルシステムのディスク容量をチェックします。 空きの割合が特定未満のファイルシステムはエラーと見なされ、そのように報告されます。

Java7で導入されたNIO2FileStore APIを利用して、クロスプラットフォームでこの情報を取得します。

それでは、エラーチェッカーを見てみましょう。

public class DiskSpaceErrorChecker implements ErrorChecker {
    private static final Logger LOG = LoggerFactory.getLogger(DiskSpaceErrorChecker.class);

    private ErrorReporter errorReporter;

    private double limit;

    public DiskSpaceErrorChecker(ErrorReporter errorReporter, double limit) {
        this.errorReporter = errorReporter;
        this.limit = limit;
    }

    @Override
    public void check() {
        FileSystems.getDefault().getFileStores().forEach(fileStore -> {
            try {
                long totalSpace = fileStore.getTotalSpace();
                long usableSpace = fileStore.getUsableSpace();
                double usablePercentage = ((double) usableSpace) / totalSpace;

                if (totalSpace > 0 && usablePercentage < limit) {
                    String error = String.format("File store %s only has %d%% usable disk space",
                        fileStore.name(), (int)(usablePercentage * 100));
                    errorReporter.reportProblem(error);
                }
            } catch (IOException e) {
                LOG.error("Error getting disk space for file store {}", fileStore, e);
            }
        });
    }
}

ここでは、ローカルシステム上のすべてのファイルストアのリストを取得し、それぞれを個別にチェックしています。 使用可能スペースとして定義された制限より少ないものは、エラーレポーターを使用してエラーを生成します。

5. Slackチャネルへのエラーの送信

エラーを報告できるようにする必要があります。 最初のレポーターはSlackチャネルにメッセージを送信するものになります。これにより、誰かがそれに反応することを期待して、チャネル内の誰もがメッセージを見ることができます。

これは、SlackSDKのSlackClient と、メッセージの送信先のチャネル名を使用します。 また、 ErrorReporter インターフェースを実装しているため、エラーチェッカーが使用したいものに簡単にプラグインできます。

public class SlackChannelErrorReporter implements ErrorReporter {
    private SlackClient slackClient;

    private String channel;

    public SlackChannelErrorReporter(SlackClient slackClient, String channel) {
        this.slackClient = slackClient;
        this.channel = channel;
    }

    @Override
    public void reportProblem(String problem) {
        slackClient.postMessage(
          ChatPostMessageParams.builder()
            .setText(problem)
            .setChannelId(channel)
            .build()
        ).join().unwrapOrElseThrow();
    }
}

6. アプリケーションの配線

これで、アプリケーションを接続してシステムを監視できるようになりました。 このチュートリアルでは、コアJVMの一部であるJavaタイマーとTimerTaskを使用しますが、Springやその他のフレームワークを使用してこれを構築することも簡単にできます。

今のところ、これには単一の DiskSpaceErrorChecker があり、10 % u未満のディスクを「一般」チャネルに報告し、5分ごとに実行されます。

public class MainClass {
    public static final long MINUTES = 1000 * 60;

    public static void main(String[] args) throws IOException {
        SlackClientRuntimeConfig runtimeConfig = SlackClientRuntimeConfig.builder()
          .setTokenSupplier(() -> "<Your API Token>")
          .build();

        SlackClient slackClient = SlackClientFactory.defaultFactory().build(runtimeConfig);

        ErrorReporter slackChannelErrorReporter = new SlackChannelErrorReporter(slackClient, "general");

        ErrorChecker diskSpaceErrorChecker10pct = 
          new DiskSpaceErrorChecker(slackChannelErrorReporter, 0.1);

        Timer timer = new Timer();
        timer.scheduleAtFixedRate(new TimerTask() {
            @Override
            public void run() {
                diskSpaceErrorChecker10pct.check();
            }
        }, 0, 5 * MINUTES);
    }
}

」と以前に取得したトークンを使用すると、実行する準備が整います。 すぐに、すべてが正しければ、プラグインはローカルドライブをチェックし、エラーがある場合はSlackにメッセージを送信します。

7. プライベートメッセージとしてのエラーの送信

次に、代わりにプライベートメッセージを送信するエラーレポーターを追加します。 これは、チャネル内の誰かに反応するのではなく、特定のユーザーにすぐにpingを送信するため、より緊急のエラーに役立ちます

ここでのエラーレポーターは、単一のターゲットユーザーと対話する必要があるため、より複雑です。

public class SlackUserErrorReporter implements ErrorReporter {
    private SlackClient slackClient;

    private String user;

    public SlackUserErrorReporter(SlackClient slackClient, String user) {
        this.slackClient = slackClient;
        this.user = user;
    }

    @Override
    public void reportProblem(String problem) {
        UsersInfoResponse usersInfoResponse = slackClient
            .lookupUserByEmail(UserEmailParams.builder()
              .setEmail(user)
              .build()
            ).join().unwrapOrElseThrow();

        ImOpenResponse imOpenResponse = slackClient.openIm(ImOpenParams.builder()
            .setUserId(usersInfoResponse.getUser().getId())
            .build()
        ).join().unwrapOrElseThrow();

        imOpenResponse.getChannel().ifPresent(channel -> {
            slackClient.postMessage(
                ChatPostMessageParams.builder()
                  .setText(problem)
                  .setChannelId(channel.getId())
                  .build()
            ).join().unwrapOrElseThrow();
        });
    }
}

ここで行う必要があるのは、メッセージを送信しているユーザーを見つけることです。これは変更できない1つのことであるため、電子メールアドレスで検索します。 次に、ユーザーにIMチャネルを開き、そのチャネルにエラーメッセージを投稿します。

次に、これを main メソッドに接続して、1人のユーザーに直接警告します。

ErrorReporter slackUserErrorReporter = new SlackUserErrorReporter(slackClient, "[email protected]");

ErrorChecker diskSpaceErrorChecker2pct = new DiskSpaceErrorChecker(slackUserErrorReporter, 0.02);

timer.scheduleAtFixedRate(new TimerTask() {
    @Override
    public void run() {
        diskSpaceErrorChecker2pct.check();
    }
}, 0, 5 * MINUTES);

完了したら、これを実行して、エラーのプライベートメッセージを取得することもできます。

8. 結論

ここでは、Slackをツールに組み込んで、チーム全体または個々のメンバーにフィードバックを送信する方法を説明しました。 Slack APIでできることはまだまだたくさんあるので、他に何を組み込むことができるか見てみませんか。

いつものように、この記事のソースコードはGitHubにあります。