From 54a6e5713e292092221f09665de051044802384d Mon Sep 17 00:00:00 2001 From: Manason Date: Sun, 3 Dec 2023 15:13:48 -0800 Subject: [PATCH] feat(modules): added logger --- modules/logger.lua | 156 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 156 insertions(+) create mode 100644 modules/logger.lua diff --git a/modules/logger.lua b/modules/logger.lua new file mode 100644 index 000000000..27831cf84 --- /dev/null +++ b/modules/logger.lua @@ -0,0 +1,156 @@ +local isServer = IsDuplicityVersion() +if not isServer then + lib.print.error('cannot use the logger on the client') + return +end + +local logQueue, isProcessingQueue, logCount = {}, false, 0 +local lastRequestTime, requestDelay = 0, 0 + +---@enum Colors +local Colors = { -- https://www.spycolor.com/ + default = 14423100, + blue = 255, + red = 16711680, + green = 65280, + white = 16777215, + black = 0, + orange = 16744192, + yellow = 16776960, + pink = 16761035, + lightgreen = 65309, +} + +---Log Queue +local function applyRequestDelay() + local currentTime = GetGameTimer() + local timeDiff = currentTime - lastRequestTime + + if timeDiff < requestDelay then + local remainingDelay = requestDelay - timeDiff + + Wait(remainingDelay) + end + + lastRequestTime = GetGameTimer() +end + +local allowedErr = { + [200] = true, + [201] = true, + [204] = true, + [304] = true +} + +---Log Queue +---@param payload Log Queue +local function logPayload(payload) + local tags + + if payload.tags then + for i = 1, #payload.tags do + if not tags then tags = '' end + tags = tags .. payload.tags[i] + end + end + + PerformHttpRequest(payload.webhook, function(err, _, headers) + if err and not allowedErr[err] then + lib.print.error('can\'t send log to discord', err) + return + end + + local remainingRequests = tonumber(headers["X-RateLimit-Remaining"]) + local resetTime = tonumber(headers["X-RateLimit-Reset"]) + + if remainingRequests and resetTime and remainingRequests == 0 then + local currentTime = os.time() + local resetDelay = resetTime - currentTime + + if resetDelay > 0 then + requestDelay = resetDelay * 1000 / 10 + end + end + end, 'POST', json.encode({content = tags, embeds = payload.embed}), { ['Content-Type'] = 'application/json' }) +end + +---Log Queue +local function processLogQueue() + if #logQueue > 0 then + local payload = table.remove(logQueue, 1) + + logPayload(payload) + + logCount += 1 + + if logCount % 5 == 0 then + Wait(60000) + else + applyRequestDelay() + end + + processLogQueue() + else + isProcessingQueue = false + end +end + +---@class DiscordLog +---@field source string source of the log. Usually a playerId or name of a resource. +---@field event string the action or 'event' being logged. Usually a verb describing what the name is doing. Example: SpawnVehicle +---@field message string the message attached to the log +---@field webhook string url of the webhook this log should send to +---@field color? string what color the message should be +---@field tags? string[] tags in discord. Example: ['@admin', '@everyone'] + +---Creates a discord log +---@param log DiscordLog +local function discordLog(log) + local embedData = { + { + title = log.event, + color = Colors[log.color] or Colors.default, + footer = { + text = os.date('%H:%M:%S %m-%d-%Y'), + }, + description = log.message, + author = { + name = 'QBX Logs', + }, + } + } + + logQueue[#logQueue + 1] = { + webhook = log.webhook, + tags = log.tags, + embed = embedData + } + + if not isProcessingQueue then + isProcessingQueue = true + CreateThread(processLogQueue) + end +end + +---@class Log +---@field source string source of the log. Usually a playerId or name of a resource. +---@field event string the action or 'event' being logged. Usually a verb describing what the name is doing. Example: SpawnVehicle +---@field message string the message attached to the log +---@field webhook? string Discord logs only. url of the webhook this log should send to +---@field color? string Discord logs only. what color the message should be +---@field tags? string[] Discord logs only. tags in discord. Example: ['@admin', '@everyone'] + +---Creates a log using either ox_lib logger, discord webhooks depending on convar +---@param log Log +local function createLog(log) + if log.webhook then + ---@diagnostic disable-next-line: param-type-mismatch + discordLog(log) + else + lib.logger(log.source, log.event, log.message) + end +end + +return { + log = createLog +} \ No newline at end of file