Skip to content

Commit

Permalink
Use new OnLuaError hook (#38)
Browse files Browse the repository at this point in the history
  • Loading branch information
brandonsturgeon committed Jan 20, 2024
1 parent 1d95ee8 commit 21b62fa
Show file tree
Hide file tree
Showing 9 changed files with 324 additions and 81 deletions.
26 changes: 20 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,20 @@ A pure-lua (well, Moonscript) Error tracker for Garry's Mod.

This addon will watch for errors, do a little investigation, and send a message to a Discord channel for your review.

### Who is this for?
This is for Server Owners/Operators. This allows server operators to monitor and manage the errors that occur on their server.

### Who is this **not** for?
Addon developers looking for a way to track their errors automatically across all servers - this is not the tool for you.

<br>

## Notice ⚠️
A full-rewrite of this addon is nearly complete. It has fixes, new features, design reworks, and will attempt to use the upcoming [`OnLuaError`](https://wiki.facepunch.com/gmod/GM:OnLuaError) hook.
A full-rewrite of this addon is nearly complete. It has fixes, new features, design reworks, discord ratelimit prevention, reliability improvements, and more.

Please keep an eye out for the update!

You can track its progress in our support Discord: https://discord.gg/5JUqZjzmYJ
You can track its progress _(or ask questions)_ in our support Discord: https://discord.gg/5JUqZjzmYJ

<br>

Expand All @@ -21,9 +27,9 @@ You can track its progress in our support Discord: https://discord.gg/5JUqZjzmYJ
- 🔎 Shows you the current values of up to 8 local variables in the stack that threw an error (very useful for debugging!)

## Requirements
- [gm_logger](https://github.com/CFC-Servers/gm_logger) _(Optional)_
- [gm_luaerror](https://github.com/danielga/gm_luaerror)
- [gmsv_reqwest](https://github.com/WilliamVenner/gmsv_reqwest)
- [gmsv_reqwest](https://github.com/WilliamVenner/gmsv_reqwest) **Required**
- [gm_luaerror](https://github.com/danielga/gm_luaerror) _(Optional)_
- Add this module if you want more information about serverside errors, such as locals at the time of error


## Installation
Expand All @@ -40,6 +46,7 @@ You can track its progress in our support Discord: https://discord.gg/5JUqZjzmYJ
- **`cfc_err_forwarder_server_webhook`**: The full Discord Webhook URL to send Serverside errors
- **`cfc_err_forwarder_client_webhook`**: The full Discord Webhook URL to send Clientside errors
- **`cfc_err_forwarder_client_enabled`**: A boolean indicating whether or not the addon should even track Clientside errors
- **`cfc_err_forwarder_bucket_size`**: Client -> Server rate limiting bucket size. (Only applies when not using the luaerror dll)

## Screenshots

Expand Down Expand Up @@ -93,6 +100,13 @@ The error structure would look like:
| `reportInterval` | `number` | `60` | In seconds, how often the addon is sending errors to Discord |
| `sourceFile` | `string` | `"addons/test/lua/example/init.lua"` | The file path where the error occurred |
| `sourceLine` | `number` | `4` | The line in the file where the error occurred |
| `stack` | `table` | `{ 1 = { currentLine = 4, name = "unknown", source = "..." }, ... }` | A numerically indexed Stack object |
| `stack` | `table` | `{ 1 = { currentline = 4, name = "unknown", source = "..." }, ... }` | A numerically indexed Stack object |

<br>

### `CFC_ErrorForwarder_OnReceiveCLError`
This hook is only called when the `luaerror` dll is not installed.

This hook is called in the network receiver that is triggered when a player forwards their error to the server.

Return `false` to prevent it from being processed.
18 changes: 17 additions & 1 deletion moon/autorun/client/cfc_err_fwd.moon
Original file line number Diff line number Diff line change
@@ -1,4 +1,20 @@
hook.Add "InitPostEntity", "CFC_ErrForwarder_BranchInit", ->
hook.Add "Think", "CFC_ErrForwarder_BranchInit", ->
hook.Remove "Think", "CFC_ErrForwarder_BranchInit"
net.Start "cfc_err_forwarder_clbranch"
net.WriteString BRANCH
net.SendToServer!

hook.Add "OnLuaError", "CFC_ErrForwarder_OnLuaError", (errorString, _, stack) ->
net.Start "cfc_err_forwarder_clerror"
net.WriteString errorString

stackCount = math.min #stack, 7
net.WriteUInt stackCount, 8

for i = 1, stackCount
level = stack[i]
net.WriteString level.File
net.WriteString level.Function
net.WriteString level.Line

net.SendToServer!
48 changes: 25 additions & 23 deletions moon/autorun/server/cfc_err_fwd.moon
Original file line number Diff line number Diff line change
@@ -1,16 +1,20 @@
require "luaerror"
require "reqwest"

useErrorModule = false
if util.IsBinaryModuleInstalled "luaerror"
require "luaerror"
luaerror.EnableCompiletimeDetour true
luaerror.EnableClientDetour true
luaerror.EnableRuntimeDetour true
useErrorModule = true

util.AddNetworkString "cfc_err_forwarder_clbranch"
util.AddNetworkString "cfc_err_forwarder_clerror"

timerName = "CFC_ErrorForwarderQueue"
errorForwarder = include "cfc_err_forwarder/error_forwarder.lua"
discordBuilder = include "cfc_err_forwarder/discord_interface.lua"

luaerror.EnableCompiletimeDetour true
luaerror.EnableClientDetour true
luaerror.EnableRuntimeDetour true

convarPrefix = "cfc_err_forwarder"
convarFlags = FCVAR_ARCHIVE + FCVAR_PROTECTED
makeConfig = (name, value, help) -> CreateConVar "#{convarPrefix}_#{name}", value, convarFlags, help
Expand All @@ -22,28 +26,23 @@ Config =
-- cfc_err_forwarder_client_enabled
clientEnabled: makeConfig "client_enabled", "1", "Whether or not to track and forward Clientside errors"

bucketSize: makeConfig "bucket_size", "5", "Client -> Server rate limiting bucket size. (Only applies to clientside errors when not using the luaerror dll)"

webhook:
-- cfc_err_forwarder_client_webhook
client: makeConfig "client_webhook", "", "Discord Webhook URL"

-- cfc_err_forwarder_server_webhook
server: makeConfig "server_webhook", "", "Discord Webhook URL"

local logger
if file.Exists "includes/modules/logger.lua", "LUA"
require "logger"
logger = Logger "ErrorForwarder"
else
log = (...) -> print "[ErrorForwarder]", ...
log "GM_Logger not found, using backup logger. Consider installing: github.com/CFC-Servers/gm_logger"
log = (...) => print "[ErrorForwarder]", ...
logger =
trace: ->
debug: ->
info: log
warn: log
error: log

logger =
trace: ->
debug: ->
info: log
warn: log
error: log


Discord = discordBuilder Config
ErrorForwarder = errorForwarder logger, Discord, Config
Expand All @@ -56,11 +55,14 @@ timer.Create timerName, Config.groomInterval\GetInt! or 60, 0, ->
cvars.AddChangeCallback "cfc_err_forwarder_interval", (_, _, value) ->
timer.Adjust timerName, tonumber(value), "UpdateTimer"

hook.Add "LuaError", "CFC_ServerErrorForwarder", ErrorForwarder\receiveSVError
hook.Add "ClientLuaError", "CFC_ClientErrorForwarder", ErrorForwarder\receiveCLError
hook.Add "ShutDown", "CFC_ShutdownErrorForwarder", ErrorForwarder\forwardErrors
if useErrorModule
hook.Add "LuaError", "CFC_ServerErrorForwarder", ErrorForwarder\receiveSVError
hook.Add "ClientLuaError", "CFC_ClientErrorForwarder", ErrorForwarder\receiveCLError
else
include("cfc_err_forwarder/plain_receiver.lua") logger, ErrorForwarder, Config

net.Receive "cfc_err_forwarder_clbranch", (_,ply) ->
hook.Add "ShutDown", "CFC_ShutdownErrorForwarder", ErrorForwarder\forwardErrors
net.Receive "cfc_err_forwarder_clbranch", (_, ply) ->
if not ply.CFC_ErrorForwarder_CLBranch
ply.CFC_ErrorForwarder_CLBranch = net.ReadString!

Expand Down
26 changes: 12 additions & 14 deletions moon/cfc_err_forwarder/error_forwarder.moon
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
import Count from table

osTime = os.time
rawset = rawset
rawget = rawget
istable = istable

pretty = include "cfc_err_forwarder/formatter/pretty_values.lua"
Expand Down Expand Up @@ -71,10 +69,10 @@ return class ErrorForwarder

countQueue: => Count @queue

errorIsQueued: (fullError) => rawget(@queue, fullError) ~= nil
errorIsQueued: (fullError) => @queue[fullError] ~= nil

addPlyToObject: (errorStruct, ply) =>
rawset errorStruct, "player", {
errorStruct.player = {
playerName: ply\Name!,
playerSteamID: ply\SteamID!
}
Expand Down Expand Up @@ -122,23 +120,23 @@ return class ErrorForwarder

@logger\debug "Inserting error into queue: '#{fullError}'"

rawset @queue, fullError, newError
@queue[fullError] = newError

unqueueError: (fullError) =>
thisErr = rawget @queue, fullError
thisErr = @queue[fullError]

if thisErr
for k in pairs thisErr
rawset thisErr, k, nil
thisErr[k] = nil

rawset @queue, fullError, nil
@queue[fullError] = nil

incrementError: (fullError) =>
thisErr = rawget @queue, fullError
count = rawget thisErr, "count"
thisErr = @queue[fullError]
count = thisErr.count

rawset thisErr, "count", count + 1
rawset thisErr, "occurredAt", osTime!
thisErr.count = count + 1
thisErr.occurredAt = osTime!

receiveError: (isRuntime, fullError, sourceFile, sourceLine, errorString, stack, ply) =>
if @errorIsQueued fullError
Expand All @@ -147,7 +145,7 @@ return class ErrorForwarder
@queueError isRuntime, fullError, sourceFile, sourceLine, errorString, stack, ply

logErrorInfo: (isRuntime, fullError, sourceFile, sourceLine, errorString, stack) =>
debug = @logger\debug
debug = @logger\info

debug "Is Runtime: #{isRuntime}"
debug "Full Error: #{fullError}"
Expand All @@ -170,7 +168,7 @@ return class ErrorForwarder

@receiveError true, fullError, sourceFile, sourceLine, errorString, stack, ply

-- TODO: Remove this stupid thing andc all stripStack directly
-- TODO: Remove this stupid thing and call stripStack directly
cleanStruct: (errorStruct) =>
stripStack errorStruct.stack
return errorStruct
Expand Down
12 changes: 6 additions & 6 deletions moon/cfc_err_forwarder/formatter/formatter.moon
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
red = 14483456
clientColor = 14592265
serverColor = 240116
locals = include "locals.lua"
niceStack = include "nice_stack.lua"

Expand All @@ -18,15 +19,14 @@ nonil = (t) -> [v for v in *t when v ~= nil]
content: ""
embeds: {
{
color: red
color: client and clientColor or serverColor
title: "#{realm} Error"
author: name: GetHostName!
description: bad data.errorString
fields: nonil {
{
name: "Source File"
value: getSourceText data
}
with source = getSourceText data
return { name: "Source File", value: source } if source
return nil

{
name: "Full Error"
Expand Down

0 comments on commit 21b62fa

Please sign in to comment.