«1. Введение

Slack — популярная система чата, используемая людьми и компаниями по всему миру. Одна из вещей, которая делает его таким популярным, — это возможность писать собственные настраиваемые плагины, которые могут взаимодействовать с людьми и каналами в рамках одного Slack. Это использует их HTTP API.

Slack не предлагает официального SDK для написания плагинов на Java. Однако есть официально одобренный сообществом SDK, который мы собираемся использовать. Это дает нам доступ почти ко всему Slack API из кодовой базы Java без необходимости вникать в точные детали API.

Мы воспользуемся этим для создания небольшого бота для мониторинга системы. Это будет периодически извлекать дисковое пространство для локального компьютера и предупреждать людей, если какие-либо диски переполняются.

2. Получение учетных данных API

Прежде чем мы сможем что-то делать со Slack, нам нужно создать новое приложение и бота и подключить его к нашим каналам.

Во-первых, давайте посетим https://api.slack.com/apps. Это база, откуда мы управляем нашими приложениями Slack. Отсюда мы можем создать новое приложение.

Когда мы это сделаем, нам нужно ввести имя для приложения и рабочее пространство Slack для его создания.

После того, как мы это сделали, приложение создано и готово для работы. Следующий экран позволяет нам создать бота. Это поддельный пользователь, от имени которого будет действовать плагин.

Как и любому обычному пользователю, нам нужно дать ему отображаемое имя и имя пользователя. Это настройки, которые другие пользователи в рабочей области Slack увидят для этого пользователя-бота, если они когда-либо взаимодействуют с ним.

Теперь, когда мы это сделали, мы можем выбрать «Установить приложение» в боковом меню и добавить приложение в наше рабочее пространство Slack. Как только мы это сделали, приложение может взаимодействовать с нашим рабочим пространством.

Это даст нам токены, которые нужны нашему плагину для связи со Slack.

Каждый бот, взаимодействующий с другим рабочим пространством Slack, будет иметь свой набор токенов. Нашему приложению требуется значение «Токен доступа OAuth пользователя бота» для его запуска.

Наконец, нам нужно пригласить бота на все каналы, в которых он должен быть задействован. Для этого достаточно просто отправить ему сообщение из канала — в данном случае @system_monitoring.

3. Добавление Slack в наш проект

Прежде чем мы сможем его использовать, нам сначала нужно добавить зависимости Slack SDK в наш файл pom.xml:

3. Структура приложения

<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>

Ядро нашего приложения является возможность проверки на наличие ошибок в системе. Мы представим это с помощью концепции средства проверки ошибок. Это простой интерфейс с одним методом, запускаемым для проверки ошибок и сообщения о них:

Мы также хотим иметь возможность сообщать обо всех обнаруженных ошибках. Это еще один простой интерфейс, который будет принимать формулировку проблемы и сообщать о ней соответствующим образом:

public interface ErrorChecker {
    void check();
}

Использование интерфейса здесь позволяет нам использовать различные способы сообщения о проблемах. Например, у нас может быть тот, который отправляет электронные письма, связывается с системой отчетов об ошибках или отправляет сообщения в нашу систему Slack, чтобы люди получали немедленное уведомление.

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

За этим стоит такой дизайн, что каждому экземпляру ErrorChecker предоставляется свой собственный ErrorReporter для использования. Это дает нам возможность использовать разные отчеты об ошибках для разных средств проверки, потому что некоторые ошибки могут быть более важными, чем другие. Например, если диски заполнены более чем на 90%, может потребоваться сообщение в канал Slack, но если они заполнены более чем на 98%, вместо этого мы можем захотеть отправлять личные сообщения определенным людям.

4. Проверка дискового пространства

Наша программа проверки ошибок проверит объем дискового пространства в локальной системе. Любая файловая система, которая имеет меньше определенного процента свободного места, считается ошибкой и будет сообщено как таковая.

Мы будем использовать API-интерфейс NIO2 FileStore, представленный в Java 7, для получения этой информации кросс-платформенным способом.

Теперь давайте посмотрим на нашу программу проверки ошибок:

«

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. Это позволяет любому пользователю канала увидеть сообщение в надежде, что кто-то на него отреагирует.

Здесь используется SlackClient из Slack SDK и имя канала для отправки сообщений. Он также реализует наш интерфейс 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. Подключение приложения

Теперь мы можем подключить приложение и заставить его отслеживать наша система. Для этого руководства мы собираемся использовать Java Timer и TimerTask, которые являются частью основной JVM, но мы могли бы так же легко использовать Spring или любую другую среду для создания этого.

На данный момент у него будет один DiskSpaceErrorChecker, который сообщает обо всех дисках, которые используются менее чем на 10%, в наш «общий» канал и который запускается каждые 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);
    }
}

Нам нужно заменить – \u003cВаш токен API\u003e — с токеном, который был получен ранее, и тогда мы готовы к запуску. Как только мы это сделаем, если все правильно, наш плагин проверит локальные диски и сообщит Slack, если есть какие-либо ошибки.

7. Отправка ошибок в виде личных сообщений

Далее мы добавим отчет об ошибках, который вместо этого отправляет личные сообщения. Это может быть полезно для более срочных ошибок, так как он немедленно пингует конкретного пользователя, вместо того, чтобы полагаться на то, что кто-то в канале отреагирует.

Наш генератор сообщений об ошибках здесь более сложен, потому что ему нужно взаимодействовать с одним целевым пользователем:

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();
        });
    }
}

Здесь нам нужно найти пользователя, которому мы отправляем сообщения – поиск по электронной почте. адрес, так как это единственное, что нельзя изменить. Затем мы открываем канал обмена мгновенными сообщениями для пользователя, а затем отправляем сообщение об ошибке на этот канал.

Затем это можно подключить к основному методу, и мы будем оповещать одного пользователя напрямую:

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.