Logs de webhook Discord de um servidor FiveM: guia PerformHttpRequest
Envie logs para Discord do FiveM com PerformHttpRequest e embeds JSON. Apenas lado do servidor, URL em uma convar, uma fila para rate limits, e o que registrar.
Você quer saber quem comprou o quê, quem deu dinheiro, quem executou um comando de admin e quem entrou, sem observar o console o dia todo. Um webhook Discord faz isso: seu servidor envia uma mensagem para um canal. Este guia mostra o Lua do lado do servidor com PerformHttpRequest, como construir embeds, como manter a URL segura e como evitar o rate limit.
Crie o webhook
No Discord, abra as configurações do canal, depois Integrações, depois Webhooks, crie um e copie sua URL. Parece https://discord.com/api/webhooks/<id>/<token>. Qualquer um com essa URL pode postar no seu canal, então trate-a como uma senha.
Mantenha a URL em uma convar
Coloque em server.cfg:
set discord_webhook_logs "https://discord.com/api/webhooks/ID/TOKEN"Use set, não setr ou sets. Uma convar replicada é enviada para cada cliente, o que vazaria a URL. Leia-a no servidor:
local WEBHOOK = GetConvar('discord_webhook_logs', '')Se a convar estiver vazia, pule enviando em vez de errar. Você pode manter uma convar por tipo de log (dinheiro, admin, entradas) para enviá-las para canais diferentes.
Envie uma mensagem
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',
})
endPontos a saber:
coloré um número decimal, não uma string hex.3447003é azul e15158332é vermelho. Converta hex comtonumber('FF0000', 16).timestampdeve ser uma data ISO 8601 em UTC. O!no formato fazos.dateusar UTC.fieldsé uma lista de{ name = '...', value = '...', inline = true }. Um valor de field não pode estar vazio.- Uma chamada webhook bem-sucedida retorna status 204, com um corpo vazio.
- Discord limita tamanhos. Títulos são curtos (256 caracteres), descrições são longas mas limitadas (4096), e uma mensagem contém um número limitado de fields e embeds. Corte texto longo antes de enviar.
Um exemplo de chamada, para um jogador que enviou dinheiro:
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 },
})Apenas lado do servidor, nunca do cliente
Atenção: não chame
PerformHttpRequestpara um webhook em um script cliente, e não envie a URL para o cliente. Arquivos cliente podem ser lidos por cada jogador, então a URL vaza e qualquer um pode inundar seu canal.
Se um evento no cliente deve ser registrado, envie um evento para o servidor, e deixe o servidor decidir o que registrar de dados que confia. Um cliente que pode disparar "log this text" também pode disparar logs falsos. Para segurança de eventos em geral, leia secure events in FiveM. Registre o que o servidor fez, não o que o cliente diz que fez.
Rate limits: use uma fila
Discord rejeita chamadas de webhook que chegam muito rápido, com uma resposta 429. Uma explosão de logs, como 50 jogadores disparando o mesmo evento, pode acertá-la. Envie as mensagens de uma fila em um ritmo constante:
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)Esperar dois segundos entre mensagens fica sob o limite. Se você precisa mais, agrupe vários embeds em uma mensagem: uma request pode levar até 10 embeds em sua lista embeds. Para o uso de Wait, veja Wait explained.
O que registrar
Registre os eventos que você gostaria quando algo dá errado:
- Dinheiro: transferências grandes, compras, qualquer coisa que crie dinheiro. Isto é onde abuso mostra primeiro.
- Ações de admin: quem usou qual comando de admin em quem, bans, avisos, teleports. Veja ban and warn players.
- Entradas e saídas, com os identificadores do jogador, o que ajuda com disputas e bans.
- Spawning de item e uso de arma, se você as permite.
Não registre tudo. Um canal com uma mensagem a cada segundo é um canal que ninguém lê. Escolha alguns canais, coloque os importantes onde staff olha, e mantenha o resto curto. Mantenha dados pessoais ao que você precisa, e não registre chat privado.
Dica: coloque sua função de logging em um pequeno recurso e chame-a com uma export de seus outros scripts, para que a URL do webhook e a fila de rate limit vivam em um lugar. Veja exports in FiveM.
Checklist
| Sintoma | Solução |
|---|---|
| Nada chega | Verifique o nome da convar, que a URL está completa e que a chamada roda no servidor |
| Status 400 | O JSON é inválido: valor de field vazio, texto muito longo, ou uma string de cor hex |
| Status 429 | Envie através de uma fila com uma pausa entre mensagens |
| Timestamp ignorado | Use UTC ISO 8601: os.date('!%Y-%m-%dT%H:%M:%SZ') |
| URL vazada | Delete o webhook no Discord, crie um novo, e mantenha em uma convar set |
| Muitas mensagens | Registre apenas dinheiro, ações de admin e entradas |
Respostas rápidas
Posso enviar um webhook Discord do cliente?
Não. Qualquer um pode ler código cliente e roubar a URL do webhook, depois spammar seu canal. Acione o log no servidor e envie de lá.
Quantas mensagens de webhook posso enviar?
Discord limita webhooks, e aproximadamente 30 mensagens por minuto por webhook é um teto seguro. Além disso, você obtém uma resposta 429, então enfileire suas mensagens e envie-as em um ritmo constante.
Onde devo manter a URL do webhook?
Em uma convar de servidor definida com set em server.cfg, leia com GetConvar. Nunca coloque em um arquivo cliente ou em uma convar definida com setr ou sets.
Scripts sem esse problema
Advanced BoostingBoosting de veículos pelo tablet: contratos da classe D à S+, crews e fila ao vivo.Ver script →
Crypto MiningCompre um galpão, monte rigs peça por peça e minere moedas num mercado que se mexe.Ver script →
Shop CreatorMonte uma loja em menos de um minuto — donos, funcionários, cofres e assaltos inclusos.Ver script →