Skip to content

Commit

Permalink
improve logging by pre-buffering before log open and sanitizing PII p…
Browse files Browse the repository at this point in the history
…aths
  • Loading branch information
nikitalita committed Dec 8, 2024
1 parent a38ce01 commit 00903c7
Show file tree
Hide file tree
Showing 4 changed files with 99 additions and 29 deletions.
32 changes: 31 additions & 1 deletion utility/gdre_logger.cpp
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
#include "gdre_logger.h"
#include "core/os/mutex.h"
#include "editor/gdre_editor.h"
#include "gdre_settings.h"

Expand All @@ -23,7 +24,7 @@ void GDRELogger::logv(const char *p_format, va_list p_list, bool p_err) {
if (disabled || !should_log(p_err)) {
return;
}
if (file.is_valid() || inGuiMode()) {
if (file.is_valid() || inGuiMode() || is_prebuffering) {
const int static_buf_size = 512;
char static_buf[static_buf_size];
char *buf = static_buf;
Expand All @@ -49,6 +50,12 @@ void GDRELogger::logv(const char *p_format, va_list p_list, bool p_err) {
file->flush();
}
}
if (is_prebuffering) {
MutexLock lock(buffer_mutex);
if (is_prebuffering) {
buffer.push_back(String(buf));
}
}
if (len >= static_buf_size) {
Memory::free_static(buf);
}
Expand All @@ -67,9 +74,32 @@ Error GDRELogger::open_file(const String &p_base_path) {
file = FileAccess::open(p_base_path, FileAccess::WRITE, &err);
ERR_FAIL_COND_V_MSG(file.is_null(), err, "Failed to open log file " + p_base_path + " for writing.");
base_path = p_base_path.simplify_path();
{
MutexLock lock(buffer_mutex);
if (is_prebuffering) {
for (int i = 0; i < buffer.size(); i++) {
file->store_string(buffer[i]);
}
is_prebuffering = false;
buffer.clear();
}
}

return OK;
}

void GDRELogger::start_prebuffering() {
is_prebuffering = true;
}

void GDRELogger::stop_prebuffering() {
if (is_prebuffering) {
MutexLock lock(buffer_mutex);
is_prebuffering = false;
buffer.clear();
}
}

void GDRELogger::close_file() {
if (file.is_valid()) {
file->flush();
Expand Down
7 changes: 6 additions & 1 deletion utility/gdre_logger.h
Original file line number Diff line number Diff line change
@@ -1,18 +1,23 @@
#pragma once

#include "core/io/logger.h"
#include "core/templates/safe_refcount.h"

class GDRELogger : public Logger {
Ref<FileAccess> file;
String base_path;
bool disabled = false;
static std::atomic<uint64_t> error_count;
thread_local static uint64_t thread_error_count;
bool is_prebuffering = false;
Mutex buffer_mutex;
Vector<String> buffer;

public:
String get_path() { return base_path; };
GDRELogger();
bool is_prebuffering_enabled() { return is_prebuffering; }
void start_prebuffering();
void stop_prebuffering();
Error open_file(const String &p_base_path);
void close_file();
void _disable(); // only used for during cleanup, because we can't remove the logger
Expand Down
87 changes: 60 additions & 27 deletions utility/gdre_settings.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -479,39 +479,64 @@ bool is_zip_file_pack(const String &p_path) {
return false;
}

// For printing out paths, we want to replace the home directory with ~ to keep PII out of logs
String GDRESettings::sanitize_home_in_path(const String &p_path) {
#ifdef WINDOWS_ENABLED
String home_dir = OS::get_singleton()->get_environment("USERPROFILE");
#else
String home_dir = OS::get_singleton()->get_environment("HOME");
#endif
if (p_path.begins_with(home_dir)) {
return String("~").path_join(p_path.replace_first(home_dir, ""));
}
return p_path;
}

Error GDRESettings::load_project(const Vector<String> &p_paths, bool _cmd_line_extract) {
if (is_pack_loaded()) {
return ERR_ALREADY_IN_USE;
}

if (p_paths.is_empty()) {
ERR_FAIL_V_MSG(ERR_FILE_NOT_FOUND, "No valid paths provided!");
}
String p_path = p_paths[0];

if (logger->get_path().is_empty()) {
logger->start_prebuffering();
log_sysinfo();
}

Error err = ERR_CANT_OPEN;
if (DirAccess::exists(p_path)) {
if (p_paths.size() > 1) {
Vector<String> pck_files = p_paths;
// This may be a ".app" bundle, so we need to check if it's a valid Godot app
// and if so, load the pck from inside the bundle
if (pck_files[0].get_extension().to_lower() == "app" && DirAccess::exists(pck_files[0])) {
if (pck_files.size() > 1) {
ERR_FAIL_V_MSG(ERR_FILE_NOT_FOUND, "Cannot specify multiple directories!");
}
// This may be a ".app" bundle, so we need to check if it's a valid Godot app
// and if so, load the pck from inside the bundle
if (p_path.get_extension().to_lower() == "app") {
String resources_path = p_path.path_join("Contents").path_join("Resources");
if (DirAccess::exists(resources_path)) {
auto list = gdre::get_recursive_dir_list(resources_path, { "*.pck" }, true);
if (!list.is_empty()) {
return load_project(list, _cmd_line_extract);
} else {
ERR_FAIL_V_MSG(ERR_FILE_NOT_FOUND, "Can't find pck file in .app bundle!");
}
String resources_path = pck_files[0].path_join("Contents").path_join("Resources");
if (DirAccess::exists(resources_path)) {
auto list = gdre::get_recursive_dir_list(resources_path, { "*.pck" }, true);
if (!list.is_empty()) {
pck_files = list;
} else {
ERR_FAIL_V_MSG(ERR_FILE_NOT_FOUND, "Can't find pck file in .app bundle!");
}
}
print_line("Opening file: " + p_path);
err = load_dir(p_path);
}

if (DirAccess::exists(pck_files[0])) {
if (pck_files.size() > 1) {
ERR_FAIL_V_MSG(ERR_FILE_NOT_FOUND, "Cannot specify multiple directories!");
}
print_line("Opening file: " + sanitize_home_in_path(pck_files[0]));
err = load_dir(pck_files[0]);
ERR_FAIL_COND_V_MSG(err, err, "FATAL ERROR: Can't load project directory!");
load_pack_uid_cache();
} else {
for (auto path : p_paths) {
print_line("Opening file: " + path);
for (auto path : pck_files) {
auto san_path = sanitize_home_in_path(path);
print_line("Opening file: " + san_path);
if (check_embedded(path) != OK) {
String new_path = path;
String parent_path = path.get_base_dir();
Expand All @@ -526,27 +551,27 @@ Error GDRESettings::load_project(const Vector<String> &p_paths, bool _cmd_line_e
new_path = pck_path;
err = OK;
}
if (p_paths.has(new_path)) {
if (pck_files.has(new_path)) {
// we already tried this path
WARN_PRINT("EXE does not have an embedded pck, not loading " + path);
WARN_PRINT("EXE does not have an embedded pck, not loading " + san_path);
continue;
}
}
if (err != OK) {
String pck_path = path.get_basename() + ".pck";
bool only_1_path = p_paths.size() == 1;
bool already_has_path = p_paths.has(pck_path);
bool only_1_path = pck_files.size() == 1;
bool already_has_path = pck_files.has(pck_path);
bool exists = FileAccess::exists(pck_path);
if (!only_1_path && (already_has_path || !exists)) {
// we already tried this path
WARN_PRINT("EXE does not have an embedded pck, not loading " + path);
WARN_PRINT("EXE does not have an embedded pck, not loading " + san_path);
continue;
}
ERR_FAIL_COND_V_MSG(!exists, err, "Can't find embedded pck file in executable and cannot find pck file in same directory!");
new_path = pck_path;
}
path = new_path;
WARN_PRINT("Could not find embedded pck in EXE, found pck file, loading from: " + path);
WARN_PRINT("Could not find embedded pck in EXE, found pck file, loading from: " + san_path);
}
err = load_pck(path);
if (err) {
Expand All @@ -561,7 +586,7 @@ Error GDRESettings::load_project(const Vector<String> &p_paths, bool _cmd_line_e
auto zip_files = get_file_list({ "*.zip" });
if (zip_files.size() > 0) {
Vector<String> pck_zip_files;
for (auto path : p_paths) {
for (auto path : pck_files) {
if (path.get_extension().to_lower() == "zip") {
pck_zip_files.push_back(path.get_file().to_lower());
}
Expand Down Expand Up @@ -857,6 +882,7 @@ Error GDRESettings::unload_project() {
if (!is_pack_loaded()) {
return ERR_DOES_NOT_EXIST;
}
logger->stop_prebuffering();
error_encryption = false;
reset_uid_cache();
if (get_pack_type() == PackInfo::DIR) {
Expand Down Expand Up @@ -1346,11 +1372,18 @@ String GDRESettings::get_sys_info_string() const {
return OS_Name + " " + OS_Version + ", " + adapter_name;
}

void GDRESettings::log_sysinfo() {
print_line("GDRE Tools " + String(GDRE_VERSION));
print_line(get_sys_info_string());
}

Error GDRESettings::open_log_file(const String &output_dir) {
String logfile = output_dir.path_join("gdre_export.log");
bool was_buffering = logger->is_prebuffering_enabled();
Error err = logger->open_file(logfile);
print_line("GDRE Tools " + String(GDRE_VERSION));
print_line(get_sys_info_string());
if (!was_buffering) {
log_sysinfo();
}
ERR_FAIL_COND_V_MSG(err == ERR_ALREADY_IN_USE, err, "Already logging to another file");
ERR_FAIL_COND_V_MSG(err != OK, err, "Could not open log file " + logfile);
return OK;
Expand Down
2 changes: 2 additions & 0 deletions utility/gdre_settings.h
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,8 @@ class GDRESettings : public Object {

static constexpr bool need_correct_patch(int ver_major, int ver_minor);
void _do_prepop(uint32_t i, const String *plugins);
String sanitize_home_in_path(const String &p_path);
void log_sysinfo();

protected:
static void _bind_methods();
Expand Down

0 comments on commit 00903c7

Please sign in to comment.