mirror of
https://github.com/Bubberstation/Bubberstation.git
synced 2026-08-23 21:18:37 +01:00
JSON Logging Take Two (#73604)
## About The Pull Request Converts all logging, excluding perf and investigate, to json. I focused on making the system as easy to use and as easy to add new categories as possible. Due to issues related to logging to world at global creation logger is now a byond real, which is created directly before Master Log categories support versioning, secret flagging, and sub-category filtering. Although all of this is entirely optional for coders. If you ever want to add a new category and use it, all you need to do is make the barebones category datum and the define. I've kept existing procs such as log_game, and simply turned them into a wrapper for Logger.Log(xxx, ...) ## Why It's Good For The Game Makes processing and filtering logs much easier in the future, while only minimally downgrading log crawling experience. I am also working on a log viewer frontend for admin usage however that will take a little bit longer to finish up. Also makes special logging and data tracking much easier thanks to a data list processing implementation and handling ## Changelog 🆑 server: All logs are now formatted in json, excluding perf and investigations /🆑 --------- Signed-off-by: GitHub <noreply@github.com> Co-authored-by: tattle <66640614+dragomagol@users.noreply.github.com> Co-authored-by: Kyle Spier-Swenson <kyleshome@gmail.com> Co-authored-by: GoldenAlpharex <58045821+GoldenAlpharex@users.noreply.github.com>
This commit is contained in:
co-authored by
tattle
Kyle Spier-Swenson
GoldenAlpharex
parent
3df5d3b42b
commit
fbec9c14e9
@@ -1,4 +1,4 @@
|
||||
///Protects a datum from being VV'd
|
||||
///Protects a datum from being VV'd or spawned through admin manipulation
|
||||
#define GENERAL_PROTECT_DATUM(Path)\
|
||||
##Path/can_vv_get(var_name){\
|
||||
return FALSE;\
|
||||
@@ -8,4 +8,10 @@
|
||||
}\
|
||||
##Path/CanProcCall(procname){\
|
||||
return FALSE;\
|
||||
}\
|
||||
##Path/Read(savefile/savefile){\
|
||||
qdel(src);\
|
||||
}\
|
||||
##Path/Write(savefile/savefile){\
|
||||
return;\
|
||||
}
|
||||
|
||||
+84
-13
@@ -55,24 +55,95 @@
|
||||
#define LOGSRC_MOB "Mob"
|
||||
|
||||
// Log header keys
|
||||
#define LOG_HEADER_CATEGORY "category"
|
||||
#define LOG_HEADER_INIT_TIMESTAMP "timestamp"
|
||||
#define LOG_HEADER_ROUND_ID "round_id"
|
||||
|
||||
// Log data keys
|
||||
#define LOG_ENTRY_MESSAGE "message"
|
||||
#define LOG_ENTRY_TIMESTAMP "timestamp"
|
||||
#define LOG_ENTRY_DATA "data"
|
||||
#define LOG_HEADER_CATEGORY "cat"
|
||||
#define LOG_HEADER_CATEGORY_LIST "cat-list"
|
||||
#define LOG_HEADER_INIT_TIMESTAMP "ts"
|
||||
#define LOG_HEADER_ROUND_ID "round-id"
|
||||
#define LOG_HEADER_SECRET "secret"
|
||||
|
||||
// Log json keys
|
||||
#define LOG_JSON_CATEGORY "category"
|
||||
#define LOG_JSON_CATEGORY "cat"
|
||||
#define LOG_JSON_ENTRIES "entries"
|
||||
#define LOG_JSON_LOGGING_START "log_start"
|
||||
#define LOG_JSON_LOGGING_START "log-start"
|
||||
|
||||
// Log categories
|
||||
#define LOG_CATEGORY_NOT_FOUND "invalid_category"
|
||||
#define LOG_CATEGORY_TARGET_ZONE_SWITCH "target_zone_switch"
|
||||
// Category for invalid/missing categories
|
||||
#define LOG_CATEGORY_NOT_FOUND "invalid-category"
|
||||
|
||||
// Misc categories
|
||||
#define LOG_CATEGORY_ATTACK "attack"
|
||||
#define LOG_CATEGORY_CONFIG "config"
|
||||
#define LOG_CATEGORY_DYNAMIC "dynamic"
|
||||
#define LOG_CATEGORY_ECONOMY "economy"
|
||||
#define LOG_CATEGORY_FILTER "filter"
|
||||
#define LOG_CATEGORY_MANIFEST "manifest"
|
||||
#define LOG_CATEGORY_MECHA "mecha"
|
||||
#define LOG_CATEGORY_PAPER "paper"
|
||||
#define LOG_CATEGORY_RUNTIME "runtime"
|
||||
#define LOG_CATEGORY_SHUTTLE "shuttle"
|
||||
#define LOG_CATEGORY_SILICON "silicon"
|
||||
#define LOG_CATEGORY_SILO "silo"
|
||||
#define LOG_CATEGORY_SIGNAL "signal"
|
||||
#define LOG_CATEGORY_SPEECH_INDICATOR "speech-indiciator"
|
||||
#define LOG_CATEGORY_SUSPICIOUS_LOGIN "supicious-login"
|
||||
#define LOG_CATEGORY_TARGET_ZONE_SWITCH "target-zone-switch"
|
||||
#define LOG_CATEGORY_TELECOMMS "telecomms"
|
||||
#define LOG_CATEGORY_TOOL "tool"
|
||||
#define LOG_CATEGORY_VIRUS "virus"
|
||||
|
||||
// Admin categories
|
||||
#define LOG_CATEGORY_ADMIN "admin"
|
||||
#define LOG_CATEGORY_ADMIN_CIRCUIT "admin-circuit"
|
||||
#define LOG_CATEGORY_ADMIN_DSAY "admin-dsay"
|
||||
|
||||
// Admin private categories
|
||||
#define LOG_CATEGORY_ADMIN_PRIVATE "adminprivate"
|
||||
#define LOG_CATEGORY_ADMIN_PRIVATE_ASAY "adminprivate-asay"
|
||||
|
||||
// Debug categories
|
||||
#define LOG_CATEGORY_DEBUG "debug"
|
||||
#define LOG_CATEGORY_DEBUG_ASSET "debug-asset"
|
||||
#define LOG_CATEGORY_DEBUG_HREF "debug-href"
|
||||
#define LOG_CATEGORY_DEBUG_JOB "debug-job"
|
||||
#define LOG_CATEGORY_DEBUG_LUA "debug-lua"
|
||||
#define LOG_CATEGORY_DEBUG_MAPPING "debug-mapping"
|
||||
#define LOG_CATEGORY_DEBUG_MOBTAG "debug-mobtag"
|
||||
#define LOG_CATEGORY_DEBUG_QDEL "debug-qdel"
|
||||
#define LOG_CATEGORY_DEBUG_SQL "debug-sql"
|
||||
#define LOG_CATEGORY_DEBUG_TGUI "debug-tgui"
|
||||
|
||||
// Compatibility categories, for when stuff is changed and you need existing functionality to work
|
||||
#define LOG_CATEGORY_COMPAT_GAME "game-compat"
|
||||
|
||||
// Game categories
|
||||
#define LOG_CATEGORY_GAME "game"
|
||||
#define LOG_CATEGORY_GAME_ACCESS "game-access"
|
||||
#define LOG_CATEGORY_GAME_EMOTE "game-emote"
|
||||
#define LOG_CATEGORY_GAME_INTERNET_REQUEST "game-internet-request"
|
||||
#define LOG_CATEGORY_GAME_OOC "game-ooc"
|
||||
#define LOG_CATEGORY_GAME_PRAYER "game-prayer"
|
||||
#define LOG_CATEGORY_GAME_RADIO_EMOTE "game-radio-emote"
|
||||
#define LOG_CATEGORY_GAME_SAY "game-say"
|
||||
#define LOG_CATEGORY_GAME_TOPIC "game-topic"
|
||||
#define LOG_CATEGORY_GAME_TRAITOR "game-traitor"
|
||||
#define LOG_CATEGORY_GAME_VOTE "game-vote"
|
||||
#define LOG_CATEGORY_GAME_WHISPER "game-whisper"
|
||||
|
||||
// Uplink categories
|
||||
#define LOG_CATEGORY_UPLINK "uplink"
|
||||
#define LOG_CATEGORY_UPLINK_CHANGELING "uplink-changeling"
|
||||
#define LOG_CATEGORY_UPLINK_HERETIC "uplink-heretic"
|
||||
#define LOG_CATEGORY_UPLINK_MALF "uplink-malf"
|
||||
#define LOG_CATEGORY_UPLINK_SPELL "uplink-spell"
|
||||
|
||||
// PDA categories
|
||||
#define LOG_CATEGORY_PDA "pda"
|
||||
#define LOG_CATEGORY_PDA_CHAT "pda-chat"
|
||||
#define LOG_CATEGORY_PDA_COMMENT "pda-comment"
|
||||
|
||||
#define SCHEMA_VERSION "schema-version"
|
||||
|
||||
// Default log schema version
|
||||
#define LOG_CATEGORY_SCHEMA_VERSION_NOT_SET "0.0.1"
|
||||
|
||||
//wrapper macros for easier grepping
|
||||
#define DIRECT_OUTPUT(A, B) A << B
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
*/
|
||||
GLOBAL_VAR_INIT(fileaccess_timer, 0)
|
||||
|
||||
/client/proc/browse_files(root_type=BROWSE_ROOT_ALL_LOGS, max_iterations=10, list/valid_extensions=list("txt","log","htm", "html", "gz"))
|
||||
/client/proc/browse_files(root_type=BROWSE_ROOT_ALL_LOGS, max_iterations=10, list/valid_extensions=list("txt","log","htm", "html", "gz", "json"))
|
||||
// wow why was this ever a parameter
|
||||
var/root = "data/logs/"
|
||||
switch(root_type)
|
||||
|
||||
@@ -10,6 +10,31 @@
|
||||
msg = "## NOTICE: [msg]"
|
||||
log_world(msg)
|
||||
|
||||
#define SET_SERIALIZATION_SEMVER(semver_list, semver) semver_list[type] = semver
|
||||
#define CHECK_SERIALIZATION_SEMVER(wanted, actual) (__check_serialization_semver(wanted, actual))
|
||||
|
||||
/// Checks if the actual semver is equal or later than the wanted semver
|
||||
/// Must be passed as TEXT; you're probably looking for CHECK_SERIALIZATION_SEMVER, look right above
|
||||
/proc/__check_serialization_semver(wanted, actual)
|
||||
if(wanted == actual)
|
||||
return TRUE
|
||||
|
||||
var/list/wanted_versions = semver_to_list(wanted)
|
||||
var/list/actual_versions = semver_to_list(actual)
|
||||
|
||||
if(!wanted_versions || !actual_versions)
|
||||
stack_trace("Invalid semver string(s) passed to __check_serialization_semver: '[wanted]' and '[actual]'")
|
||||
return FALSE
|
||||
|
||||
if(wanted_versions[1] != actual_versions[1])
|
||||
return FALSE // major must always
|
||||
|
||||
if(wanted_versions[2] > actual_versions[2])
|
||||
return FALSE // actual must be later than wanted
|
||||
|
||||
// patch is not checked
|
||||
return TRUE
|
||||
|
||||
//print a testing-mode debug message to world.log and world
|
||||
#ifdef TESTING
|
||||
#define testing(msg) log_world("## TESTING: [msg]"); to_chat(world, "## TESTING: [msg]")
|
||||
@@ -128,7 +153,7 @@ GLOBAL_LIST_INIT(testing_global_profiler, list("_PROFILE_NAME" = "Global"))
|
||||
/* Close open log handles. This should be called as late as possible, and no logging should hapen after. */
|
||||
/proc/shutdown_logging()
|
||||
rustg_log_close_all()
|
||||
GLOB.logger.shutdown_logging()
|
||||
logger.shutdown_logging()
|
||||
|
||||
/* Helper procs for building detailed log lines */
|
||||
/proc/key_name(whom, include_link = null, include_name = TRUE)
|
||||
|
||||
@@ -1,33 +1,36 @@
|
||||
/* Items with ADMINPRIVATE prefixed are stripped from public logs. */
|
||||
|
||||
// For backwards compatibility these are currently also added to LOG_CATEGORY_GAME with their respective prefix
|
||||
// This is to avoid breaking any existing tools that rely on the old format, but should be removed in the future
|
||||
|
||||
/// General logging for admin actions
|
||||
/proc/log_admin(text)
|
||||
/proc/log_admin(text, list/data)
|
||||
GLOB.admin_activities.Add(text)
|
||||
if (CONFIG_GET(flag/log_admin))
|
||||
WRITE_LOG(GLOB.world_game_log, "ADMIN: [text]")
|
||||
logger.Log(LOG_CATEGORY_ADMIN, text, data)
|
||||
logger.Log(LOG_CATEGORY_COMPAT_GAME, "ADMIN: [text]")
|
||||
|
||||
/// Logging for admin actions on or with circuits
|
||||
/proc/log_admin_circuit(text)
|
||||
/proc/log_admin_circuit(text, list/data)
|
||||
GLOB.admin_activities.Add(text)
|
||||
if(CONFIG_GET(flag/log_admin))
|
||||
WRITE_LOG(GLOB.world_game_log, "ADMIN: CIRCUIT: [text]")
|
||||
logger.Log(LOG_CATEGORY_ADMIN_CIRCUIT, text, data)
|
||||
logger.Log(LOG_CATEGORY_COMPAT_GAME, "ADMIN: CIRCUIT: [text]")
|
||||
|
||||
/// General logging for admin actions
|
||||
/proc/log_admin_private(text)
|
||||
/proc/log_admin_private(text, list/data)
|
||||
GLOB.admin_activities.Add(text)
|
||||
if (CONFIG_GET(flag/log_admin))
|
||||
WRITE_LOG(GLOB.world_game_log, "ADMINPRIVATE: [text]")
|
||||
logger.Log(LOG_CATEGORY_ADMIN_PRIVATE, text, data)
|
||||
logger.Log(LOG_CATEGORY_COMPAT_GAME, "ADMINPRIVATE: [text]")
|
||||
|
||||
/// Logging for AdminSay (ASAY) messages
|
||||
/proc/log_adminsay(text)
|
||||
/proc/log_adminsay(text, list/data)
|
||||
GLOB.admin_activities.Add(text)
|
||||
if (CONFIG_GET(flag/log_adminchat))
|
||||
WRITE_LOG(GLOB.world_game_log, "ADMINPRIVATE: ASAY: [text]")
|
||||
logger.Log(LOG_CATEGORY_ADMIN_PRIVATE_ASAY, text, data)
|
||||
logger.Log(LOG_CATEGORY_COMPAT_GAME, "ADMINPRIVATE: ASAY: [text]")
|
||||
|
||||
/// Logging for DeachatSay (DSAY) messages
|
||||
/proc/log_dsay(text)
|
||||
if (CONFIG_GET(flag/log_adminchat))
|
||||
WRITE_LOG(GLOB.world_game_log, "ADMIN: DSAY: [text]")
|
||||
/proc/log_dsay(text, list/data)
|
||||
logger.Log(LOG_CATEGORY_ADMIN_DSAY, text, data)
|
||||
logger.Log(LOG_CATEGORY_COMPAT_GAME, "ADMIN: DSAY: [text]")
|
||||
|
||||
/**
|
||||
* Writes to a special log file if the log_suspicious_login config flag is set,
|
||||
@@ -36,8 +39,7 @@
|
||||
* Mirrors this log entry to log_access when access_log_mirror is TRUE, so this proc
|
||||
* doesn't need to be used alongside log_access and can replace it where appropriate.
|
||||
*/
|
||||
/proc/log_suspicious_login(text, access_log_mirror = TRUE)
|
||||
if (CONFIG_GET(flag/log_suspicious_login))
|
||||
WRITE_LOG(GLOB.world_suspicious_login_log, "SUSPICIOUS_ACCESS: [text]")
|
||||
/proc/log_suspicious_login(text, list/data, access_log_mirror = TRUE)
|
||||
logger.Log(LOG_CATEGORY_SUSPICIOUS_LOGIN, text)
|
||||
if(access_log_mirror)
|
||||
log_access(text)
|
||||
|
||||
@@ -1,29 +1,23 @@
|
||||
/// Logging for traitor objectives
|
||||
/proc/log_traitor(text)
|
||||
if (CONFIG_GET(flag/log_traitor))
|
||||
WRITE_LOG(GLOB.world_game_log, "TRAITOR: [text]")
|
||||
/proc/log_traitor(text, list/data)
|
||||
logger.Log(LOG_CATEGORY_GAME_TRAITOR, text, data)
|
||||
|
||||
/// Logging for items purchased from a traitor uplink
|
||||
/proc/log_uplink(text)
|
||||
if (CONFIG_GET(flag/log_uplink))
|
||||
WRITE_LOG(GLOB.world_uplink_log, "UPLINK: [text]")
|
||||
/proc/log_uplink(text, list/data)
|
||||
logger.Log(LOG_CATEGORY_UPLINK, text, data)
|
||||
|
||||
/// Logging for upgrades purchased by a malfunctioning (or combat upgraded) AI
|
||||
/proc/log_malf_upgrades(text)
|
||||
if (CONFIG_GET(flag/log_uplink))
|
||||
WRITE_LOG(GLOB.world_uplink_log, "MALF UPGRADE: [text]")
|
||||
/proc/log_malf_upgrades(text, list/data)
|
||||
logger.Log(LOG_CATEGORY_UPLINK_MALF, text, data)
|
||||
|
||||
/// Logging for changeling powers purchased
|
||||
/proc/log_changeling_power(text)
|
||||
if (CONFIG_GET(flag/log_uplink))
|
||||
WRITE_LOG(GLOB.world_uplink_log, "CHANGELING: [text]")
|
||||
/proc/log_changeling_power(text, list/data)
|
||||
logger.Log(LOG_CATEGORY_UPLINK_CHANGELING, text, data)
|
||||
|
||||
/// Logging for heretic powers learned
|
||||
/proc/log_heretic_knowledge(text)
|
||||
if (CONFIG_GET(flag/log_uplink))
|
||||
WRITE_LOG(GLOB.world_uplink_log, "HERETIC RESEARCH: [text]")
|
||||
/proc/log_heretic_knowledge(text, list/data)
|
||||
logger.Log(LOG_CATEGORY_UPLINK_HERETIC, text, data)
|
||||
|
||||
/// Logging for wizard powers learned
|
||||
/proc/log_spellbook(text)
|
||||
if (CONFIG_GET(flag/log_uplink))
|
||||
WRITE_LOG(GLOB.world_uplink_log, "SPELLBOOK: [text]")
|
||||
/proc/log_spellbook(text, list/data)
|
||||
logger.Log(LOG_CATEGORY_UPLINK_SPELL, text, data)
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
/// Generic attack logging
|
||||
/proc/log_attack(text)
|
||||
if (CONFIG_GET(flag/log_attack))
|
||||
WRITE_LOG(GLOB.world_attack_log, "ATTACK: [text]")
|
||||
/proc/log_attack(text, list/data)
|
||||
logger.Log(LOG_CATEGORY_ATTACK, text)
|
||||
|
||||
/**
|
||||
* Log a combat message in the attack log
|
||||
|
||||
@@ -1,32 +1,30 @@
|
||||
/// Logging for loading and caching assets
|
||||
/proc/log_asset(text)
|
||||
if(CONFIG_GET(flag/log_asset))
|
||||
WRITE_LOG(GLOB.world_asset_log, "ASSET: [text]")
|
||||
/proc/log_asset(text, list/data)
|
||||
logger.Log(LOG_CATEGORY_DEBUG_ASSET, text, data)
|
||||
|
||||
/// Logging for config errors
|
||||
/// Rarely gets called; just here in case the config breaks.
|
||||
/proc/log_config(text)
|
||||
WRITE_LOG(GLOB.config_error_log, text)
|
||||
/proc/log_config(text, list/data)
|
||||
logger.Log(LOG_CATEGORY_CONFIG, text, data)
|
||||
SEND_TEXT(world.log, text)
|
||||
|
||||
/proc/log_filter_raw(text)
|
||||
WRITE_LOG(GLOB.filter_log, "FILTER: [text]")
|
||||
/proc/log_filter_raw(text, list/data)
|
||||
logger.Log(LOG_CATEGORY_FILTER, text, data)
|
||||
|
||||
/// Logging for job slot changes
|
||||
/proc/log_job_debug(text)
|
||||
if (CONFIG_GET(flag/log_job_debug))
|
||||
WRITE_LOG(GLOB.world_job_debug_log, "JOB: [text]")
|
||||
/proc/log_job_debug(text, list/data)
|
||||
logger.Log(LOG_CATEGORY_DEBUG_JOB, text, data)
|
||||
|
||||
/// Logging for lua scripting
|
||||
/proc/log_lua(text)
|
||||
WRITE_LOG(GLOB.lua_log, text)
|
||||
/proc/log_lua(text, list/data)
|
||||
logger.Log(LOG_CATEGORY_DEBUG_LUA, text, data)
|
||||
|
||||
/// Logging for mapping errors
|
||||
/proc/log_mapping(text, skip_world_log)
|
||||
#ifdef UNIT_TESTS
|
||||
GLOB.unit_test_mapping_logs += text
|
||||
#endif
|
||||
WRITE_LOG(GLOB.world_map_error_log, text)
|
||||
logger.Log(LOG_CATEGORY_DEBUG_MAPPING, text)
|
||||
if(skip_world_log)
|
||||
return
|
||||
SEND_TEXT(world.log, text)
|
||||
@@ -37,31 +35,27 @@
|
||||
WRITE_LOG_NO_FORMAT(GLOB.perf_log, .)
|
||||
|
||||
/// Logging for hard deletes
|
||||
/proc/log_qdel(text)
|
||||
WRITE_LOG(GLOB.world_qdel_log, "QDEL: [text]")
|
||||
|
||||
/// Logging for SQL errors
|
||||
/proc/log_query_debug(text)
|
||||
WRITE_LOG(GLOB.query_debug_log, "SQL: [text]")
|
||||
/proc/log_qdel(text, list/data)
|
||||
logger.Log(LOG_CATEGORY_DEBUG_QDEL, text, data)
|
||||
|
||||
/* Log to the logfile only. */
|
||||
/proc/log_runtime(text)
|
||||
WRITE_LOG(GLOB.world_runtime_log, text)
|
||||
/proc/log_runtime(text, list/data)
|
||||
logger.Log(LOG_CATEGORY_RUNTIME, text, data)
|
||||
|
||||
/proc/log_signal(text)
|
||||
WRITE_LOG(GLOB.signals_log, text)
|
||||
/proc/log_signal(text, list/data)
|
||||
logger.Log(LOG_CATEGORY_SIGNAL, text, data)
|
||||
|
||||
/// Logging for DB errors
|
||||
/proc/log_sql(text)
|
||||
WRITE_LOG(GLOB.sql_error_log, "SQL: [text]")
|
||||
/proc/log_sql(text, list/data)
|
||||
logger.Log(LOG_CATEGORY_DEBUG_SQL, text, data)
|
||||
|
||||
/// Logging for world/Topic
|
||||
/proc/log_topic(text)
|
||||
WRITE_LOG(GLOB.world_game_log, "TOPIC: [text]")
|
||||
/proc/log_topic(text, list/data)
|
||||
logger.Log(LOG_CATEGORY_GAME_TOPIC, text, data)
|
||||
|
||||
/// Log to both DD and the logfile.
|
||||
/proc/log_world(text)
|
||||
/proc/log_world(text, list/data)
|
||||
#ifdef USE_CUSTOM_ERROR_HANDLER
|
||||
WRITE_LOG(GLOB.world_runtime_log, text)
|
||||
logger.Log(LOG_CATEGORY_RUNTIME, text, data)
|
||||
#endif
|
||||
SEND_TEXT(world.log, text)
|
||||
|
||||
@@ -4,5 +4,5 @@
|
||||
log_dynamic("[text]")
|
||||
|
||||
/// Logging for dynamic procs
|
||||
/proc/log_dynamic(text)
|
||||
WRITE_LOG(GLOB.dynamic_log, "DYNAMIC: [text]")
|
||||
/proc/log_dynamic(text, list/data)
|
||||
logger.Log(LOG_CATEGORY_DYNAMIC, text, data)
|
||||
|
||||
@@ -1,3 +1,2 @@
|
||||
/proc/log_econ(text)
|
||||
if (CONFIG_GET(flag/log_econ))
|
||||
WRITE_LOG(GLOB.world_econ_log, "MONEY: [text]")
|
||||
/proc/log_econ(text, list/data)
|
||||
logger.Log(LOG_CATEGORY_ECONOMY, text, data)
|
||||
|
||||
@@ -1,40 +1,32 @@
|
||||
/// Logging for generic/unsorted game messages
|
||||
/proc/log_game(text)
|
||||
if (CONFIG_GET(flag/log_game))
|
||||
WRITE_LOG(GLOB.world_game_log, "GAME: [text]")
|
||||
/proc/log_game(text, list/data)
|
||||
logger.Log(LOG_CATEGORY_GAME, text, data)
|
||||
|
||||
/// Logging for emotes
|
||||
/proc/log_emote(text)
|
||||
if (CONFIG_GET(flag/log_emote))
|
||||
WRITE_LOG(GLOB.world_game_log, "EMOTE: [text]")
|
||||
/proc/log_emote(text, list/data)
|
||||
logger.Log(LOG_CATEGORY_GAME_EMOTE, text, data)
|
||||
|
||||
/// Logging for emotes sent over the radio
|
||||
/proc/log_radio_emote(text)
|
||||
if (CONFIG_GET(flag/log_emote))
|
||||
WRITE_LOG(GLOB.world_game_log, "RADIOEMOTE: [text]")
|
||||
/proc/log_radio_emote(text, list/data)
|
||||
logger.Log(LOG_CATEGORY_GAME_RADIO_EMOTE, text, data)
|
||||
|
||||
/// Logging for messages sent in OOC
|
||||
/proc/log_ooc(text)
|
||||
if (CONFIG_GET(flag/log_ooc))
|
||||
WRITE_LOG(GLOB.world_game_log, "OOC: [text]")
|
||||
/proc/log_ooc(text, list/data)
|
||||
logger.Log(LOG_CATEGORY_GAME_OOC, text, data)
|
||||
|
||||
/// Logging for prayed messages
|
||||
/proc/log_prayer(text)
|
||||
if (CONFIG_GET(flag/log_prayer))
|
||||
WRITE_LOG(GLOB.world_game_log, "PRAY: [text]")
|
||||
/proc/log_prayer(text, list/data)
|
||||
logger.Log(LOG_CATEGORY_GAME_PRAYER, text, data)
|
||||
|
||||
/// Logging for music requests
|
||||
/proc/log_internet_request(text)
|
||||
if (CONFIG_GET(flag/log_internet_request))
|
||||
WRITE_LOG(GLOB.world_game_log, "INTERNET REQUEST: [text]")
|
||||
/proc/log_internet_request(text, list/data)
|
||||
logger.Log(LOG_CATEGORY_GAME_INTERNET_REQUEST, text, data)
|
||||
|
||||
/// Logging for logging in & out of the game, with error messages.
|
||||
/proc/log_access(text)
|
||||
if (CONFIG_GET(flag/log_access))
|
||||
WRITE_LOG(GLOB.world_game_log, "ACCESS: [text]")
|
||||
/proc/log_access(text, list/data)
|
||||
logger.Log(LOG_CATEGORY_GAME_ACCESS, text, data)
|
||||
|
||||
/// Logging for OOC votes
|
||||
/proc/log_vote(text)
|
||||
if (CONFIG_GET(flag/log_vote))
|
||||
WRITE_LOG(GLOB.world_game_log, "VOTE: [text]")
|
||||
/proc/log_vote(text, list/data)
|
||||
logger.Log(LOG_CATEGORY_GAME_VOTE, text, data)
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
/// Logging for player manifest (ckey, name, job, special role, roundstart/latejoin)
|
||||
/proc/log_manifest(ckey, datum/mind/mind, mob/body, latejoin = FALSE)
|
||||
if (CONFIG_GET(flag/log_manifest))
|
||||
WRITE_LOG(GLOB.world_manifest_log, "[ckey] \\ [body.real_name] \\ [mind.assigned_role.title] \\ [mind.special_role ? mind.special_role : "NONE"] \\ [latejoin ? "LATEJOIN":"ROUNDSTART"]")
|
||||
logger.Log(LOG_CATEGORY_MANIFEST, "manifest entry added", list(
|
||||
"mind" = mind, "body" = body, "latejoin" = latejoin
|
||||
))
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
/// Logging for mech actions
|
||||
/proc/log_mecha(text)
|
||||
if (CONFIG_GET(flag/log_mecha))
|
||||
WRITE_LOG(GLOB.world_mecha_log, "MECHA: [text]")
|
||||
/proc/log_mecha(text, list/data)
|
||||
logger.Log(LOG_CATEGORY_MECHA, text, data)
|
||||
|
||||
/// Logging for equipment installed in a mecha
|
||||
/obj/item/mecha_parts/mecha_equipment/log_message(message, message_type = LOG_MECHA, color = null, log_globally)
|
||||
|
||||
@@ -3,12 +3,11 @@
|
||||
* Arguments:
|
||||
* * text - text to log.
|
||||
*/
|
||||
/mob/proc/log_mob_tag(text)
|
||||
WRITE_LOG(GLOB.world_mob_tag_log, "TAG: \[[tag]\] [text]")
|
||||
/mob/proc/log_mob_tag(text, list/data)
|
||||
logger.Log(LOG_CATEGORY_DEBUG_MOBTAG, text, data)
|
||||
|
||||
/proc/log_silicon(text)
|
||||
if (CONFIG_GET(flag/log_silicon))
|
||||
WRITE_LOG(GLOB.world_silicon_log, "SILICON: [text]")
|
||||
/proc/log_silicon(text, list/data)
|
||||
logger.Log(LOG_CATEGORY_SILICON, text, data)
|
||||
|
||||
|
||||
/// Logs a message in a mob's individual log, and in the global logs as well if log_globally is true
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
/// Logging for writing made on paper
|
||||
/proc/log_paper(text)
|
||||
WRITE_LOG(GLOB.world_paper_log, "PAPER: [text]")
|
||||
/proc/log_paper(text, list/data)
|
||||
logger.Log(LOG_CATEGORY_PAPER, text, data)
|
||||
|
||||
@@ -1,16 +1,11 @@
|
||||
/// Logging for PDA messages sent
|
||||
/proc/log_pda(text)
|
||||
if (CONFIG_GET(flag/log_pda))
|
||||
WRITE_LOG(GLOB.world_pda_log, "PDA: [text]")
|
||||
/proc/log_pda(text, list/data)
|
||||
logger.Log(LOG_CATEGORY_PDA, text, data)
|
||||
|
||||
/// Logging for newscaster comments
|
||||
/proc/log_comment(text)
|
||||
//reusing the PDA option because I really don't think news comments are worth a config option
|
||||
if (CONFIG_GET(flag/log_pda))
|
||||
WRITE_LOG(GLOB.world_pda_log, "COMMENT: [text]")
|
||||
/proc/log_comment(text, list/data)
|
||||
logger.Log(LOG_CATEGORY_PDA_COMMENT, text, data)
|
||||
|
||||
/// Logging for chatting on modular computer channels
|
||||
/proc/log_chat(text)
|
||||
//same thing here
|
||||
if (CONFIG_GET(flag/log_pda))
|
||||
WRITE_LOG(GLOB.world_pda_log, "CHAT: [text]")
|
||||
/proc/log_chat(text, list/data)
|
||||
logger.Log(LOG_CATEGORY_PDA_CHAT, text, data)
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
/// Logging for shuttle actions
|
||||
/proc/log_shuttle(text)
|
||||
if (CONFIG_GET(flag/log_shuttle))
|
||||
WRITE_LOG(GLOB.world_shuttle_log, "SHUTTLE: [text]")
|
||||
/proc/log_shuttle(text, list/data)
|
||||
logger.Log(LOG_CATEGORY_SHUTTLE, text, data)
|
||||
|
||||
@@ -17,14 +17,12 @@
|
||||
log_message("[prefix][custom_say_emote ? "*[custom_say_emote]*, " : ""]\"[message]\"[suffix]", message_type, log_globally = log_globally)
|
||||
|
||||
/// Logging for generic spoken messages
|
||||
/proc/log_say(text)
|
||||
if (CONFIG_GET(flag/log_say))
|
||||
WRITE_LOG(GLOB.world_game_log, "SAY: [text]")
|
||||
/proc/log_say(text, list/data)
|
||||
logger.Log(LOG_CATEGORY_GAME_SAY, text, data)
|
||||
|
||||
/// Logging for whispered messages
|
||||
/proc/log_whisper(text)
|
||||
if (CONFIG_GET(flag/log_whisper))
|
||||
WRITE_LOG(GLOB.world_game_log, "WHISPER: [text]")
|
||||
/proc/log_whisper(text, list/data)
|
||||
logger.Log(LOG_CATEGORY_GAME_WHISPER, text, data)
|
||||
|
||||
/// Helper for logging of messages with only one sender and receiver (i.e. mind links)
|
||||
/proc/log_directed_talk(atom/source, atom/target, message, message_type, tag)
|
||||
@@ -37,11 +35,9 @@
|
||||
target.log_talk(message, LOG_VICTIM, tag = "[tag] from [key_name(source)]", log_globally = FALSE)
|
||||
|
||||
/// Logging for speech taking place over comms, as well as tcomms equipment
|
||||
/proc/log_telecomms(text)
|
||||
if (CONFIG_GET(flag/log_telecomms))
|
||||
WRITE_LOG(GLOB.world_telecomms_log, "TCOMMS: [text]")
|
||||
/proc/log_telecomms(text, list/data)
|
||||
logger.Log(LOG_CATEGORY_TELECOMMS, text, data)
|
||||
|
||||
/// Logging for speech indicators.
|
||||
/proc/log_speech_indicators(text)
|
||||
if (CONFIG_GET(flag/log_speech_indicators))
|
||||
WRITE_LOG(GLOB.world_speech_indicators_log, "SPEECH INDICATOR: [text]")
|
||||
/proc/log_speech_indicators(text, list/data)
|
||||
logger.Log(LOG_CATEGORY_SPEECH_INDICATOR, text, data)
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
/// Logging for tool usage
|
||||
/proc/log_tool(text, mob/initiator)
|
||||
if(CONFIG_GET(flag/log_tools))
|
||||
WRITE_LOG(GLOB.world_tool_log, "TOOL: [text]")
|
||||
logger.Log(LOG_CATEGORY_TOOL, text, initiator ? list("initiator" = initiator) : null)
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/proc/log_href(text)
|
||||
WRITE_LOG(GLOB.world_href_log, "HREF: [text]")
|
||||
/proc/log_href(text, list/data)
|
||||
logger.Log(LOG_CATEGORY_DEBUG_HREF, text, data)
|
||||
|
||||
/**
|
||||
* Appends a tgui-related log entry. All arguments are optional.
|
||||
@@ -31,4 +31,4 @@
|
||||
// Insert message
|
||||
if(message)
|
||||
entry += "\n[message]"
|
||||
WRITE_LOG(GLOB.tgui_log, entry)
|
||||
logger.Log(LOG_CATEGORY_DEBUG_TGUI, entry)
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
/// Logging for the creation and contraction of viruses
|
||||
/proc/log_virus(text)
|
||||
if (CONFIG_GET(flag/log_virus))
|
||||
WRITE_LOG(GLOB.world_virus_log, "VIRUS: [text]")
|
||||
/proc/log_virus(text, list/data)
|
||||
logger.Log(LOG_CATEGORY_VIRUS, text, data)
|
||||
|
||||
/// Returns a string for admin logging uses, should describe the disease in detail
|
||||
/datum/disease/proc/admin_details()
|
||||
|
||||
@@ -1193,3 +1193,15 @@ GLOBAL_LIST_INIT(binary, list("0","1"))
|
||||
/proc/sanitize_css_class_name(name)
|
||||
var/static/regex/regex = new(@"[^a-zA-Z0-9]","g")
|
||||
return replacetext(name, regex, "")
|
||||
|
||||
/// Converts a semver string into a list of numbers
|
||||
/proc/semver_to_list(semver_string)
|
||||
var/static/regex/semver_regex = regex(@"(\d+)\.(\d+)\.(\d+)", "")
|
||||
if(!semver_regex.Find(semver_string))
|
||||
return null
|
||||
|
||||
return list(
|
||||
text2num(semver_regex.group[1]),
|
||||
text2num(semver_regex.group[2]),
|
||||
text2num(semver_regex.group[3]),
|
||||
)
|
||||
|
||||
@@ -28,47 +28,18 @@ GLOBAL_PROTECT(##log_var_name);\
|
||||
SHOULD_CALL_PARENT(TRUE)
|
||||
return
|
||||
|
||||
// All individual log files
|
||||
// All individual log files.
|
||||
// These should be used where the log category cannot easily be a json log file.
|
||||
DECLARE_LOG(config_error_log, DONT_START_LOG)
|
||||
DECLARE_LOG(dynamic_log, DONT_START_LOG)
|
||||
DECLARE_LOG(lua_log, DONT_START_LOG)
|
||||
DECLARE_LOG(perf_log, DONT_START_LOG) // Declared here but name is set in time_track subsystem
|
||||
DECLARE_LOG(query_debug_log, DONT_START_LOG)
|
||||
DECLARE_LOG(signals_log, DONT_START_LOG)
|
||||
DECLARE_LOG(tgui_log, START_LOG)
|
||||
|
||||
#ifdef REFERENCE_DOING_IT_LIVE
|
||||
DECLARE_LOG_NAMED(harddel_log, "harddels", START_LOG)
|
||||
#endif
|
||||
|
||||
#if defined(UNIT_TESTS) || defined(SPACEMAN_DMM)
|
||||
DECLARE_LOG_NAMED(test_log, "tests", START_LOG)
|
||||
#endif
|
||||
DECLARE_LOG_NAMED(filter_log, "filters", DONT_START_LOG)
|
||||
DECLARE_LOG_NAMED(sql_error_log, "sql", DONT_START_LOG)
|
||||
DECLARE_LOG_NAMED(world_asset_log, "asset", DONT_START_LOG)
|
||||
DECLARE_LOG_NAMED(world_attack_log, "attack", START_LOG)
|
||||
DECLARE_LOG_NAMED(world_econ_log, "econ", START_LOG)
|
||||
DECLARE_LOG_NAMED(world_game_log, "game", START_LOG)
|
||||
DECLARE_LOG_NAMED(world_href_log, "hrefs", START_LOG)
|
||||
DECLARE_LOG_NAMED(world_job_debug_log, "job_debug", START_LOG)
|
||||
DECLARE_LOG_NAMED(world_manifest_log, "manifest", START_LOG)
|
||||
DECLARE_LOG_NAMED(world_map_error_log, "map_errors", DONT_START_LOG)
|
||||
DECLARE_LOG_NAMED(world_mecha_log, "mecha", DONT_START_LOG)
|
||||
DECLARE_LOG_NAMED(world_mob_tag_log, "mob_tags", START_LOG)
|
||||
DECLARE_LOG_NAMED(world_paper_log, "paper", DONT_START_LOG)
|
||||
DECLARE_LOG_NAMED(world_pda_log, "pda", START_LOG)
|
||||
DECLARE_LOG_NAMED(world_qdel_log, "qdel", START_LOG)
|
||||
DECLARE_LOG_NAMED(world_runtime_log, "runtime", START_LOG)
|
||||
DECLARE_LOG_NAMED(world_shuttle_log, "shuttle", START_LOG)
|
||||
DECLARE_LOG_NAMED(world_silicon_log, "silicon", DONT_START_LOG)
|
||||
DECLARE_LOG_NAMED(world_speech_indicators_log, "speech_indicators", DONT_START_LOG)
|
||||
DECLARE_LOG_NAMED(world_telecomms_log, "telecomms", START_LOG)
|
||||
DECLARE_LOG_NAMED(world_tool_log, "tools", DONT_START_LOG)
|
||||
DECLARE_LOG_NAMED(world_uplink_log, "uplink", START_LOG)
|
||||
DECLARE_LOG_NAMED(world_virus_log, "virus", DONT_START_LOG)
|
||||
/// Log associated with [/proc/log_suspicious_login()]
|
||||
/// Intended to hold all logins that failed due to suspicious circumstances such as ban detection, CID randomisation etc.
|
||||
DECLARE_LOG_NAMED(world_suspicious_login_log, "suspicious_logins", DONT_START_LOG)
|
||||
|
||||
|
||||
|
||||
/// Picture logging
|
||||
|
||||
@@ -158,6 +158,10 @@
|
||||
/// logs all timers in buckets on automatic bucket reset (Useful for timer debugging)
|
||||
/datum/config_entry/flag/log_timers_on_bucket_reset
|
||||
|
||||
/// Log human readable versions of json log entries
|
||||
/datum/config_entry/flag/log_as_human_readable
|
||||
default = TRUE
|
||||
|
||||
/// allows admins with relevant permissions to have their own ooc colour
|
||||
/datum/config_entry/flag/allow_admin_ooccolor
|
||||
|
||||
|
||||
@@ -569,12 +569,18 @@ Delayed insert mode was removed in mysql 7 and only works with MyISAM type table
|
||||
. = (status != DB_QUERY_BROKEN)
|
||||
var/timed_out = !. && findtext(last_error, "Operation timed out")
|
||||
if(!. && log_error)
|
||||
log_sql("[last_error] | Query used: [sql] | Arguments: [json_encode(arguments)]")
|
||||
logger.Log(LOG_CATEGORY_DEBUG_SQL, "sql query failed", list(
|
||||
"query" = sql,
|
||||
"arguments" = json_encode(arguments),
|
||||
"error" = last_error,
|
||||
))
|
||||
|
||||
if(!async && timed_out)
|
||||
log_query_debug("Query execution started at [start_time]")
|
||||
log_query_debug("Query execution ended at [REALTIMEOFDAY]")
|
||||
log_query_debug("Slow query timeout detected.")
|
||||
log_query_debug("Query used: [sql]")
|
||||
logger.Log(LOG_CATEGORY_DEBUG_SQL, "slow query timeout", list(
|
||||
"query" = sql,
|
||||
"start_time" = start_time,
|
||||
"end_time" = REALTIMEOFDAY,
|
||||
))
|
||||
slow_query_check()
|
||||
|
||||
/// Sleeps until execution of the query has finished.
|
||||
|
||||
+14
-8
@@ -183,13 +183,20 @@
|
||||
to_chat(target, txt_changed_vars())
|
||||
#endif
|
||||
|
||||
///Return a LIST for serialize_datum to encode! Not the actual json!
|
||||
/datum/proc/serialize_list(list/options)
|
||||
CRASH("Attempted to serialize datum [src] of type [type] without serialize_list being implemented!")
|
||||
/// Return a list of data which can be used to investigate the datum, also ensure that you set the semver in the options list
|
||||
/datum/proc/serialize_list(list/options, list/semvers)
|
||||
SHOULD_CALL_PARENT(TRUE)
|
||||
|
||||
///Accepts a LIST from deserialize_datum. Should return src or another datum.
|
||||
. = list()
|
||||
.["tag"] = tag
|
||||
|
||||
SET_SERIALIZATION_SEMVER(semvers, "1.0.0")
|
||||
return .
|
||||
|
||||
///Accepts a LIST from deserialize_datum. Should return whether or not the deserialization was successful.
|
||||
/datum/proc/deserialize_list(json, list/options)
|
||||
CRASH("Attempted to deserialize datum [src] of type [type] without deserialize_list being implemented!")
|
||||
SHOULD_CALL_PARENT(TRUE)
|
||||
return TRUE
|
||||
|
||||
///Serializes into JSON. Does not encode type.
|
||||
/datum/proc/serialize_json(list/options)
|
||||
@@ -241,11 +248,10 @@
|
||||
return
|
||||
var/typeofdatum = jsonlist["DATUM_TYPE"] //BYOND won't directly read if this is just put in the line below, and will instead runtime because it thinks you're trying to make a new list?
|
||||
var/datum/D = new typeofdatum
|
||||
var/datum/returned = D.deserialize_list(jsonlist, options)
|
||||
if(!isdatum(returned))
|
||||
if(!D.deserialize_list(jsonlist, options))
|
||||
qdel(D)
|
||||
else
|
||||
return returned
|
||||
return D
|
||||
|
||||
/**
|
||||
* Callback called by a timer to end an associative-list-indexed cooldown.
|
||||
|
||||
@@ -59,7 +59,9 @@ GENERAL_PROTECT_DATUM(/datum/json_savefile)
|
||||
if(path)
|
||||
rustg_file_write(json_encode(tree), path)
|
||||
|
||||
/datum/json_savefile/serialize_list(list/options)
|
||||
/datum/json_savefile/serialize_list(list/options, list/semvers)
|
||||
SHOULD_CALL_PARENT(FALSE)
|
||||
SET_SERIALIZATION_SEMVER(semvers, "1.0.0")
|
||||
return tree.Copy()
|
||||
|
||||
/// Traverses the entire dir tree of the given savefile and dynamically assembles the tree from it
|
||||
|
||||
@@ -16,6 +16,16 @@
|
||||
/// If set to true this style allows you to punch people despite being a pacifist (for instance Boxing, which does no damage)
|
||||
var/pacifist_style = FALSE
|
||||
|
||||
/datum/martial_art/serialize_list(list/options, list/semvers)
|
||||
. = ..()
|
||||
|
||||
.["name"] = name
|
||||
.["id"] = id
|
||||
.["pacifist_style"] = pacifist_style
|
||||
|
||||
SET_SERIALIZATION_SEMVER(semvers, "1.0.0")
|
||||
return .
|
||||
|
||||
/datum/martial_art/proc/help_act(mob/living/attacker, mob/living/defender)
|
||||
return MARTIAL_ATTACK_INVALID
|
||||
|
||||
|
||||
@@ -75,6 +75,22 @@
|
||||
memorizer_mind = null
|
||||
return ..()
|
||||
|
||||
/datum/memory/serialize_list(list/options, list/semvers)
|
||||
. = ..()
|
||||
|
||||
.["name"] = name
|
||||
.["memorizer"] = memorizer
|
||||
.["story_value"] = story_value
|
||||
.["memory_flags"] = memory_flags
|
||||
.["mood_verb"] = mood_verb
|
||||
.["protagonist_name"] = protagonist_name
|
||||
.["deuteragonist_name"] = deuteragonist_name
|
||||
.["antagonist_name"] = antagonist_name
|
||||
.["where"] = where
|
||||
|
||||
SET_SERIALIZATION_SEMVER(semvers, "1.0.0")
|
||||
return .
|
||||
|
||||
/**
|
||||
* Generates a name for the memory.
|
||||
*/
|
||||
|
||||
@@ -122,6 +122,25 @@
|
||||
set_current(null)
|
||||
return ..()
|
||||
|
||||
/datum/mind/serialize_list(list/options, list/semvers)
|
||||
. = ..()
|
||||
|
||||
.["key"] = key
|
||||
.["name"] = name
|
||||
.["ghostname"] = ghostname
|
||||
.["memories"] = memories
|
||||
.["martial_art"] = martial_art
|
||||
.["antag_datums"] = antag_datums
|
||||
.["holy_role"] = holy_role
|
||||
.["special_role"] = special_role
|
||||
.["assigned_role"] = assigned_role.title
|
||||
.["current"] = current
|
||||
|
||||
var/mob/enslaved_to = src.enslaved_to?.resolve()
|
||||
.["enslaved_to"] = enslaved_to
|
||||
|
||||
SET_SERIALIZATION_SEMVER(semvers, "1.0.0")
|
||||
return .
|
||||
|
||||
/datum/mind/vv_edit_var(var_name, var_value)
|
||||
switch(var_name)
|
||||
|
||||
+12
-1
@@ -76,6 +76,9 @@ GLOBAL_VAR(restart_counter)
|
||||
// Init the debugger first so we can debug Master
|
||||
init_debugger()
|
||||
|
||||
// Create the logger
|
||||
logger = new
|
||||
|
||||
// THAT'S IT, WE'RE DONE, THE. FUCKING. END.
|
||||
Master = new
|
||||
|
||||
@@ -176,6 +179,14 @@ GLOBAL_VAR(restart_counter)
|
||||
#endif
|
||||
SSticker.OnRoundstart(CALLBACK(GLOBAL_PROC, GLOBAL_PROC_REF(_addtimer), cb, 10 SECONDS))
|
||||
|
||||
/// Returns a list of data about the world state, don't clutter
|
||||
/world/proc/get_world_state_for_logging()
|
||||
var/data = list()
|
||||
data["tick_usage"] = world.tick_usage
|
||||
data["tick_lag"] = world.tick_lag
|
||||
data["time"] = world.time
|
||||
data["timestamp"] = logger.unix_timestamp_string()
|
||||
return data
|
||||
|
||||
/world/proc/SetupLogs()
|
||||
var/override_dir = params[OVERRIDE_LOG_DIRECTORY_PARAMETER]
|
||||
@@ -199,7 +210,7 @@ GLOBAL_VAR(restart_counter)
|
||||
GLOB.picture_logging_prefix = "O_[override_dir]_"
|
||||
GLOB.picture_log_directory = "data/picture_logs/[override_dir]"
|
||||
|
||||
GLOB.logger.init_logging()
|
||||
logger.init_logging()
|
||||
|
||||
var/latest_changelog = file("[global.config.directory]/../html/changelogs/archive/" + time2text(world.timeofday, "YYYY-MM") + ".yml")
|
||||
GLOB.changelog_hash = fexists(latest_changelog) ? md5(latest_changelog) : 0 //for telling if the changelog has changed recently
|
||||
|
||||
@@ -1474,15 +1474,17 @@
|
||||
else if(href_list["slowquery"])
|
||||
if(!check_rights(R_ADMIN))
|
||||
return
|
||||
|
||||
var/data = list("key" = usr.key)
|
||||
var/answer = href_list["slowquery"]
|
||||
if(answer == "yes")
|
||||
log_query_debug("[usr.key] | Reported a server hang")
|
||||
if(tgui_alert(usr, "Did you just press any admin buttons?", "Query server hang report", list("Yes", "No")) == "Yes")
|
||||
var/response = input(usr,"What were you just doing?","Query server hang report") as null|text
|
||||
if(response)
|
||||
log_query_debug("[usr.key] | [response]")
|
||||
data["response"] = response
|
||||
logger.Log(LOG_CATEGORY_DEBUG_SQL, "server hang", data)
|
||||
else if(answer == "no")
|
||||
log_query_debug("[usr.key] | Reported no server hang")
|
||||
logger.Log(LOG_CATEGORY_DEBUG_SQL, "no server hang", data)
|
||||
|
||||
else if(href_list["ctf_toggle"])
|
||||
if(!check_rights(R_ADMIN))
|
||||
|
||||
@@ -0,0 +1,26 @@
|
||||
/datum/log_category/admin
|
||||
category = LOG_CATEGORY_ADMIN
|
||||
config_flag = /datum/config_entry/flag/log_admin
|
||||
|
||||
/datum/log_category/admin_dsay
|
||||
category = LOG_CATEGORY_ADMIN_DSAY
|
||||
master_category = /datum/log_category/admin
|
||||
config_flag = /datum/config_entry/flag/log_admin
|
||||
|
||||
/datum/log_category/admin_circuit
|
||||
category = LOG_CATEGORY_ADMIN_CIRCUIT
|
||||
master_category = /datum/log_category/admin
|
||||
config_flag = /datum/config_entry/flag/log_admin
|
||||
|
||||
// private categories //
|
||||
|
||||
/datum/log_category/admin_private
|
||||
category = LOG_CATEGORY_ADMIN_PRIVATE
|
||||
config_flag = /datum/config_entry/flag/log_admin
|
||||
secret = TRUE
|
||||
|
||||
/datum/log_category/admin_asay
|
||||
category = LOG_CATEGORY_ADMIN_PRIVATE_ASAY
|
||||
master_category = /datum/log_category/admin_private
|
||||
config_flag = /datum/config_entry/flag/log_adminchat
|
||||
secret = TRUE
|
||||
@@ -0,0 +1,7 @@
|
||||
/datum/log_category/game_compat
|
||||
category = LOG_CATEGORY_COMPAT_GAME
|
||||
master_category = /datum/log_category/game
|
||||
config_flag = /datum/config_entry/flag/logging_compat_adminprivate
|
||||
|
||||
/datum/config_entry/flag/logging_compat_adminprivate
|
||||
default = FALSE
|
||||
@@ -0,0 +1,45 @@
|
||||
/datum/log_category/debug
|
||||
category = LOG_CATEGORY_DEBUG
|
||||
|
||||
/datum/log_category/debug_tgui
|
||||
category = LOG_CATEGORY_DEBUG_TGUI
|
||||
master_category = /datum/log_category/debug
|
||||
|
||||
/datum/log_category/debug_sql
|
||||
category = LOG_CATEGORY_DEBUG_SQL
|
||||
master_category = /datum/log_category/debug
|
||||
|
||||
/datum/log_category/debug_lua
|
||||
category = LOG_CATEGORY_DEBUG_LUA
|
||||
master_category = /datum/log_category/debug
|
||||
|
||||
/datum/log_category/debug_href
|
||||
category = LOG_CATEGORY_DEBUG_HREF
|
||||
master_category = /datum/log_category/debug
|
||||
|
||||
// This is not in the debug master category on purpose, do not add it
|
||||
/datum/log_category/debug_runtime
|
||||
category = LOG_CATEGORY_RUNTIME
|
||||
internal_formatting = FALSE
|
||||
|
||||
/datum/log_category/debug_mapping
|
||||
category = LOG_CATEGORY_DEBUG_MAPPING
|
||||
master_category = /datum/log_category/debug
|
||||
|
||||
/datum/log_category/debug_job
|
||||
category = LOG_CATEGORY_DEBUG_JOB
|
||||
config_flag = /datum/config_entry/flag/log_job_debug
|
||||
master_category = /datum/log_category/debug
|
||||
|
||||
/datum/log_category/debug_mobtag
|
||||
category = LOG_CATEGORY_DEBUG_MOBTAG
|
||||
master_category = /datum/log_category/debug
|
||||
|
||||
/datum/log_category/debug_asset
|
||||
category = LOG_CATEGORY_DEBUG_ASSET
|
||||
config_flag = /datum/config_entry/flag/log_asset
|
||||
master_category = /datum/log_category/debug
|
||||
|
||||
/datum/log_category/debug_qdel
|
||||
category = LOG_CATEGORY_DEBUG_QDEL
|
||||
master_category = /datum/log_category/debug
|
||||
@@ -0,0 +1,58 @@
|
||||
/datum/log_category/game
|
||||
category = LOG_CATEGORY_GAME
|
||||
config_flag = /datum/config_entry/flag/log_game
|
||||
|
||||
/datum/log_category/game_vote
|
||||
category = LOG_CATEGORY_GAME_VOTE
|
||||
config_flag = /datum/config_entry/flag/log_vote
|
||||
master_category = /datum/log_category/game
|
||||
|
||||
/datum/log_category/game_emote
|
||||
category = LOG_CATEGORY_GAME_EMOTE
|
||||
config_flag = /datum/config_entry/flag/log_emote
|
||||
master_category = /datum/log_category/game
|
||||
|
||||
/datum/log_category/game_internet_request
|
||||
category = LOG_CATEGORY_GAME_INTERNET_REQUEST
|
||||
config_flag = /datum/config_entry/flag/log_internet_request
|
||||
master_category = /datum/log_category/game
|
||||
|
||||
/datum/log_category/game_radio_emote
|
||||
category = LOG_CATEGORY_GAME_RADIO_EMOTE
|
||||
config_flag = /datum/config_entry/flag/log_emote
|
||||
master_category = /datum/log_category/game
|
||||
|
||||
/datum/log_category/game_traitor
|
||||
category = LOG_CATEGORY_GAME_TRAITOR
|
||||
config_flag = /datum/config_entry/flag/log_traitor
|
||||
master_category = /datum/log_category/game
|
||||
|
||||
/datum/log_category/game_topic
|
||||
category = LOG_CATEGORY_GAME_TOPIC
|
||||
config_flag = /datum/config_entry/flag/log_world_topic
|
||||
master_category = /datum/log_category/game
|
||||
|
||||
/datum/log_category/game_say
|
||||
category = LOG_CATEGORY_GAME_SAY
|
||||
config_flag = /datum/config_entry/flag/log_say
|
||||
master_category = /datum/log_category/game
|
||||
|
||||
/datum/log_category/game_whisper
|
||||
category = LOG_CATEGORY_GAME_WHISPER
|
||||
config_flag = /datum/config_entry/flag/log_whisper
|
||||
master_category = /datum/log_category/game
|
||||
|
||||
/datum/log_category/game_ooc
|
||||
category = LOG_CATEGORY_GAME_OOC
|
||||
config_flag = /datum/config_entry/flag/log_ooc
|
||||
master_category = /datum/log_category/game
|
||||
|
||||
/datum/log_category/game_prayer
|
||||
category = LOG_CATEGORY_GAME_PRAYER
|
||||
config_flag = /datum/config_entry/flag/log_prayer
|
||||
master_category = /datum/log_category/game
|
||||
|
||||
/datum/log_category/game_access
|
||||
category = LOG_CATEGORY_GAME_ACCESS
|
||||
config_flag = /datum/config_entry/flag/log_access
|
||||
master_category = /datum/log_category/game
|
||||
@@ -0,0 +1,58 @@
|
||||
/datum/log_category/virus
|
||||
category = LOG_CATEGORY_VIRUS
|
||||
config_flag = /datum/config_entry/flag/log_virus
|
||||
|
||||
/datum/log_category/tool
|
||||
category = LOG_CATEGORY_TOOL
|
||||
config_flag = /datum/config_entry/flag/log_tools
|
||||
|
||||
/datum/log_category/mecha
|
||||
category = LOG_CATEGORY_MECHA
|
||||
config_flag = /datum/config_entry/flag/log_mecha
|
||||
|
||||
/datum/log_category/silicon
|
||||
category = LOG_CATEGORY_SILICON
|
||||
config_flag = /datum/config_entry/flag/log_silicon
|
||||
|
||||
/datum/log_category/paper
|
||||
category = LOG_CATEGORY_PAPER
|
||||
|
||||
/datum/log_category/attack
|
||||
category = LOG_CATEGORY_ATTACK
|
||||
config_flag = /datum/config_entry/flag/log_attack
|
||||
|
||||
/datum/log_category/economy
|
||||
category = LOG_CATEGORY_ECONOMY
|
||||
config_flag = /datum/config_entry/flag/log_econ
|
||||
|
||||
/datum/log_category/manifest
|
||||
category = LOG_CATEGORY_MANIFEST
|
||||
config_flag = /datum/config_entry/flag/log_manifest
|
||||
|
||||
/datum/log_category/shuttle
|
||||
category = LOG_CATEGORY_SHUTTLE
|
||||
config_flag = /datum/config_entry/flag/log_shuttle
|
||||
|
||||
/datum/log_category/supicious_login
|
||||
category = LOG_CATEGORY_SUSPICIOUS_LOGIN
|
||||
config_flag = /datum/config_entry/flag/log_suspicious_login
|
||||
|
||||
/datum/log_category/config
|
||||
category = LOG_CATEGORY_CONFIG
|
||||
|
||||
/datum/log_category/filter
|
||||
category = LOG_CATEGORY_FILTER
|
||||
|
||||
/datum/log_category/signal
|
||||
category = LOG_CATEGORY_SIGNAL
|
||||
|
||||
/datum/log_category/dynamic
|
||||
category = LOG_CATEGORY_DYNAMIC
|
||||
|
||||
/datum/log_category/telecomms
|
||||
category = LOG_CATEGORY_TELECOMMS
|
||||
config_flag = /datum/config_entry/flag/log_telecomms
|
||||
|
||||
/datum/log_category/speech_indicator
|
||||
category = LOG_CATEGORY_SPEECH_INDICATOR
|
||||
config_flag = /datum/config_entry/flag/log_speech_indicators
|
||||
@@ -0,0 +1,11 @@
|
||||
/datum/log_category/pda
|
||||
category = LOG_CATEGORY_PDA
|
||||
config_flag = /datum/config_entry/flag/log_pda
|
||||
|
||||
/datum/log_category/pda_chat
|
||||
category = LOG_CATEGORY_PDA_CHAT
|
||||
master_category = /datum/log_category/pda
|
||||
|
||||
/datum/log_category/pda_comment
|
||||
category = LOG_CATEGORY_PDA_COMMENT
|
||||
master_category = /datum/log_category/pda
|
||||
@@ -0,0 +1,23 @@
|
||||
/datum/log_category/uplink
|
||||
category = LOG_CATEGORY_UPLINK
|
||||
config_flag = /datum/config_entry/flag/log_uplink
|
||||
|
||||
/datum/log_category/uplink_malf
|
||||
category = LOG_CATEGORY_UPLINK_MALF
|
||||
config_flag = /datum/config_entry/flag/log_uplink
|
||||
master_category = /datum/log_category/uplink
|
||||
|
||||
/datum/log_category/uplink_heretic
|
||||
category = LOG_CATEGORY_UPLINK_HERETIC
|
||||
config_flag = /datum/config_entry/flag/log_uplink
|
||||
master_category = /datum/log_category/uplink
|
||||
|
||||
/datum/log_category/uplink_changeling
|
||||
category = LOG_CATEGORY_UPLINK_CHANGELING
|
||||
config_flag = /datum/config_entry/flag/log_uplink
|
||||
master_category = /datum/log_category/uplink
|
||||
|
||||
/datum/log_category/uplink_spell
|
||||
category = LOG_CATEGORY_UPLINK_SPELL
|
||||
config_flag = /datum/config_entry/flag/log_uplink
|
||||
master_category = /datum/log_category/uplink
|
||||
@@ -1,32 +1,56 @@
|
||||
/// The main datum that contains all log entries for a category
|
||||
/datum/log_category
|
||||
/// The category this datum contains
|
||||
/// The category name
|
||||
var/category
|
||||
|
||||
/// The schema version of this log category.
|
||||
/// Expected format of "Major.Minor.Patch"
|
||||
var/schema_version = LOG_CATEGORY_SCHEMA_VERSION_NOT_SET
|
||||
|
||||
/// The master category that contains this category
|
||||
var/datum/log_category/master_category
|
||||
|
||||
/// If set this config flag is checked to enable this log category
|
||||
var/config_flag
|
||||
/// List of all entries, in chronological order of when they were added
|
||||
var/list/entries = list()
|
||||
|
||||
/// Whether or not this log should not be publically visible
|
||||
var/secret = FALSE
|
||||
|
||||
/// Whether the readable version of the log message is formatted internally instead of by rustg
|
||||
var/internal_formatting = TRUE
|
||||
|
||||
GENERAL_PROTECT_DATUM(/datum/log_category)
|
||||
|
||||
/// Backup log category to catch attempts to log to a category that doesn't exist
|
||||
/datum/log_category/backup_category_not_found
|
||||
category = LOG_CATEGORY_NOT_FOUND
|
||||
|
||||
/// Add an entry to this category. It is very important that any data you provide doesn't hold references to anything!
|
||||
/datum/log_category/proc/add_entry(message, list/data)
|
||||
var/list/entry = list(
|
||||
LOG_ENTRY_MESSAGE = message,
|
||||
LOG_ENTRY_TIMESTAMP = big_number_to_text(rustg_unix_timestamp()),
|
||||
/datum/log_category/proc/create_entry(message, list/data, list/semver_store)
|
||||
var/datum/log_entry/entry = new(
|
||||
// world state contains raw timestamp
|
||||
timestamp = logger.human_readable_timestamp(),
|
||||
category = category,
|
||||
message = message,
|
||||
data = data,
|
||||
semver_store = semver_store,
|
||||
)
|
||||
if(data)
|
||||
entry[LOG_ENTRY_DATA] = data
|
||||
|
||||
entries += list(entry)
|
||||
write_entry(entry)
|
||||
|
||||
/// Allows for category specific file splitting. Needs to accept a null entry for the default file.
|
||||
/datum/log_category/proc/get_output_file(list/entry)
|
||||
return "[GLOB.log_directory]/[category].json"
|
||||
/// If master_category it will always return the output of master_category.get_output_file(entry)
|
||||
/datum/log_category/proc/get_output_file(list/entry, extension = "log.json")
|
||||
if(master_category)
|
||||
return master_category.get_output_file(entry, extension)
|
||||
if(secret)
|
||||
return "[GLOB.log_directory]/secret/[category].[extension]"
|
||||
return "[GLOB.log_directory]/[category].[extension]"
|
||||
|
||||
/// Writes an entry to the output file for the category
|
||||
/datum/log_category/proc/write_entry(list/entry)
|
||||
rustg_file_append("[json_encode(entry)]\n", get_output_file(entry))
|
||||
/// Writes an entry to the output file(s) for the category
|
||||
/datum/log_category/proc/write_entry(datum/log_entry/entry)
|
||||
// config isn't loaded? assume we want human readable logs
|
||||
if(isnull(config) || CONFIG_GET(flag/log_as_human_readable))
|
||||
entry.write_readable_entry_to_file(get_output_file(entry, "log"), format_internally = internal_formatting)
|
||||
|
||||
entry.write_entry_to_file(get_output_file(entry))
|
||||
|
||||
@@ -0,0 +1,114 @@
|
||||
|
||||
// Schema version must always be the very last element in the array.
|
||||
|
||||
// Current Schema: 1.0.0
|
||||
// [timestamp, category, message, data, world_state, semver_store, id, schema_version]
|
||||
|
||||
/// A datum which contains log information.
|
||||
/datum/log_entry
|
||||
/// Next id to assign to a log entry.
|
||||
var/static/next_id = 0
|
||||
|
||||
/// Unique id of the log entry.
|
||||
var/id
|
||||
|
||||
/// Schema version of the log entry.
|
||||
var/schema_version = "1.0.0"
|
||||
|
||||
/// Unix timestamp of the log entry.
|
||||
var/timestamp
|
||||
|
||||
/// Category of the log entry.
|
||||
var/category
|
||||
|
||||
/// Message of the log entry.
|
||||
var/message
|
||||
|
||||
/// Data of the log entry; optional.
|
||||
var/list/data
|
||||
|
||||
/// Semver store of the log entry, used to store the schema of data entries
|
||||
var/list/semver_store
|
||||
|
||||
GENERAL_PROTECT_DATUM(/datum/log_entry)
|
||||
|
||||
/datum/log_entry/New(timestamp, category, message, list/data, list/semver_store)
|
||||
..()
|
||||
|
||||
src.id = next_id++
|
||||
src.timestamp = timestamp
|
||||
src.category = category
|
||||
src.message = message
|
||||
with_data(data)
|
||||
with_semver_store(semver_store)
|
||||
|
||||
/datum/log_entry/proc/with_data(list/data)
|
||||
if(!isnull(data))
|
||||
if(!islist(data))
|
||||
src.data = list("data" = data)
|
||||
stack_trace("Log entry data was not a list, it was [data.type].")
|
||||
else
|
||||
src.data = data
|
||||
return src
|
||||
|
||||
/datum/log_entry/proc/with_semver_store(list/semver_store)
|
||||
if(isnull(semver_store))
|
||||
return
|
||||
if(!islist(semver_store))
|
||||
stack_trace("Log entry semver store was not a list, it was [semver_store.type]. We cannot reliably convert it to a list.")
|
||||
else
|
||||
src.semver_store = semver_store
|
||||
return src
|
||||
|
||||
/// Converts the log entry to a human-readable string.
|
||||
/datum/log_entry/proc/to_readable_text(format = TRUE)
|
||||
if(format)
|
||||
return "\[[timestamp]\] [uppertext(category)]: [message]"
|
||||
else
|
||||
return "[message]"
|
||||
|
||||
/// Converts the log entry to a JSON string.
|
||||
/datum/log_entry/proc/to_json_text()
|
||||
// I do not trust byond's json encoder, so we're doing it manually
|
||||
var/list/json_strings = list()
|
||||
|
||||
json_strings += json_encode(timestamp)
|
||||
|
||||
json_strings += json_encode(category)
|
||||
|
||||
json_strings += json_encode(message)
|
||||
|
||||
if(length(data))
|
||||
json_strings += json_encode(data)
|
||||
else
|
||||
json_strings += "null"
|
||||
|
||||
json_strings += json_encode(world.get_world_state_for_logging())
|
||||
|
||||
if(length(semver_store))
|
||||
json_strings += json_encode(semver_store)
|
||||
else
|
||||
json_strings += "null"
|
||||
|
||||
json_strings += "[id]"
|
||||
|
||||
json_strings += json_encode(schema_version)
|
||||
|
||||
return "\[[json_strings.Join(",")]\]"
|
||||
|
||||
/// Writes the log entry to a file.
|
||||
/datum/log_entry/proc/write_entry_to_file(file)
|
||||
if(!fexists(file))
|
||||
CRASH("Attempted to log to an uninitialized file: [file]")
|
||||
WRITE_LOG_NO_FORMAT(file, "[to_json_text()]\n")
|
||||
|
||||
/// Writes the log entry to a file as a human-readable string.
|
||||
/datum/log_entry/proc/write_readable_entry_to_file(file, format_internally = TRUE)
|
||||
if(!fexists(file))
|
||||
CRASH("Attempted to log to an uninitialized file: [file]")
|
||||
|
||||
// If it's being formatted internally we need to manually add a newline
|
||||
if(format_internally)
|
||||
WRITE_LOG_NO_FORMAT(file, "[to_readable_text(format = TRUE)]\n")
|
||||
else
|
||||
WRITE_LOG(file, "[to_readable_text(format = FALSE)]")
|
||||
@@ -1,6 +1,5 @@
|
||||
GLOBAL_DATUM_INIT(logger, /datum/log_holder, new)
|
||||
GLOBAL_PROTECT(logger)
|
||||
|
||||
GLOBAL_REAL(logger, /datum/log_holder)
|
||||
/**
|
||||
* Main datum to manage logging actions
|
||||
*/
|
||||
@@ -14,40 +13,58 @@ GLOBAL_PROTECT(logger)
|
||||
var/list/datum/log_category/log_categories
|
||||
/// typecache list for categories that exist but are disabled
|
||||
var/list/disabled_categories
|
||||
/// category nesting tree for ui purposes
|
||||
var/list/category_group_tree
|
||||
|
||||
/// list of Log args waiting for processing pending log initialization
|
||||
var/list/waiting_log_calls
|
||||
|
||||
/// Whether or not logging as human readable text is enabled
|
||||
var/human_readable_enabled = FALSE
|
||||
|
||||
var/initialized = FALSE
|
||||
var/shutdown = FALSE
|
||||
|
||||
GENERAL_PROTECT_DATUM(/datum/log_holder)
|
||||
|
||||
/// Assembles basic information for logging, creating the log category datums and checking for config flags as required
|
||||
/datum/log_holder/proc/init_logging()
|
||||
if(initialized)
|
||||
CRASH("Attempted to call init_logging twice!")
|
||||
initialized = TRUE
|
||||
|
||||
round_id = GLOB.round_id
|
||||
logging_start_timestamp = rustg_unix_timestamp()
|
||||
logging_start_timestamp = unix_timestamp_string()
|
||||
log_categories = list()
|
||||
disabled_categories = list()
|
||||
for(var/datum/log_category/category_type as anything in subtypesof(/datum/log_category))
|
||||
var/category = initial(category_type.category)
|
||||
if(!category)
|
||||
continue
|
||||
|
||||
if(category in log_categories)
|
||||
stack_trace("Found two identical log category type definitions! [category_type]")
|
||||
continue
|
||||
human_readable_enabled = CONFIG_GET(flag/log_as_human_readable)
|
||||
|
||||
var/config_flag = initial(category_type.config_flag)
|
||||
category_group_tree = assemble_log_category_tree()
|
||||
var/config_flag
|
||||
for(var/datum/log_category/master_category as anything in category_group_tree)
|
||||
var/list/sub_categories = category_group_tree[master_category]
|
||||
sub_categories = sub_categories.Copy()
|
||||
for(var/datum/log_category/sub_category as anything in sub_categories)
|
||||
config_flag = initial(sub_category.config_flag)
|
||||
if(config_flag && !config.Get(config_flag))
|
||||
disabled_categories[initial(sub_category.category)] = TRUE
|
||||
sub_categories -= sub_category
|
||||
continue
|
||||
|
||||
config_flag = initial(master_category.config_flag)
|
||||
if(config_flag && !config.Get(config_flag))
|
||||
disabled_categories[category] = TRUE
|
||||
continue
|
||||
category_type = log_categories[category] = new category_type
|
||||
var/list/log_start_entry = list(
|
||||
LOG_HEADER_CATEGORY = category,
|
||||
LOG_HEADER_INIT_TIMESTAMP = big_number_to_text(logging_start_timestamp),
|
||||
LOG_HEADER_ROUND_ID = big_number_to_text(GLOB.round_id),
|
||||
)
|
||||
rustg_file_write("[json_encode(log_start_entry)]\n", category_type.get_output_file(null))
|
||||
disabled_categories[initial(master_category.category)] = TRUE
|
||||
if(!length(sub_categories))
|
||||
continue
|
||||
// enabled, or any of the sub categories are enabled
|
||||
init_log_category(master_category, sub_categories)
|
||||
|
||||
initialized = TRUE
|
||||
|
||||
// process any waiting log calls and then cut the list
|
||||
for(var/list/arg_list as anything in waiting_log_calls)
|
||||
Log(arglist(arg_list))
|
||||
waiting_log_calls?.Cut()
|
||||
|
||||
if(fexists(GLOB.config_error_log))
|
||||
fcopy(GLOB.config_error_log, "[GLOB.log_directory]/config_error.log")
|
||||
@@ -61,10 +78,120 @@ GLOBAL_PROTECT(logger)
|
||||
CRASH("Attempted to call shutdown_logging twice!")
|
||||
shutdown = TRUE
|
||||
|
||||
/// This is Log because log is a byond internal proc
|
||||
/// Iterates over all log category types to assemble them into a tree of main category -> (sub category)[] while also checking for loops and sanity errors
|
||||
/datum/log_holder/proc/assemble_log_category_tree()
|
||||
var/static/list/category_tree
|
||||
if(category_tree)
|
||||
return category_tree
|
||||
|
||||
category_tree = list()
|
||||
var/list/all_types = subtypesof(/datum/log_category)
|
||||
var/list/known_categories = list()
|
||||
var/list/sub_categories = list()
|
||||
|
||||
// Assemble the master categories
|
||||
for(var/datum/log_category/category_type as anything in all_types)
|
||||
var/category = initial(category_type.category)
|
||||
if(category in known_categories)
|
||||
stack_trace("log category type '[category_type]' has duplicate category '[category]', skipping")
|
||||
continue
|
||||
|
||||
if(!initial(category_type.schema_version))
|
||||
stack_trace("log category type '[category_type]' does not have a valid schema version, skipping")
|
||||
continue
|
||||
|
||||
var/master_category = initial(category_type.master_category)
|
||||
if(master_category)
|
||||
sub_categories[master_category] += list(category_type)
|
||||
continue
|
||||
category_tree[category_type] = list()
|
||||
|
||||
// Sort the sub categories
|
||||
for(var/datum/log_category/master as anything in sub_categories)
|
||||
if(!(master in category_tree))
|
||||
stack_trace("log category [master] is an invalid master category as it's a sub category")
|
||||
continue
|
||||
for(var/datum/log_category/sub_category as anything in sub_categories[master])
|
||||
if(initial(sub_category.secret) != initial(master.secret))
|
||||
stack_trace("log category [sub_category] has a secret status that differs from its master category [master]")
|
||||
category_tree[master] += list(sub_category)
|
||||
|
||||
return category_tree
|
||||
|
||||
/// Initializes the given log category and populates the list of contained categories based on the sub category list
|
||||
/datum/log_holder/proc/init_log_category(datum/log_category/category_type, list/datum/log_category/sub_categories)
|
||||
var/datum/log_category/category_instance = new category_type
|
||||
|
||||
var/list/contained_categories = list()
|
||||
for(var/datum/log_category/sub_category as anything in sub_categories)
|
||||
sub_category = new sub_category
|
||||
var/sub_category_actual = sub_category.category
|
||||
sub_category.master_category = category_instance
|
||||
log_categories[sub_category_actual] = sub_category
|
||||
|
||||
if(!semver_to_list(sub_category.schema_version))
|
||||
stack_trace("log category [sub_category_actual] has an invalid schema version '[sub_category.schema_version]'")
|
||||
sub_category.schema_version = LOG_CATEGORY_SCHEMA_VERSION_NOT_SET
|
||||
|
||||
contained_categories += sub_category_actual
|
||||
|
||||
log_categories[category_instance.category] = category_instance
|
||||
|
||||
if(!semver_to_list(category_instance.schema_version))
|
||||
stack_trace("log category [category_instance.category] has an invalid schema version '[category_instance.schema_version]'")
|
||||
category_instance.schema_version = LOG_CATEGORY_SCHEMA_VERSION_NOT_SET
|
||||
|
||||
contained_categories += category_instance.category
|
||||
|
||||
var/list/category_header = list(
|
||||
LOG_HEADER_INIT_TIMESTAMP = logging_start_timestamp,
|
||||
LOG_HEADER_ROUND_ID = big_number_to_text(GLOB.round_id),
|
||||
LOG_HEADER_SECRET = category_instance.secret,
|
||||
LOG_HEADER_CATEGORY_LIST = contained_categories,
|
||||
LOG_HEADER_CATEGORY = category_instance.category,
|
||||
)
|
||||
|
||||
rustg_file_write("[json_encode(category_header)]\n", category_instance.get_output_file(null))
|
||||
if(human_readable_enabled)
|
||||
rustg_file_write("\[[human_readable_timestamp()]\] Starting up round ID [round_id].\n - -------------------------\n", category_instance.get_output_file(null, "log"))
|
||||
|
||||
/datum/log_holder/proc/unix_timestamp_string() // pending change to rust-g
|
||||
return RUSTG_CALL(RUST_G, "unix_timestamp")()
|
||||
|
||||
/datum/log_holder/proc/human_readable_timestamp(precision = 3)
|
||||
var/start = time2text(world.timeofday, "YYYY-MM-DD hh:mm:ss")
|
||||
// now we grab the millis from the rustg timestamp
|
||||
var/list/timestamp = splittext(unix_timestamp_string(), ".")
|
||||
var/millis = timestamp[2]
|
||||
if(length(millis) > precision)
|
||||
millis = copytext(millis, 1, precision + 1)
|
||||
return "[start].[millis]"
|
||||
|
||||
/// Adds an entry to the given category, if the category is disabled it will not be logged.
|
||||
/// If the category does not exist, we will CRASH and log to the error category.
|
||||
/// the data list is optional and will be recursively json serialized.
|
||||
/datum/log_holder/proc/Log(category, message, list/data)
|
||||
if(!initialized || shutdown)
|
||||
CRASH("Attempted to perform logging before initializion or after shutdown!")
|
||||
// This is Log because log is a byond internal proc
|
||||
if(shutdown)
|
||||
stack_trace("Performing logging after shutdown! This might not be functional in the future!")
|
||||
// but for right now it's fine
|
||||
|
||||
// do not include the message because these go into the runtime log and we might be secret!
|
||||
if(!istext(message))
|
||||
message = "[message]"
|
||||
stack_trace("Logging with a non-text message")
|
||||
|
||||
if(!category)
|
||||
category = LOG_CATEGORY_NOT_FOUND
|
||||
stack_trace("Logging with a null or empty category")
|
||||
|
||||
if(data && !islist(data))
|
||||
data = list("data" = data)
|
||||
stack_trace("Logging with data this is not a list, it will be converted to a list with a single key 'data'")
|
||||
|
||||
if(!initialized) // we are initialized during /world/proc/SetupLogging which is called in /world/New
|
||||
waiting_log_calls += list(list(category, message, data))
|
||||
return
|
||||
|
||||
if(disabled_categories[category])
|
||||
return
|
||||
@@ -73,4 +200,49 @@ GLOBAL_PROTECT(logger)
|
||||
if(!log_category)
|
||||
Log(LOG_CATEGORY_NOT_FOUND, message, data)
|
||||
CRASH("Attempted to log to a category that doesn't exist! [category]")
|
||||
log_category.add_entry(message, data)
|
||||
|
||||
var/list/semver_store = null
|
||||
if(length(data))
|
||||
semver_store = list()
|
||||
data = recursive_jsonify(data, semver_store)
|
||||
log_category.create_entry(message, data, semver_store)
|
||||
|
||||
/// Recursively converts an associative list of datums into their jsonified(list) form
|
||||
/datum/log_holder/proc/recursive_jsonify(list/data_list, list/semvers)
|
||||
if(isnull(data_list))
|
||||
return null
|
||||
|
||||
var/list/jsonified_list = list()
|
||||
for(var/key in data_list)
|
||||
var/datum/data = data_list[key]
|
||||
|
||||
if(isnull(data))
|
||||
// do nothing - nulls are allowed
|
||||
|
||||
else if(islist(data))
|
||||
data = recursive_jsonify(data, semvers)
|
||||
|
||||
else if(isdatum(data))
|
||||
var/list/options_list = list(
|
||||
SCHEMA_VERSION = LOG_CATEGORY_SCHEMA_VERSION_NOT_SET,
|
||||
)
|
||||
|
||||
var/list/serialization_data = data.serialize_list(options_list, semvers)
|
||||
var/current_semver = semvers[data.type]
|
||||
if(!semver_to_list(current_semver))
|
||||
stack_trace("serialization of data had an invalid semver")
|
||||
semvers[data.type] = LOG_CATEGORY_SCHEMA_VERSION_NOT_SET
|
||||
|
||||
if(!length(serialization_data)) // serialize_list wasn't implemented, and errored
|
||||
stack_trace("serialization data was empty")
|
||||
continue
|
||||
|
||||
data = recursive_jsonify(serialization_data, semvers)
|
||||
|
||||
if(islist(data) && !length(data))
|
||||
stack_trace("recursive_jsonify got an empty list after serialization")
|
||||
continue
|
||||
|
||||
jsonified_list[key] = data
|
||||
|
||||
return jsonified_list
|
||||
|
||||
@@ -241,7 +241,7 @@ GLOBAL_LIST_EMPTY(silo_access_logs)
|
||||
"raw_materials" = get_raw_materials(""),
|
||||
"direction" = amount < 0 ? "withdrawn" : "deposited",
|
||||
)
|
||||
GLOB.logger.Log(
|
||||
logger.Log(
|
||||
LOG_CATEGORY_SILO,
|
||||
"[machine_name] in \[[AREACOORD(M)]\] [action] [abs(amount)]x [noun] | [get_raw_materials("")]",
|
||||
data,
|
||||
|
||||
@@ -109,6 +109,17 @@
|
||||
. = ..()
|
||||
tag = "mob_[next_mob_id++]"
|
||||
|
||||
/mob/serialize_list(list/options, list/semvers)
|
||||
. = ..()
|
||||
|
||||
.["tag"] = tag
|
||||
.["name"] = name
|
||||
.["ckey"] = ckey
|
||||
.["key"] = key
|
||||
|
||||
SET_SERIALIZATION_SEMVER(semvers, "1.0.0")
|
||||
return .
|
||||
|
||||
/**
|
||||
* set every hud image in the given category active so other people with the given hud can see it.
|
||||
* Arguments:
|
||||
|
||||
@@ -513,7 +513,7 @@
|
||||
"name" = offhand.name,
|
||||
)
|
||||
|
||||
GLOB.logger.Log(
|
||||
logger.Log(
|
||||
LOG_CATEGORY_TARGET_ZONE_SWITCH,
|
||||
"[key_name(src)] manually changed selected zone",
|
||||
data,
|
||||
|
||||
@@ -58,8 +58,9 @@
|
||||
ic.Blend(small_img,ICON_OVERLAY, 13, 13)
|
||||
picture_icon = ic
|
||||
|
||||
/datum/picture/serialize_list(list/options)
|
||||
. = list()
|
||||
/datum/picture/serialize_list(list/options, list/semvers)
|
||||
. = ..()
|
||||
|
||||
.["id"] = id
|
||||
.["desc"] = picture_desc
|
||||
.["name"] = picture_name
|
||||
@@ -69,9 +70,19 @@
|
||||
.["blueprints"] = has_blueprints
|
||||
.["logpath"] = logpath
|
||||
|
||||
SET_SERIALIZATION_SEMVER(semvers, "1.0.0")
|
||||
return .
|
||||
|
||||
/datum/picture/deserialize_list(list/input, list/options)
|
||||
if((SCHEMA_VERSION in options) && (options[SCHEMA_VERSION] != "1.0.0"))
|
||||
CRASH("Invalid schema version for datum/picture: [options[SCHEMA_VERSION]] (expected 1.0.0)")
|
||||
. = ..()
|
||||
if(!.)
|
||||
return .
|
||||
|
||||
if(!input["logpath"] || !fexists(input["logpath"]) || !input["id"] || !input["pixel_size_x"] || !input["pixel_size_y"])
|
||||
return
|
||||
return FALSE
|
||||
|
||||
picture_image = icon(file(input["logpath"]))
|
||||
logpath = input["logpath"]
|
||||
id = input["id"]
|
||||
@@ -85,7 +96,6 @@
|
||||
picture_desc = input["desc"]
|
||||
if(input["name"])
|
||||
picture_name = input["name"]
|
||||
return src
|
||||
|
||||
/proc/load_photo_from_disk(id, location)
|
||||
var/datum/picture/P = load_picture_from_disk(id)
|
||||
|
||||
+1
-97
@@ -3,6 +3,7 @@
|
||||
$include game_options.txt
|
||||
$include dbconfig.txt
|
||||
$include comms.txt
|
||||
$include logging.txt
|
||||
$include resources.txt
|
||||
$include interviews.txt
|
||||
$include lua.txt
|
||||
@@ -80,103 +81,6 @@ ENABLE_LOCALHOST_RANK
|
||||
## If USE_LOW_LIVING_HOUR_INTERN is unhashed, players under this number of living hours have [Intern] added to their ID card. If this isn't set, uses USE_EXP_RESTRICTIONS_HEADS_HOURS instead. If that isn't set, it finally defaults to a hardcoded fallback of 15 hours.
|
||||
#USE_LOW_LIVING_HOUR_INTERN_HOURS 50
|
||||
|
||||
## log OOC channel
|
||||
LOG_OOC
|
||||
|
||||
## log client Say
|
||||
LOG_SAY
|
||||
|
||||
## log admin actions
|
||||
LOG_ADMIN
|
||||
|
||||
## log admin chat
|
||||
LOG_ADMINCHAT
|
||||
|
||||
## log asset debug logs
|
||||
#LOG_ASSET
|
||||
|
||||
## log client access (logon/logoff)
|
||||
LOG_ACCESS
|
||||
|
||||
## Enables log entries for logins that failed due to suspicious circumstances (banned player, CID randomiser, spoofed BYOND version, etc.) to a dedicated file.
|
||||
LOG_SUSPICIOUS_LOGIN
|
||||
|
||||
## log game actions (start of round, results, etc.)
|
||||
LOG_GAME
|
||||
|
||||
## log player votes
|
||||
LOG_VOTE
|
||||
|
||||
## log manual target zone switching
|
||||
LOG_ZONE_SWITCH
|
||||
|
||||
## log client Whisper
|
||||
LOG_WHISPER
|
||||
|
||||
## log emotes
|
||||
LOG_EMOTE
|
||||
|
||||
## log attack messages
|
||||
LOG_ATTACK
|
||||
|
||||
## log pda messages
|
||||
LOG_PDA
|
||||
|
||||
## log uplink purchases
|
||||
LOG_UPLINK
|
||||
|
||||
## log telecomms messages
|
||||
LOG_TELECOMMS
|
||||
|
||||
## log prayers
|
||||
LOG_PRAYER
|
||||
|
||||
## Log Music requests
|
||||
LOG_INTERNET_REQUEST
|
||||
|
||||
## log silicons
|
||||
LOG_SILICON
|
||||
|
||||
## log economy actions
|
||||
LOG_ECON
|
||||
|
||||
## log traitor objectives
|
||||
LOG_TRAITOR
|
||||
|
||||
## log crew manifest to separate file
|
||||
LOG_MANIFEST
|
||||
|
||||
## log job divide debugging information
|
||||
#LOG_JOB_DEBUG
|
||||
|
||||
## log all world.Topic() calls
|
||||
# LOG_WORLD_TOPIC
|
||||
|
||||
## enables use of the proc twitterize() that lets you take a large list of strings and turn it into a JSON file of tweet sized strings.
|
||||
## As an example of how this could be """useful""" look towards Poly (https://twitter.com/Poly_the_Parrot)
|
||||
# LOG_TWITTER
|
||||
|
||||
## Enable logging pictures
|
||||
LOG_PICTURES
|
||||
|
||||
## log mecha actions
|
||||
# LOG_MECHA
|
||||
|
||||
## log virus and actions
|
||||
LOG_VIRUS
|
||||
|
||||
## log shuttle actions
|
||||
LOG_SHUTTLE
|
||||
|
||||
## log tool interactions [/atom/proc/tool_act]
|
||||
LOG_TOOLS
|
||||
|
||||
## Log all timers on timer auto reset
|
||||
# LOG_TIMERS_ON_BUCKET_RESET
|
||||
|
||||
## log speech indicators
|
||||
LOG_SPEECH_INDICATORS
|
||||
|
||||
##Log camera pictures - Must have picture logging enabled
|
||||
PICTURE_LOGGING_CAMERA
|
||||
|
||||
|
||||
@@ -0,0 +1,103 @@
|
||||
### Config Flags for logging, compatibility flags are at the top
|
||||
|
||||
## Whether or not admin/adminprivate logging is also sent to LOG_CATEGORY_GAME for legacy log parsers
|
||||
LOGGING_COMPAT_ADMINPRIVATE
|
||||
|
||||
## Should we also log entries as human readable
|
||||
LOG_AS_HUMAN_READABLE
|
||||
|
||||
### Actual logging flags
|
||||
|
||||
## log client access (logon/logoff)
|
||||
LOG_ACCESS
|
||||
|
||||
## log admin actions
|
||||
LOG_ADMIN
|
||||
|
||||
## log admin chat
|
||||
LOG_ADMINCHAT
|
||||
|
||||
## log asset debug logs
|
||||
# LOG_ASSET
|
||||
|
||||
## log attack messages
|
||||
LOG_ATTACK
|
||||
|
||||
## log economy actions
|
||||
LOG_ECON
|
||||
|
||||
## log emotes
|
||||
LOG_EMOTE
|
||||
|
||||
## log game actions (start of round, results, etc.)
|
||||
LOG_GAME
|
||||
|
||||
## log job divide debugging information
|
||||
# LOG_JOB_DEBUG
|
||||
|
||||
## log crew manifest to separate file
|
||||
LOG_MANIFEST
|
||||
|
||||
## log mecha actions
|
||||
# LOG_MECHA
|
||||
|
||||
## log OOC channel
|
||||
LOG_OOC
|
||||
|
||||
## log pda messages
|
||||
LOG_PDA
|
||||
|
||||
## Enable logging pictures
|
||||
LOG_PICTURES
|
||||
|
||||
## log prayers
|
||||
LOG_PRAYER
|
||||
|
||||
## log client Say
|
||||
LOG_SAY
|
||||
|
||||
## log shuttle actions
|
||||
LOG_SHUTTLE
|
||||
|
||||
## log silicons
|
||||
LOG_SILICON
|
||||
|
||||
## log speech indicators
|
||||
LOG_SPEECH_INDICATORS
|
||||
|
||||
## Enables log entries for logins that failed due to suspicious circumstances (banned player, CID randomiser, spoofed BYOND version, etc.) to a dedicated file.
|
||||
LOG_SUSPICIOUS_LOGIN
|
||||
|
||||
## log telecomms messages
|
||||
LOG_TELECOMMS
|
||||
|
||||
## Log all timers on timer auto reset
|
||||
# LOG_TIMERS_ON_BUCKET_RESET
|
||||
|
||||
## log tool interactions [/atom/proc/tool_act]
|
||||
LOG_TOOLS
|
||||
|
||||
## log traitor objectives
|
||||
LOG_TRAITOR
|
||||
|
||||
## enables use of the proc twitterize() that lets you take a large list of strings and turn it into a JSON file of tweet sized strings.
|
||||
## As an example of how this could be """useful""" look towards Poly (https://twitter.com/Poly_the_Parrot)
|
||||
# LOG_TWITTER
|
||||
|
||||
## log uplink purchases
|
||||
LOG_UPLINK
|
||||
|
||||
## log virus and actions
|
||||
LOG_VIRUS
|
||||
|
||||
## log player votes
|
||||
LOG_VOTE
|
||||
|
||||
## log client Whisper
|
||||
LOG_WHISPER
|
||||
|
||||
## log all world.Topic() calls
|
||||
# LOG_WORLD_TOPIC
|
||||
|
||||
## log manual target zone switching
|
||||
LOG_ZONE_SWITCH
|
||||
@@ -3734,9 +3734,17 @@
|
||||
#include "code\modules\lighting\lighting_turf.dm"
|
||||
#include "code\modules\lighting\static_lighting_area.dm"
|
||||
#include "code\modules\logging\log_category.dm"
|
||||
#include "code\modules\logging\log_entry.dm"
|
||||
#include "code\modules\logging\log_holder.dm"
|
||||
#include "code\modules\logging\categories\log_category_admin.dm"
|
||||
#include "code\modules\logging\categories\log_category_compats.dm"
|
||||
#include "code\modules\logging\categories\log_category_debug.dm"
|
||||
#include "code\modules\logging\categories\log_category_game.dm"
|
||||
#include "code\modules\logging\categories\log_category_misc.dm"
|
||||
#include "code\modules\logging\categories\log_category_pda.dm"
|
||||
#include "code\modules\logging\categories\log_category_silo.dm"
|
||||
#include "code\modules\logging\categories\log_category_target_zone_switch.dm"
|
||||
#include "code\modules\logging\categories\log_category_uplink.dm"
|
||||
#include "code\modules\mafia\_defines.dm"
|
||||
#include "code\modules\mafia\controller.dm"
|
||||
#include "code\modules\mafia\map_pieces.dm"
|
||||
|
||||
Reference in New Issue
Block a user