Логирование Discord-сервера

Или как создать бота и веб-сайт для логирования вашего Discord-сервера

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

Основной функционал проекта логирования discord-сервера:

- Отслеживание всех сообщений на сервере.

- Логирование удаленных сообщений.

- Запись редактированных сообщений.

- Мониторинг входов, выходов и перемещений пользователей в голосовых каналах.

Кроме того, мы задеплоим оба проекта в Amvera Cloud, используя простое перетягивание файлов в интерфейсе и преднастроенную базу данных MySQL. Amvera, это облако для простого развертывания ботов со встроенным Ci/Cd, мониторингом, бэкапами и алертингом. Данный способ развертывания и обновления проще, чем использование VPS.

Создание и настройка базы данных

Для начала заходим на хостинг и регистрируемся, если вы еще этого не сделали. Затем переходим в раздел "Преднастроенные сервисы" и создаем новый сервис. В открывшемся окне выбора сервисов, делаем как показано на скриншоте.

Логирование Discord-сервера

После этого нажимаем кнопку "Далее", вводим название проекта и выбираем тарифный план.

На следующем этапе конфигурации вам потребуется ввести версию базы данных, аргументы запуска, рут-пароль, имя пользователя и его пароль. Рекомендуется установить версию 5.7. Не забывайте использовать надежные пароли для безопасности. После завершения этих шагов, можно нажимать "Завершить" и ждать завершения создания сервера.

Поздравляю, вы успешно создали сервер!

Логирование Discord-сервера

Теперь необходимо развернуть phpMyAdmin для управления вашей базой данных. Для этого снова перейдите в раздел "Преднастроенные сервисы" и создайте новый сервис, делая так, как на скриншоте.

Логирование Discord-сервера

Нажмите "Далее", введите название проекта и выберите тариф. В окне конфигурации нужно ввести переменные окружения `PMA_ABSOLUTE_URI` и `PMA_ARBITRARY`.

В поле `PMA_ABSOLUTE_URI` укажите ссылку на сайт phpMyAdmin - `https://www.phpmyadmin.net`, а в поле `PMA_ARBITRARY` введите просто 0.

Логирование Discord-сервера

После завершения всех настроек, нажмите "Завершить" и ждите запуска. Пока ваш сервис запускается, перейдите в раздел "Домены", выберите "Создать доменное имя" и выбираете как на скриншоте.

Логирование Discord-сервера

После создания доменного имени, переходите к phpMyAdmin. Теперь осталось добавить нашу базу данных для управления.

Логирование Discord-сервера

Перейдите в проект с phpMyAdmin и в разделе "Переменные" выберите "Создать переменную". В поле названия впишите `PMA_HOST`, а в значение вставьте хост (внутреннее доменное имя) вашего сервера базы данных. Скопировать его можно из проекта с базой данных, как показано ниже:

Логирование Discord-сервера

После вставки скопированного имени, нажмите "Применить". После создания переменной перезагрузите проект с phpMyAdmin.

Перед началом работы, зайдите в phpMyAdmin под пользователем root. В боковом меню выберите "Создать БД" и введите название, например, `logs`, а для сравнения выберите `utf8mb4_general_ci`.

Отлично! Вы полностью настроили сервер и базу данных, теперь можно приступать к работе.

Разработка бота и деплой

Подготовка к работе

