-
Notifications
You must be signed in to change notification settings - Fork 269
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add verbs for downloading debug/runtime logs (#2298)
* Add verbs for downloading debug/runtime logs * fix a runtime error
- Loading branch information
Showing
8 changed files
with
263 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,63 @@ | ||
/client/proc/browse_files(root_type = BROWSE_ROOT_ALL_LOGS, max_iterations = 10, list/valid_extensions = list("txt", "log", "htm", "html", "gz", "json"), list/whitelist = null, allow_folder = TRUE) | ||
var/regex/valid_ext_regex = new("\\.(?:[regex_quote_list(valid_extensions)])$", "i") | ||
var/regex/whitelist_regex | ||
if(whitelist) | ||
// try not to look at it too hard. yes i wrote this by hand. | ||
whitelist_regex = new("(?:\[\\/\\\\\]$|(?:^|\\\\|\\/)(?:[regex_quote_list(whitelist)])\\.(?:[regex_quote_list(valid_extensions)])$)", "i") | ||
|
||
// wow why was this ever a parameter | ||
var/root = "data/logs/" | ||
switch(root_type) | ||
if(BROWSE_ROOT_ALL_LOGS) | ||
root = "data/logs/" | ||
if(BROWSE_ROOT_CURRENT_LOGS) | ||
root = "[GLOB.log_directory]/" | ||
var/path = root | ||
|
||
for(var/i in 1 to max_iterations) | ||
var/list/choices | ||
if(whitelist_regex) | ||
choices = list() | ||
for(var/listed_path in flist(path)) | ||
if(whitelist_regex.Find(listed_path)) | ||
choices += listed_path | ||
else | ||
choices = flist(path) | ||
if(path != root) | ||
choices.Insert(1, "/") | ||
choices = sort_list(choices) | ||
if(allow_folder) | ||
choices += "Download Folder" | ||
|
||
var/choice = tgui_input_list(src, "Choose a file to access", "Download", choices) | ||
if(!choice) | ||
return | ||
switch(choice) | ||
if("/") | ||
path = root | ||
continue | ||
if("Download Folder") | ||
if(!allow_folder) | ||
return | ||
var/list/comp_flist = flist(path) | ||
var/confirmation = input(src, "Are you SURE you want to download all the files in this folder? (This will open [length(comp_flist)] prompt[length(comp_flist) == 1 ? "" : "s"])", "Confirmation") in list("Yes", "No") | ||
if(confirmation != "Yes") | ||
continue | ||
for(var/file in comp_flist) | ||
src << ftp(path + file) | ||
return | ||
path += choice | ||
|
||
if(copytext_char(path, -1) != "/") //didn't choose a directory, no need to iterate again | ||
break | ||
if(!fexists(path) || !valid_ext_regex.Find(path)) | ||
to_chat(src, "<font color='red'>Error: browse_files(): File not found/Invalid file([path]).</font>") | ||
return | ||
|
||
return path | ||
|
||
/proc/regex_quote_list(list/input) as text | ||
var/list/sanitized = list() | ||
for(var/thingy in input) | ||
sanitized += REGEX_QUOTE(thingy) | ||
return jointext(sanitized, "|") |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,53 @@ | ||
GLOBAL_LIST(debug_logfile_names) | ||
GLOBAL_PROTECT(debug_logfile_names) | ||
|
||
/client/proc/getserverlogs_debug() | ||
set name = "Get Server Logs (Debug)" | ||
set desc = "View/retrieve debug-related logfiles." | ||
set category = "Debug" | ||
if(!check_rights_for(src, R_DEBUG)) | ||
return | ||
get_debug_logfiles() | ||
if(!GLOB.debug_logfile_names) | ||
return | ||
browseserverlogs(whitelist = GLOB.debug_logfile_names, allow_folder = FALSE) | ||
|
||
/client/proc/getcurrentlogs_debug() | ||
set name = "Get Current Logs (Debug)" | ||
set desc = "View/retrieve debug-related logfiles for the current round." | ||
set category = "Debug" | ||
if(!check_rights_for(src, R_DEBUG)) | ||
return | ||
get_debug_logfiles() | ||
if(!GLOB.debug_logfile_names) | ||
return | ||
browseserverlogs(current = TRUE, whitelist = GLOB.debug_logfile_names, allow_folder = FALSE) | ||
|
||
/client/proc/browseserverlogs(current = FALSE, list/whitelist = null, allow_folder = TRUE) | ||
var/path = browse_files(current ? BROWSE_ROOT_CURRENT_LOGS : BROWSE_ROOT_ALL_LOGS, whitelist = whitelist, allow_folder = allow_folder) | ||
if(!path || !fexists(path)) | ||
return | ||
|
||
if(file_spam_check()) | ||
return | ||
|
||
message_admins("[key_name_admin(src)] accessed file: [path]") | ||
switch(tgui_alert(usr, "View (in game), Open (in your system's text editor), or Download?", path, list("View", "Open", "Download"))) | ||
if ("View") | ||
src << browse("<pre style='word-wrap: break-word;'>[html_encode(file2text(file(path)))]</pre>", list2params(list("window" = "viewfile.[path]"))) | ||
if ("Open") | ||
src << run(file(path)) | ||
if ("Download") | ||
src << ftp(file(path)) | ||
else | ||
return | ||
to_chat(src, span_boldnotice("Attempting to send [path], this may take a fair few minutes if the file is very large."), confidential = TRUE) | ||
return | ||
|
||
/proc/get_debug_logfiles() | ||
if(!logger.initialized || GLOB.debug_logfile_names) | ||
return | ||
for(var/datum/log_category/category as anything in logger.log_categories) | ||
category = logger.log_categories[category] | ||
if(is_category_debug_visible(category)) | ||
LAZYOR(GLOB.debug_logfile_names, get_category_logfile(category)) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,49 @@ | ||
/datum/log_category | ||
/// If non-admin debuggers (+DEBUG without +ADMIN) can see logs from this category or not. | ||
/// When set to null, it will assume the value of the parent category (which will default to FALSE if not set). | ||
var/debugger_visible = null | ||
|
||
/datum/log_category/debug | ||
debugger_visible = TRUE | ||
|
||
/datum/log_category/debug_sql | ||
debugger_visible = FALSE | ||
|
||
/datum/log_category/debug_href | ||
debugger_visible = FALSE | ||
|
||
/datum/log_category/debug_runtime | ||
debugger_visible = TRUE | ||
|
||
/// Recursively checks to see if a log category or any of its parent categories is marked as "debugger_visible" or not. | ||
/// Caches the result. | ||
/proc/is_category_debug_visible(datum/log_category/category) | ||
var/static/list/cached_visibility | ||
if(!cached_visibility) | ||
cached_visibility = list(/datum/log_category = FALSE) | ||
var/datum/log_category/category_path = ispath(category) ? category : (istext(category) ? logger.log_categories[category]?.type : category?.type) | ||
if(!category) | ||
return FALSE | ||
if(!isnull(cached_visibility[category_path])) | ||
. = cached_visibility[category_path] | ||
else if(!isnull(category_path::debugger_visible)) | ||
. = cached_visibility[category_path] = category_path::debugger_visible | ||
else if(!isnull(category_path::master_category) && category_path::master_category != category_path) // safety check to prevent infinite recursion, prolly not needed but better safe than sorry | ||
. = cached_visibility[category_path] = is_category_debug_visible(category_path::master_category) | ||
else | ||
. = cached_visibility[category_path] = FALSE | ||
|
||
/proc/get_category_logfile(datum/log_category/category) | ||
var/static/list/cached_filenames | ||
if(!cached_filenames) | ||
cached_filenames = list() | ||
if(!category) | ||
return FALSE | ||
var/datum/log_category/category_path = ispath(category) ? category : (istext(category) ? logger.log_categories[category].type : category.type) | ||
if(!isnull(cached_filenames[category_path])) | ||
. = cached_filenames[category_path] | ||
else if(!isnull(category_path::master_category)) | ||
var/datum/log_category/master_category = category_path::master_category | ||
. = cached_filenames[master_category] = cached_filenames[category_path] = master_category::category | ||
else | ||
. = cached_filenames[category_path] = category_path::category |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,85 @@ | ||
/datum/log_holder | ||
/// Cached ui_data for debuggers | ||
var/list/debug_data_cache = list() | ||
|
||
/datum/log_holder/ui_interact(mob/user, datum/tgui/ui) | ||
if(!check_rights_for(user.client, R_ADMIN | R_DEBUG)) | ||
return | ||
|
||
ui = SStgui.try_update_ui(user, src, ui) | ||
if(isnull(ui)) | ||
ui = new(user, src, "LogViewer") | ||
ui.set_autoupdate(FALSE) | ||
ui.open() | ||
|
||
/datum/log_holder/ui_status(mob/user, datum/ui_state/state) | ||
return check_rights_for(user.client, R_ADMIN | R_DEBUG) ? UI_INTERACTIVE : UI_CLOSE | ||
|
||
/datum/log_holder/ui_static_data(mob/user) | ||
var/list/data = list( | ||
"round_id" = GLOB.round_id, | ||
"logging_start_timestamp" = logging_start_timestamp, | ||
) | ||
var/debug_user = is_user_debug_only(user) | ||
|
||
var/list/tree = list() | ||
data["tree"] = tree | ||
var/list/enabled_categories = list() | ||
for(var/enabled in log_categories) | ||
if(debug_user && !is_category_debug_visible(log_categories[enabled])) | ||
continue | ||
enabled_categories += enabled | ||
tree["enabled"] = enabled_categories | ||
|
||
var/list/disabled_categories = list() | ||
for(var/disabled in src.disabled_categories) | ||
if(debug_user && !is_category_debug_visible(disabled)) | ||
continue | ||
disabled_categories += disabled | ||
tree["disabled"] = disabled_categories | ||
|
||
return data | ||
|
||
/datum/log_holder/ui_data(mob/user) | ||
if(!last_data_update || (world.time - last_data_update) > LOG_UPDATE_TIMEOUT) | ||
cache_ui_data() | ||
return is_user_debug_only(user) ? debug_data_cache : data_cache | ||
|
||
/datum/log_holder/cache_ui_data() | ||
var/list/category_map = list() | ||
var/list/debug_category_map = list() | ||
for(var/datum/log_category/category as anything in log_categories) | ||
category = log_categories[category] | ||
var/list/category_data = list() | ||
|
||
var/list/entries = list() | ||
for(var/datum/log_entry/entry as anything in category.entries) | ||
entries += list(list( | ||
"id" = entry.id, | ||
"message" = entry.message, | ||
"timestamp" = entry.timestamp, | ||
"data" = entry.data, | ||
"semver" = entry.semver_store, | ||
)) | ||
category_data["entries"] = entries | ||
category_data["entry_count"] = category.entry_count | ||
|
||
category_map[category.category] = category_data | ||
if(is_category_debug_visible(category)) | ||
debug_category_map[category.category] = category_data | ||
|
||
data_cache.Cut() | ||
debug_data_cache.Cut() | ||
last_data_update = world.time | ||
|
||
data_cache["categories"] = category_map | ||
data_cache["last_data_update"] = last_data_update | ||
|
||
debug_data_cache["categories"] = debug_category_map | ||
debug_data_cache["last_data_update"] = last_data_update | ||
|
||
/// Checks to see if a user has +DEBUG without +ADMIN permissions. | ||
/// Used to give +DEBUG holders "limited" versions of some admin commands for debugging purposes. | ||
/proc/is_user_debug_only(mob/user) | ||
var/client/client = user.client | ||
return client.holder && check_rights_for(client, R_DEBUG) && !check_rights_for(client, R_ADMIN) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters