Логи Discord webhook с FiveM сервера: руководство PerformHttpRequest
Отправляйте логи в Discord с FiveM с помощью PerformHttpRequest и JSON embeds. Только серверная часть, URL в convar, очередь для лимитов и что логировать.
Вы хотите знать, кто что купил, кто дал деньги, кто запустил команду администратора и кто присоединился, без просмотра консоли весь день. Discord webhook делает это: ваш сервер публикует сообщение на канале. Это руководство показывает серверную часть Lua с PerformHttpRequest, как строить embeds, как держать URL безопасным и как избежать лимита.
Создайте webhook
В Discord откройте параметры канала, затем Integrations, затем Webhooks, создайте один и скопируйте его URL. Это выглядит как https://discord.com/api/webhooks/<id>/<token>. Любой с этим URL может опубликовать в вашем канале, поэтому обращайтесь с ним как с паролем.
Держите URL в convar
Поместите это в server.cfg:
set discord_webhook_logs "https://discord.com/api/webhooks/ID/TOKEN"Используйте set, не setr или sets. Replicated convar отправляется каждому клиенту, что вызовет утечку URL. Читайте это на сервере:
local WEBHOOK = GetConvar('discord_webhook_logs', '')Если convar пуст, пропустите отправку вместо ошибки. Вы можете держать один convar на тип лога (деньги, админ, присоединения), чтобы отправлять их в разные каналы.
Отправьте сообщение
local function sendLog(title, description, color, fields)
if WEBHOOK == '' then return end
local embed = {
title = title,
description = description,
color = color or 3447003,
fields = fields,
timestamp = os.date('!%Y-%m-%dT%H:%M:%SZ'),
}
PerformHttpRequest(WEBHOOK, function(status, body, headers)
if status ~= 204 and status ~= 200 then
print(('webhook failed: %s'):format(status))
end
end, 'POST', json.encode({ username = 'Server logs', embeds = { embed } }), {
['Content-Type'] = 'application/json',
})
endМоменты для знания:
color— это десятичное число, не шестнадцатеричная строка.3447003— это синий и15158332— это красный. Конвертируйте hex сtonumber('FF0000', 16).timestampдолжен быть датой ISO 8601 в UTC.!в формате заставляетos.dateиспользовать UTC.fields— это список{ name = '...', value = '...', inline = true }. Значение поля не может быть пустым.- Успешный вызов webhook возвращает статус 204, с пустым телом.
- Discord ограничивает размеры. Названия короткие (256 символов), описания длинные, но ограничены (4096), и сообщение содержит ограниченное количество полей и embeds. Обрежьте длинный текст перед отправкой.
Пример вызова, для игрока, который отправил деньги:
sendLog('Money transfer', 'A player sent money', 3066993, {
{ name = 'From', value = ('%s (id %d)'):format(GetPlayerName(src), src), inline = true },
{ name = 'To', value = ('%s (id %d)'):format(GetPlayerName(target), target), inline = true },
{ name = 'Amount', value = ('$%d'):format(amount), inline = false },
})Только на сервере, никогда из клиента
Внимание: не вызывайте
PerformHttpRequestдля webhook в клиентском скрипте и не отправляйте URL клиенту. Файлы клиента могут быть прочитаны каждым игроком, поэтому URL утекает и любой может затопить вашей канал.
Если событие на клиенте должно быть залогировано, отправьте событие на сервер, и пусть сервер решает, что логировать из доверенных данных. Клиент, который может вызвать «залогировать этот текст», может также вызвать поддельные логи. Для безопасности событий в целом читайте secure events in FiveM. Логируйте то, что сделал сервер, не то, что говорит клиент.
Лимиты: используйте очередь
Discord отклоняет вызовы webhook, которые приходят слишком быстро, с ответом 429. Всплеск логи, такие как 50 игроков, запускающих то же событие, может его поразить. Отправляйте сообщения из очереди в устойчивом темпе:
local queue = {}
local function enqueue(payload)
queue[#queue + 1] = payload
end
CreateThread(function()
while true do
local item = table.remove(queue, 1)
if item then
PerformHttpRequest(WEBHOOK, function(status, _, headers)
if status == 429 then
-- put it back and wait a bit longer
table.insert(queue, 1, item)
Wait(5000)
end
end, 'POST', json.encode(item), { ['Content-Type'] = 'application/json' })
end
Wait(2000)
end
end)Ожидание две секунды между сообщениями держит под лимитом. Если вам нужно больше, объедините несколько embeds в одно сообщение: один запрос может нести до 10 embeds в его списке embeds. Для использования Wait см. Wait explained.
Что логировать
Логируйте события, которые вы хотели бы, когда что-то идёт не так:
- Деньги: большие передачи, покупки, всё, что создаёт деньги. Это где проявляется злоупотребление в первую очередь.
- Действия администратора: кто использовал какую команду администратора на ком, запреты, предупреждения, телепорты. См. ban and warn players.
- Присоединения и отключения, с идентификаторами игрока, что помогает с диспутами и запретами.
- Спавнинг предметов и использование оружия, если вы это позволяете.
Не логируйте всё. Канал с сообщением каждую секунду — это канал, который никто не читает. Выберите несколько каналов, положите важные там, где смотрит сотрудник, и держите остальное коротким. Держите личные данные на то, что вам нужно, и не логируйте приватный чат.
Совет: положите функцию логирования в маленький ресурс и вызовите её с экспортом из других скриптов, поэтому URL webhook и очередь лимита живут в одном месте. См. exports in FiveM.
Контрольный список
| Проблема | Решение |
|---|---|
| Ничего не приходит | Проверьте имя convar, что URL полный и что вызов работает на сервере |
| Статус 400 | JSON неправильный: пустое значение поля, слишком длинный текст, или цвет hex строка |
| Статус 429 | Отправляйте через очередь с паузой между сообщениями |
| Временная метка игнорируется | Используйте UTC ISO 8601: os.date('!%Y-%m-%dT%H:%M:%SZ') |
| URL утёкший | Удалите webhook в Discord, создайте новый и держите его в convar set |
| Слишком много сообщений | Логируйте только деньги, действия администратора и присоединения |
Короткие ответы
Могу ли я отправить Discord webhook из клиента?
Нет. Любой может прочитать клиентский код и украсть URL webhook, затем спамить вашей канал. Вызовите лог на сервере и отправьте его оттуда.
Сколько сообщений webhook я могу отправить?
Discord ограничивает webhook, и примерно 30 сообщений в минуту на webhook — это безопасный потолок. Дальше вы получаете ответ 429, поэтому поставьте ваши сообщения в очередь и отправляйте их в устойчивом темпе.
Где мне держать URL webhook?
В convar сервера, установленном с set в server.cfg, читаемый с GetConvar. Никогда не кладите его в файл клиента или в convar, установленный с setr или sets.
Скрипты без этой проблемы
Advanced BoostingУгон машин на заказ через планшет: контракты от класса D до S+, команды и живая очередь.Смотреть скрипт →
Crypto MiningКупите склад, соберите фермы по деталям и майните монеты на живом рынке.Смотреть скрипт →
Shop CreatorМагазин меньше чем за минуту — владельцы, сотрудники, сейфы и ограбления в комплекте.Смотреть скрипт →