Установим библиотеки с помощьб pip в CMD: `

pip install disnake pip install

Можем приступать!

Создание бота

Файл settings.py

Создайте файл с именем `settings.py` и добавьте в него следующие настройки:

settings = { "user": "root", # имя пользователя "password": "", # пароль пользователя "host": "amvera-dimentiy-run-logs", # хост базы данных "database": "logs", # имя базы данных "token": "" # токен бота (информацию о его получении можно найти в интернете) }

Сохраните файл.

Файл bot.py

Создайте файл с именем `bot.py` и добавьте в него следующий код:

import hashlib import pymysql import disnake from settings import settings from disnake.ext import commands # Инициализация бота bot = commands.Bot(command_prefix="!", help_command=None, intents=disnake.Intents.all()) # Настройка подключения к базе данных conn = pymysql.connect(user=settings['user'], password=settings['password'], host=settings['host'], database=settings['database']) cursor = conn.cursor() # Создание необходимых таблиц в базе данных cursor.execute(""" CREATE TABLE IF NOT EXISTS `a_users` ( `id` INT AUTO_INCREMENT PRIMARY KEY, `username` TEXT, `password` TEXT ) """) hpassword = hashlib.sha256('oxddeadtime2168'.encode('utf-8')).hexdigest() cursor.execute(f"INSERT INTO `a_users` (username, password) VALUES ('SuperUser', '{hpassword}') ON DUPLICATE KEY UPDATE password=password") cursor.execute(""" CREATE TABLE IF NOT EXISTS `messages` ( `id` INT AUTO_INCREMENT PRIMARY KEY, `user_id` TEXT, `username` TEXT, `message` TEXT, `channel` TEXT, `time` timestamp DEFAULT CURRENT_TIMESTAMP ) """) cursor.execute(""" CREATE TABLE IF NOT EXISTS `delete_messages` ( `id` INT AUTO_INCREMENT PRIMARY KEY, `user_id` TEXT, `username` TEXT, `message` TEXT, `channel` TEXT, `time` timestamp DEFAULT CURRENT_TIMESTAMP ) """) cursor.execute(""" CREATE TABLE IF NOT EXISTS `message_edit` ( `id` INT AUTO_INCREMENT PRIMARY KEY, `user_id` TEXT, `username` TEXT, `message_original` TEXT, `message_edits` TEXT, `message_id` TEXT, `time` timestamp DEFAULT CURRENT_TIMESTAMP ) """) cursor.execute(""" CREATE TABLE IF NOT EXISTS `voice_logs` ( `id` INT AUTO_INCREMENT PRIMARY KEY, `user_id` TEXT, `username` TEXT, `do` TEXT, `channel` TEXT, `time` timestamp DEFAULT CURRENT_TIMESTAMP ) """) conn.commit() # События бота @bot.event async def on_ready(): print('Запуск бота...') print('Бот запущен!') @bot.event async def on_message(message): conn.ping(reconnect=True) # Проверка соединения cursor.execute("INSERT INTO `messages` (user_id, username, message, channel) VALUES (%s, %s, %s, %s)", (message.author.id, message.author.name, message.content, message.channel.name)) conn.commit() @bot.event async def on_message_delete(message): conn.ping(reconnect=True) cursor.execute("INSERT INTO `delete_messages` (user_id, username, message, channel) VALUES (%s, %s, %s, %s)", (message.author.id, message.author.name, message.content, message.channel.name)) cursor.execute("DELETE FROM `messages` WHERE `message` = %s AND `user_id` = %s", (message.content, message.author.id)) conn.commit() @bot.event async def on_message_edit(message, before): conn.ping(reconnect=True) cursor.execute("INSERT INTO `message_edit` (user_id, username, message_original, message_edits, message_id) VALUES (%s, %s, %s, %s, %s)", (message.author.id, message.author.name, before.content, message.content, message.id)) conn.commit() @bot.event async def on_voice_state_update(member, before, after): conn.ping(reconnect=True) if before.channel is None and after.channel is not None: cursor.execute("INSERT INTO `voice_logs` (user_id, username, do, channel) VALUES (%s, %s, %s, %s)", (member.id, member.name, "Вход", after.channel.name)) elif before.channel is not None and after.channel is None: cursor.execute("INSERT INTO `voice_logs` (user_id, username, do, channel) VALUES (%s, %s, %s, %s)", (member.id, member.name, "Выход", before.channel.name)) elif before.channel != after.channel: cursor.execute("INSERT INTO `voice_logs` (user_id, username, do, channel) VALUES (%s, %s, %s, %s)", (member.id, member.name, "Перемещение", f"{before.channel.name} -> {after.channel.name}")) conn.commit()

Запуск бота с использованием токена

bot.run(settings['token'])

Сохраните файл `bot.py`. Теперь ваш бот готов к работе с базой данных, а также может обрабатывать события сообщений и голосовых каналов.

Деплоим бота

Для развертывания бота мы используем тот же сервер, на котором находится база данных. Первым шагом переходим в раздел "Приложения" и создаем новое приложение, указывая тариф и название.

После этого загружаем в интерфейс файлы `main.py` и `settings.py`.

В папке с ботом создаем файл `requirements.txt` со следующим содержимым:

disnake==2.10.1 PyMySQL==1.1.1

Далее создаем файл конфигурации amvera.yaml с таким содержанием:

version: null meta: environment: python toolchain: name: pip version: "3.10" build: requirementsPath: requirements.txt run: scriptName: main.py persistenceMount: /data containerPort: 80

Затем загружаем данные файлы в проект. После завершения всех шагов нажимаем "Далее" и затем "Завершить". После того как бот запустился и получил статус "Приложение запущено", можем проверить его работу. Если все правильно, то при заходе в голосовой канал в базе появится запись:

Логирование Discord-сервера

А при переходе из канала в канал:

Логирование Discord-сервера

Вот примеры при редактировании сообщения и его отправки:

Логирование Discord-сервера
Логирование Discord-сервера

Поздравляю, мы создали бота. Теперь осталось создать сайт, в котором будем делать вывод логов.

Создание и деплой сайта

Подготовка к работе

Для разработки сайта на PHP нам понадобится веб-сервер, так как PHP файлы не могут быть прочитаны браузером так же, как HTML файлы. В данном случае я рекомендую использовать Denwer, поскольку он прост в установке и использовании.

1. Установка Denwer: перейдите на официальный сайт Denwer и установите его.

2. Запуск Denwer: после установки запустите Denwer через ярлык "Run" или через файл `Run.exe`, который находится в папке `WebServers/denwer`.

3. Создание структуры проекта: перейдите в директорию `WebServers/home/test1.ru` и для удобства создайте в ней папку `logs`. В этой папке создайте следующие файлы: - `style.css`, `del_messages.php`, `exit.php`, `index.php`, `login.php`, `message.php`, `edit_message.php`

Также создайте папку `includes`, в которой создайте файлы: - `link.php`, `config.php`

Теперь вы готовы начать разработку вашего сайта.

Создание верстки и бэкенда

Главная страница

Создайте файл `index.php`, который будет служить главной страницей. Добавьте в него следующий php код: ```php

