mirror of
https://github.com/yogstation13/Yogstation.git
synced 2025-02-26 09:04:50 +00:00
* Refactor several log lines to use datum_info_line and atom_loc_line * Add default return strings from datum_info_line and atom_loc_line * Add parentheses around atom_loc_line data * Change more logs to use atom_loc_line * Add check in atom_loc_line for turfs to avoid calling get_turf on them * Re-add removed 'at' * Replace datum_info_line with key_name and atom_loc_line with loc_name * Refactor logging functions * Avoid double-logging self-interactions * Fallback to simple stringification if all else fails in key_name() * Rewrite muscle spasm logging to use log_message * Standardize logging of martial arts * Tweak individual logging panel look * Fix individual logging panel source * When I typed || I really meant && * Fix Telecomms logging always showing client logs in the panel * Reverts addition of buggy ownership log to panel * Remove colon * Fix missing log_directed_talk tag * Add warning for missing type in log_direted_talk * Change warnings to stack_traces * Add square brackets around fallthrough key_name() case to help parsing * Allow atom arguments/src in log_*() functions * Change log_combat call with null argument to log_message * Change mecha types' log_message() arguments to match atom and mob version * Add key_name() case for atoms * Fix resist_grab() unsetting pulledby before log_combat gets a chance to use it * Fix log_globally logic * Add logging for hitting objects with items * Move log_combat() to atoms.dm * Use utility functions for object stringification in log_combat() * Use utility functions for object stringification in log_combat() * Add missing logs for interacting with display cases * Rewrite log_combat() comment * Add missing space in log_combat() * Add logging for hitting grilles barehanded * Add missing ..()
132 lines
4.9 KiB
Plaintext
132 lines
4.9 KiB
Plaintext
GLOBAL_VAR_INIT(total_runtimes, GLOB.total_runtimes || 0)
|
|
GLOBAL_VAR_INIT(total_runtimes_skipped, 0)
|
|
|
|
#ifdef DEBUG
|
|
|
|
#define ERROR_USEFUL_LEN 2
|
|
|
|
/world/Error(exception/E, datum/e_src)
|
|
GLOB.total_runtimes++
|
|
|
|
if(!istype(E)) //Something threw an unusual exception
|
|
log_world("uncaught runtime error: [E]")
|
|
return ..()
|
|
|
|
//this is snowflake because of a byond bug (ID:2306577), do not attempt to call non-builtin procs in this if
|
|
if(copytext(E.name,1,32) == "Maximum recursion level reached")
|
|
//log to world while intentionally triggering the byond bug.
|
|
log_world("runtime error: [E.name]\n[E.desc]")
|
|
//if we got to here without silently ending, the byond bug has been fixed.
|
|
log_world("The bug with recursion runtimes has been fixed. Please remove the snowflake check from world/Error in [__FILE__]:[__LINE__]")
|
|
return //this will never happen.
|
|
|
|
if (islist(stack_trace_storage))
|
|
for (var/line in splittext(E.desc, "\n"))
|
|
if (text2ascii(line) != 32)
|
|
stack_trace_storage += line
|
|
|
|
var/static/list/error_last_seen = list()
|
|
var/static/list/error_cooldown = list() /* Error_cooldown items will either be positive(cooldown time) or negative(silenced error)
|
|
If negative, starts at -1, and goes down by 1 each time that error gets skipped*/
|
|
|
|
if(!error_last_seen) // A runtime is occurring too early in start-up initialization
|
|
return ..()
|
|
|
|
var/erroruid = "[E.file][E.line]"
|
|
var/last_seen = error_last_seen[erroruid]
|
|
var/cooldown = error_cooldown[erroruid] || 0
|
|
|
|
if(last_seen == null)
|
|
error_last_seen[erroruid] = world.time
|
|
last_seen = world.time
|
|
|
|
if(cooldown < 0)
|
|
error_cooldown[erroruid]-- //Used to keep track of skip count for this error
|
|
GLOB.total_runtimes_skipped++
|
|
return //Error is currently silenced, skip handling it
|
|
//Handle cooldowns and silencing spammy errors
|
|
var/silencing = FALSE
|
|
|
|
// We can runtime before config is initialized because BYOND initialize objs/map before a bunch of other stuff happens.
|
|
// This is a bunch of workaround code for that. Hooray!
|
|
var/configured_error_cooldown
|
|
var/configured_error_limit
|
|
var/configured_error_silence_time
|
|
if(config && config.entries)
|
|
configured_error_cooldown = CONFIG_GET(number/error_cooldown)
|
|
configured_error_limit = CONFIG_GET(number/error_limit)
|
|
configured_error_silence_time = CONFIG_GET(number/error_silence_time)
|
|
else
|
|
var/datum/config_entry/CE = /datum/config_entry/number/error_cooldown
|
|
configured_error_cooldown = initial(CE.config_entry_value)
|
|
CE = /datum/config_entry/number/error_limit
|
|
configured_error_limit = initial(CE.config_entry_value)
|
|
CE = /datum/config_entry/number/error_silence_time
|
|
configured_error_silence_time = initial(CE.config_entry_value)
|
|
|
|
|
|
//Each occurence of a unique error adds to its cooldown time...
|
|
cooldown = max(0, cooldown - (world.time - last_seen)) + configured_error_cooldown
|
|
// ... which is used to silence an error if it occurs too often, too fast
|
|
if(cooldown > configured_error_cooldown * configured_error_limit)
|
|
cooldown = -1
|
|
silencing = TRUE
|
|
spawn(0)
|
|
usr = null
|
|
sleep(configured_error_silence_time)
|
|
var/skipcount = abs(error_cooldown[erroruid]) - 1
|
|
error_cooldown[erroruid] = 0
|
|
if(skipcount > 0)
|
|
SEND_TEXT(world.log, "\[[time_stamp()]] Skipped [skipcount] runtimes in [E.file],[E.line].")
|
|
GLOB.error_cache.log_error(E, skip_count = skipcount)
|
|
|
|
error_last_seen[erroruid] = world.time
|
|
error_cooldown[erroruid] = cooldown
|
|
|
|
var/list/usrinfo = null
|
|
var/locinfo
|
|
if(istype(usr))
|
|
usrinfo = list(" usr: [key_name(usr)]")
|
|
locinfo = loc_name(usr)
|
|
if(locinfo)
|
|
usrinfo += " usr.loc: [locinfo]"
|
|
// The proceeding mess will almost definitely break if error messages are ever changed
|
|
var/list/splitlines = splittext(E.desc, "\n")
|
|
var/list/desclines = list()
|
|
if(LAZYLEN(splitlines) > ERROR_USEFUL_LEN) // If there aren't at least three lines, there's no info
|
|
for(var/line in splitlines)
|
|
if(LAZYLEN(line) < 3 || findtext(line, "source file:") || findtext(line, "usr.loc:"))
|
|
continue
|
|
if(findtext(line, "usr:"))
|
|
if(usrinfo)
|
|
desclines.Add(usrinfo)
|
|
usrinfo = null
|
|
continue // Our usr info is better, replace it
|
|
|
|
if(copytext(line, 1, 3) != " ")
|
|
desclines += (" " + line) // Pad any unpadded lines, so they look pretty
|
|
else
|
|
desclines += line
|
|
if(usrinfo) //If this info isn't null, it hasn't been added yet
|
|
desclines.Add(usrinfo)
|
|
if(silencing)
|
|
desclines += " (This error will now be silenced for [DisplayTimeText(configured_error_silence_time)])"
|
|
if(GLOB.error_cache)
|
|
GLOB.error_cache.log_error(E, desclines)
|
|
|
|
var/main_line = "\[[time_stamp()]] Runtime in [E.file],[E.line]: [E]"
|
|
SEND_TEXT(world.log, main_line)
|
|
for(var/line in desclines)
|
|
SEND_TEXT(world.log, line)
|
|
|
|
#ifdef UNIT_TESTS
|
|
if(GLOB.current_test)
|
|
//good day, sir
|
|
GLOB.current_test.Fail("[main_line]\n[desclines.Join("\n")]")
|
|
#endif
|
|
|
|
|
|
// This writes the regular format (unwrapping newlines and inserting timestamps as needed).
|
|
log_runtime("runtime error: [E.name]\n[E.desc]")
|
|
|
|
#endif |