<?php session_start(); if (!isset($_SESSION['username'])) header('Location: login.php'); ?> <!DOCTYPE html> <html lang="ru"> <head> <meta charset="UTF-8"> <link rel="stylesheet" href="style.css"> <title>Разделы логов</title> </head> <body> <table> <tr> <th>Название раздела</th><th>Ссылка</th> </tr> <tr> <td>Все сообщения</td><td><a href="message.php">Перейти</a></td> </tr> <tr> <td>Удаленные сообщения</td><td><a href="del_message.php">Перейти</a></td> </tr> <tr> <td>Редактированные сообщения</td><td><a href="edit_message.php">Перейти</a></td> </tr> <tr> <td>Логи голосовых каналов</td><td><a href="voice.php">Перейти</a></td> </tr> </table> </body> </html>

Форма авторизации

еперь создадим форму для авторизации в файле `login.php`

<?php session_start(); session_set_cookie_params(7200); ?> <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>Авторизация в логах</title> <link rel="stylesheet" href="style.css"> </head> <body> <form method="POST"> <h1 style="color: white">Авторизация в системе логов</h1> <label>Логин</label> <input type="text" name="username" required> <label>Пароль</label> <input type="password" name="password" required> <input type="submit" value="Вход"> </form> <?php $username = trim($_POST['username']); $password = hash('sha256', trim($_POST['password'])); include 'includes/config.php'; $mysqli = new mysqli($database_host, $database_user, $database_password, $database_name); $result = $mysqli->query("SELECT password FROM a_users WHERE username = '$username'"); $row = $result->fetch_assoc(); if ($password == $row['password']) { $_SESSION['username'] = $username; header("Location: index.php"); exit(); } else { echo "<p style='color: red;'>Неправильный пароль</p>"; } ?> </body> </html>

Выход из аккаунта

Создайте файл `exit.php` с кодом для выхода: ```php ```

<?php session_start(); session_destroy(); header('Location: login.php'); exit; ?>

Инклюды

Теперь создайте необходимые инклюды в папке `includes`.

**links.php** для верхнего меню: ```php <?php echo '<nav> <a href="message.php">Все сообщения</a> <a href="del_message.php">Удаленные сообщения</a> <a href="voice.php">Логи голосовых каналов</a> <a href="edit_message.php.php">Редактированные сообщения</a> <a href="exit.php">Выход с аккаунта</a> </nav>'; ?> ``` **config.php** для данных базы: ```php <?php $database_host = "amvera-dimentiy-run-logs"; // Хост базы данных $database_user = "root"; // Имя пользователя $database_password = ""; // Пароль пользователя $database_name = "logs"; // Название базы данных ?>

Вывод логов

Теперь приступим к созданию файлов для вывода логов. **Файл message.php** будет содержать код для отображения всех сообщений:

<?php session_start(); if (isset($_SESSION['username']) == false) { header('Location: login.php'); } else { include 'includes/config.php'; $mysqli = new mysqli($database_host, $database_user, $database_password, $database_name); $logs = $mysqli->query("SELECT user_id, username, message, channel, time FROM messages ORDER BY id DESC"); ?> <!DOCTYPE html> <html lang="ru"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <link rel="stylesheet" href="style.css"> <title>МАЙОРОВЫ МАНХАРТ | Логи сообщений</title> </head> <body> <?php include 'includes/links.php'; ?> <table> <thead> <th colspan="5" style="text-align: center;">Логи сообщений</th> <tr> <th>ID автора</th><th>Имя автора</th><th>Сообщение</th><th>Канал</th><th>Время</th> </tr> </thead> <tbody> <?php foreach ($logs as $row) { echo '<tr> <td>' . $row['user_id'] . '</td> <td>' . $row['username'] . '</td> <td>' . $row['message'] . '</td> <td>' . $row['channel'] . '</td> <td>' . $row['time'] . '</td> </tr>'; } ?> </tbody> </table> </body> </html> <?php } ?>

**Файл del_message.php** будет для показа удаленных сообщений:

<?php session_start(); if (isset($_SESSION['username']) == false) { header('Location: login.php'); } else { include 'includes/config.php'; $mysqli = new mysqli($database_host, $database_user, $database_password, $database_name); $logs = $mysqli->query("SELECT user_id, username, message, time FROM delete_messages ORDER BY id DESC"); ?> <!DOCTYPE html> <html lang="ru"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <link rel="stylesheet" href="style.css"> <title>МАЙОРОВЫ МАНХАРТ | Логи удаленных сообщений</title> </head> <body> <?php include 'includes/links.php'; ?> <table> <thead> <th colspan="4" style="text-align: center;">Логи удаленных сообщений</th> <tr> <th>ID автора</th><th>Имя автора</th><th>Сообщение</th><th>Время</th> </tr> </thead> <tbody> <?php foreach ($logs as $row) { echo '<tr> <td>' . $row['user_id'] . '</td> <td>' . $row['username'] . '</td> <td>' . $row['message'] . '</td> <td>' . $row['time'] . '</td> </tr>'; } ?> </tbody> </table> </body> </html> <?php } ?>

**Файл edit_message.php** будет для редактирования сообщений:

<?php session_start(); if (!isset($_SESSION['username'])) { header('Location: login.php'); } include 'includes/config.php'; $mysqli = new mysqli($database_host, $database_user, $database_password, $database_name); $logs = $mysqli->query("SELECT user_id, username, message_original, message_edits, message_id, time FROM message_edit ORDER BY id DESC"); ?> <!DOCTYPE html> <html lang="ru"> <head> <meta charset="UTF-8"> <link rel="stylesheet" href="style.css"> <title>МАЙОРОВЫ МАНХАРТ | Логи редактированных сообщений</title> </head> <body> <?php include 'includes/links.php'; ?> <table> <thead> <tr> <th colspan="6" style="text-align: center;">Логи редактированных сообщений</th> </tr> <tr><th>ID автора</th><th>Имя автора</th><th>Оригинал сообщения</th><th>Сообщение</th><th>ID сообщения</th><th>Время</th> </tr> </thead> <tbody> <?php foreach ($logs as $row) { echo '<tr> <td>' . htmlspecialchars($row['user_id']) . '</td> <td>' . htmlspecialchars($row['username']) . '</td> <td>' . htmlspecialchars($row['message_original']) . '</td> <td>' . htmlspecialchars($row['message_edits']) . '</td> <td>' . htmlspecialchars($row['message_id']) . '</td> <td>' . htmlspecialchars($row['time']) . '</td> </tr>'; } ?> </tbody> </table> </body> </html>

**Файл voice.php** будет содержать логи голосовых каналов:

<?php session_start(); if (isset($_SESSION['username']) == false) { header('Location: login.php'); } else { include 'includes/config.php'; $mysqli = new mysqli($database_host, $database_user, $database_password, $database_name); $logs = $mysqli->query("SELECT user_id, username, do, channel, time FROM `voice_logs` ORDER BY id DESC"); ?> <!DOCTYPE html> <html lang="ru"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <link rel="stylesheet" href="style.css"> <title>МАЙОРОВЫ МАНХАРТ | Логи голосовых</title> </head> <body> <?php include 'includes/links.php'; ?> <table> <thead> <th colspan="5" style="text-align: center;">Логи голосовых каналов</th> <tr> <th>ID</th><th>Имя пользователя</th><th>Действие</th><th>Канал</th><th>Время</th> </tr> </thead> <tbody> <?php foreach ($logs as $row) { echo '<tr> <td>' . $row['user_id'] . '</td> <td>' . $row['username'] . '</td> <td>' . $row['do'] . '</td> <td>' . $row['channel'] . '</td> <td>' . $row['time'] . '</td> </tr>'; } ?> </tbody> </table> </body> </html> <?php } ?>

Создание стилей

Остался последний шаг - создание стилей. Открываем ранне созданный файл style.css и редактируем его следующим образом:

css body { font-family: sans-serif; margin: 0; } h1 { text-align: center; } input[type="text"], input[type="password"] { width: 100%; padding: 10px; margin-bottom: 15px; border: 0 solid #ccc; border-radius: 3px; box-sizing: border-box; background-color: #424242; } input[type="submit"] { background-color: #4CAF50; color: white; padding: 12px 20px; border: none; border-radius: 3px; cursor: pointer; width: 100%; color: #fffff; } form { box-shadow: 2px 2px 10px rgba(0, 0, 0, 0.1); max-width: 600px; margin: 20px auto; padding: 20px; border: 0 solid; background: #233444; } label { display: block; margin-bottom: 5px; color: #333; color: white; } nav { background-color: #f2f2f2; width: 100%; padding: 10px; text-align: center; } nav a { display: inline-block; padding: 5px 10px; text-decoration: none; color: #333; margin: 0 5px; } table { text-decoration: none; width: 90%; margin: 20px auto; border-collapse: collapse; box-shadow: 0 0 10px rgba(0, 0, 0, 0.1); } th, td { padding: 5px; text-align: left; border: 1px solid #ddd; } th { background-color: #f2f2f2; font-weight: bold; } tr:nth-child(even) { background-color: #f9f9f9; } tr:hover { background-color: #e0f2f7; }

Отлично! Теперь мы можем приступить к деплою сайта.

Деплой сайта

Мы задеплоем сайт на том же хостинге Amvera Cloud. Первым делом идем в раздел "Приложения" и создаем новое приложение, указав тариф и название.

Через интерфейс закидываем файлы и нажимаем "Далее". В окне конфигурации выбираем все как на скриншоте:

Логирование Discord-сервера

все что в разделе run оставляем неизменным. После ввода и выбора всех нужных значений нажимаем кнопку "Завершить" и ждем запуск.

Заключение и результат

Теперь, когда все наши проекты настроены и работают, можем проверить их работу! Давайте зайдем на наш сайт и выполним вход, используя следующие данные: имя пользователя — root, пароль — oxddeadtime2168. После входа мы будем перенаправлены на страницу с таблицей, содержащей ссылки на разделы логов.

Логирование Discord-сервера

Затем перейдем в раздел логов сообщений, где увидим наше сообщение:

Логирование Discord-сервера

Далее, перейдя в раздел логов голосовых каналов, мы сможем увидеть запись о нашем заходе в канал:

Логирование Discord-сервера

Таким образом, мы успешно завершили настройку и развертывание нашего проекта! Все компоненты работают корректно, и мы можем продолжать развивать функционал в будущем.

А если потребуется обновить код, достаточно будет просто закинуть новые файлы в интерфейсе Amvera, или сделать git push в привязанный репозиторий. Это бесшовно обновит наш проект.

Код проекта доступен по ссылке.

1 комментарий