From 1a2311e3505765e37b736fe6bb46bb229e00701f Mon Sep 17 00:00:00 2001 From: Ruslan Mustakov Date: Fri, 22 Sep 2017 12:56:02 +0700 Subject: [PATCH] Extract logging logic Previously logging logic was scattered over OS class implementations with plenty of duplication. Major changes in this commit: - Extracted logging logic into a separate Logger hierarchy. It allows easy configuration of logging mechanism depending on compile-time or run-time configuration. - Implemented RotatedFileLogger which is usually used with StdLogger, providing persistency of logs. It is often important to be able to obtain logs of the game even in production to be able to understand what happened prior to some problem. On mobile there previously was no way to obtain the logs aside from having the device connected to your machine. - flush() is not performed in release mode for every logged line. It is only performed for errors. --- core/error_macros.cpp | 3 +- core/io/file_access_buffered_fa.h | 5 + core/io/file_access_compressed.cpp | 7 + core/io/file_access_compressed.h | 1 + core/io/file_access_encrypted.cpp | 6 + core/io/file_access_encrypted.h | 1 + core/io/file_access_memory.cpp | 4 + core/io/file_access_memory.h | 1 + core/io/file_access_network.cpp | 4 + core/io/file_access_network.h | 1 + core/io/file_access_pack.cpp | 5 + core/io/file_access_pack.h | 1 + core/io/file_access_zip.cpp | 5 + core/io/file_access_zip.h | 1 + core/io/logger.cpp | 252 +++++++++++++++++++ core/io/logger.h | 107 ++++++++ core/os/file_access.cpp | 2 +- core/os/file_access.h | 1 + core/os/os.cpp | 34 +-- core/os/os.h | 21 +- drivers/unix/file_access_unix.cpp | 6 + drivers/unix/file_access_unix.h | 1 + drivers/unix/os_unix.cpp | 95 ++++--- drivers/unix/os_unix.h | 12 +- drivers/unix/syslog_logger.cpp | 71 ++++++ drivers/unix/syslog_logger.h | 48 ++++ drivers/windows/dir_access_windows.cpp | 2 +- drivers/windows/file_access_windows.cpp | 6 + drivers/windows/file_access_windows.h | 1 + main/main.cpp | 3 +- platform/android/file_access_android.cpp | 5 + platform/android/file_access_android.h | 1 + platform/android/file_access_jandroid.cpp | 3 + platform/android/file_access_jandroid.h | 1 + platform/android/os_android.cpp | 32 +-- platform/android/os_android.h | 3 +- platform/iphone/os_iphone.cpp | 10 + platform/iphone/os_iphone.h | 1 + platform/javascript/os_javascript.cpp | 4 + platform/javascript/os_javascript.h | 6 +- platform/osx/os_osx.h | 3 +- platform/osx/os_osx.mm | 88 ++++--- platform/uwp/os_uwp.cpp | 60 +---- platform/uwp/os_uwp.h | 4 +- platform/windows/SCsub | 1 + platform/windows/os_windows.cpp | 143 +---------- platform/windows/os_windows.h | 4 +- platform/windows/windows_terminal_logger.cpp | 157 ++++++++++++ platform/windows/windows_terminal_logger.h | 47 ++++ 49 files changed, 948 insertions(+), 332 deletions(-) create mode 100644 core/io/logger.cpp create mode 100644 core/io/logger.h create mode 100644 drivers/unix/syslog_logger.cpp create mode 100644 drivers/unix/syslog_logger.h create mode 100644 platform/windows/windows_terminal_logger.cpp create mode 100644 platform/windows/windows_terminal_logger.h diff --git a/core/error_macros.cpp b/core/error_macros.cpp index 5919d38375d..170a22e8dd9 100644 --- a/core/error_macros.cpp +++ b/core/error_macros.cpp @@ -29,6 +29,7 @@ /*************************************************************************/ #include "error_macros.h" +#include "io/logger.h" #include "os/os.h" bool _err_error_exists = false; @@ -79,7 +80,7 @@ void remove_error_handler(ErrorHandlerList *p_handler) { void _err_print_error(const char *p_function, const char *p_file, int p_line, const char *p_error, ErrorHandlerType p_type) { - OS::get_singleton()->print_error(p_function, p_file, p_line, p_error, _err_error_exists ? OS::get_singleton()->get_last_error() : "", (OS::ErrorType)p_type); + OS::get_singleton()->print_error(p_function, p_file, p_line, p_error, _err_error_exists ? OS::get_singleton()->get_last_error() : "", (Logger::ErrorType)p_type); _global_lock(); ErrorHandlerList *l = error_handler_list; diff --git a/core/io/file_access_buffered_fa.h b/core/io/file_access_buffered_fa.h index 9e41834561b..309fc16d09e 100644 --- a/core/io/file_access_buffered_fa.h +++ b/core/io/file_access_buffered_fa.h @@ -76,6 +76,11 @@ protected: }; public: + void flush() { + + f.flush(); + }; + void store_8(uint8_t p_dest) { f.store_8(p_dest); diff --git a/core/io/file_access_compressed.cpp b/core/io/file_access_compressed.cpp index 47509458543..514e3c65f01 100644 --- a/core/io/file_access_compressed.cpp +++ b/core/io/file_access_compressed.cpp @@ -338,6 +338,13 @@ Error FileAccessCompressed::get_error() const { return read_eof ? ERR_FILE_EOF : OK; } +void FileAccessCompressed::flush() { + ERR_FAIL_COND(!f); + ERR_FAIL_COND(!writing); + + // compressed files keep data in memory till close() +} + void FileAccessCompressed::store_8(uint8_t p_dest) { ERR_FAIL_COND(!f); diff --git a/core/io/file_access_compressed.h b/core/io/file_access_compressed.h index 1a57e2d4ee7..1d99e5bfd44 100644 --- a/core/io/file_access_compressed.h +++ b/core/io/file_access_compressed.h @@ -84,6 +84,7 @@ public: virtual Error get_error() const; ///< get last error + virtual void flush(); virtual void store_8(uint8_t p_dest); ///< store a byte virtual bool file_exists(const String &p_name); ///< return true if a file exists diff --git a/core/io/file_access_encrypted.cpp b/core/io/file_access_encrypted.cpp index 461c5bafe2a..c93e12f7dac 100644 --- a/core/io/file_access_encrypted.cpp +++ b/core/io/file_access_encrypted.cpp @@ -268,6 +268,12 @@ void FileAccessEncrypted::store_buffer(const uint8_t *p_src, int p_length) { } } +void FileAccessEncrypted::flush() { + ERR_FAIL_COND(!writing); + + // encrypted files keep data in memory till close() +} + void FileAccessEncrypted::store_8(uint8_t p_dest) { ERR_FAIL_COND(!writing); diff --git a/core/io/file_access_encrypted.h b/core/io/file_access_encrypted.h index 82f60ac654b..d83fed3e0ed 100644 --- a/core/io/file_access_encrypted.h +++ b/core/io/file_access_encrypted.h @@ -71,6 +71,7 @@ public: virtual Error get_error() const; ///< get last error + virtual void flush(); virtual void store_8(uint8_t p_dest); ///< store a byte virtual void store_buffer(const uint8_t *p_src, int p_length); ///< store an array of bytes diff --git a/core/io/file_access_memory.cpp b/core/io/file_access_memory.cpp index b948394385b..0a5815fca81 100644 --- a/core/io/file_access_memory.cpp +++ b/core/io/file_access_memory.cpp @@ -170,6 +170,10 @@ Error FileAccessMemory::get_error() const { return pos >= length ? ERR_FILE_EOF : OK; } +void FileAccessMemory::flush() { + ERR_FAIL_COND(!data); +} + void FileAccessMemory::store_8(uint8_t p_byte) { ERR_FAIL_COND(!data); diff --git a/core/io/file_access_memory.h b/core/io/file_access_memory.h index b7b8430089b..23392719b47 100644 --- a/core/io/file_access_memory.h +++ b/core/io/file_access_memory.h @@ -62,6 +62,7 @@ public: virtual Error get_error() const; ///< get last error + virtual void flush(); virtual void store_8(uint8_t p_byte); ///< store a byte virtual void store_buffer(const uint8_t *p_src, int p_length); ///< store an array of bytes diff --git a/core/io/file_access_network.cpp b/core/io/file_access_network.cpp index 8c624226a13..a224abd9e7d 100644 --- a/core/io/file_access_network.cpp +++ b/core/io/file_access_network.cpp @@ -456,6 +456,10 @@ Error FileAccessNetwork::get_error() const { return pos == total_size ? ERR_FILE_EOF : OK; } +void FileAccessNetwork::flush() { + ERR_FAIL(); +} + void FileAccessNetwork::store_8(uint8_t p_dest) { ERR_FAIL(); diff --git a/core/io/file_access_network.h b/core/io/file_access_network.h index abbe378b60a..20614476d0c 100644 --- a/core/io/file_access_network.h +++ b/core/io/file_access_network.h @@ -155,6 +155,7 @@ public: virtual Error get_error() const; ///< get last error + virtual void flush(); virtual void store_8(uint8_t p_dest); ///< store a byte virtual bool file_exists(const String &p_path); ///< return true if a file exists diff --git a/core/io/file_access_pack.cpp b/core/io/file_access_pack.cpp index ff4c28ec39f..a7eb8ce6a92 100644 --- a/core/io/file_access_pack.cpp +++ b/core/io/file_access_pack.cpp @@ -293,6 +293,11 @@ Error FileAccessPack::get_error() const { return OK; } +void FileAccessPack::flush() { + + ERR_FAIL(); +} + void FileAccessPack::store_8(uint8_t p_dest) { ERR_FAIL(); diff --git a/core/io/file_access_pack.h b/core/io/file_access_pack.h index 3deb0d2bd38..12187a353a7 100644 --- a/core/io/file_access_pack.h +++ b/core/io/file_access_pack.h @@ -161,6 +161,7 @@ public: virtual Error get_error() const; + virtual void flush(); virtual void store_8(uint8_t p_dest); virtual void store_buffer(const uint8_t *p_src, int p_length); diff --git a/core/io/file_access_zip.cpp b/core/io/file_access_zip.cpp index 73b23ac7021..ec809011a90 100644 --- a/core/io/file_access_zip.cpp +++ b/core/io/file_access_zip.cpp @@ -353,6 +353,11 @@ Error FileAccessZip::get_error() const { return OK; }; +void FileAccessZip::flush() { + + ERR_FAIL(); +} + void FileAccessZip::store_8(uint8_t p_dest) { ERR_FAIL(); diff --git a/core/io/file_access_zip.h b/core/io/file_access_zip.h index a40e1a753df..0977b241eed 100644 --- a/core/io/file_access_zip.h +++ b/core/io/file_access_zip.h @@ -108,6 +108,7 @@ public: virtual Error get_error() const; ///< get last error + virtual void flush(); virtual void store_8(uint8_t p_dest); ///< store a byte virtual bool file_exists(const String &p_name); ///< return true if a file exists diff --git a/core/io/logger.cpp b/core/io/logger.cpp new file mode 100644 index 00000000000..7ea5f06d7e2 --- /dev/null +++ b/core/io/logger.cpp @@ -0,0 +1,252 @@ +/*************************************************************************/ +/* logger.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#include "logger.h" +#include "os/dir_access.h" +#include "os/os.h" +#include "print_string.h" + +bool Logger::should_log(bool p_err) { + return (!p_err || _print_error_enabled) && (p_err || _print_line_enabled); +} + +void Logger::log_error(const char *p_function, const char *p_file, int p_line, const char *p_code, const char *p_rationale, ErrorType p_type) { + if (!should_log(true)) { + return; + } + + const char *err_type = "**ERROR**"; + switch (p_type) { + case ERR_ERROR: err_type = "**ERROR**"; break; + case ERR_WARNING: err_type = "**WARNING**"; break; + case ERR_SCRIPT: err_type = "**SCRIPT ERROR**"; break; + case ERR_SHADER: err_type = "**SHADER ERROR**"; break; + default: ERR_PRINT("Unknown error type"); break; + } + + const char *err_details; + if (p_rationale && *p_rationale) + err_details = p_rationale; + else + err_details = p_code; + + logf_error("%s: %s\n", err_type, err_details); + logf_error(" At: %s:%i:%s() - %s\n", p_file, p_line, p_function, p_code); +} + +void Logger::logf(const char *p_format, ...) { + if (!should_log(false)) { + return; + } + + va_list argp; + va_start(argp, p_format); + + logv(p_format, argp, false); + + va_end(argp); +} + +void Logger::logf_error(const char *p_format, ...) { + if (!should_log(true)) { + return; + } + + va_list argp; + va_start(argp, p_format); + + logv(p_format, argp, true); + + va_end(argp); +} + +Logger::~Logger() {} + +void RotatedFileLogger::close_file() { + if (file) { + memdelete(file); + file = NULL; + } +} + +void RotatedFileLogger::clear_old_backups() { + int max_backups = max_files - 1; // -1 for the current file + + String basename = base_path.get_basename(); + String extension = "." + base_path.get_extension(); + + DirAccess *da = DirAccess::open(base_path.get_base_dir()); + if (!da) { + return; + } + + da->list_dir_begin(); + String f = da->get_next(); + Set backups; + while (f != String()) { + if (!da->current_is_dir() && f.begins_with(basename) && f.ends_with(extension) && f != base_path) { + backups.insert(f); + } + f = da->get_next(); + } + da->list_dir_end(); + + if (backups.size() > max_backups) { + // since backups are appended with timestamp and Set iterates them in sorted order, + // first backups are the oldest + int to_delete = backups.size() - max_backups; + for (Set::Element *E = backups.front(); E && to_delete > 0; E = E->next(), --to_delete) { + da->remove(E->get()); + } + } + + memdelete(da); +} + +void RotatedFileLogger::rotate_file() { + close_file(); + + if (FileAccess::exists(base_path)) { + if (max_files > 1) { + char timestamp[21]; + OS::Date date = OS::get_singleton()->get_date(); + OS::Time time = OS::get_singleton()->get_time(); + sprintf(timestamp, "-%04d-%02d-%02d-%02d-%02d-%02d", date.year, date.month, date.day + 1, time.hour, time.min, time.sec); + + String backup_name = base_path.get_basename() + timestamp + "." + base_path.get_extension(); + + DirAccess *da = DirAccess::open(base_path.get_base_dir()); + if (da) { + da->copy(base_path, backup_name); + memdelete(da); + } + clear_old_backups(); + } + } else { + DirAccess *da = DirAccess::create(DirAccess::ACCESS_USERDATA); + if (da) { + da->make_dir_recursive(base_path.get_base_dir()); + memdelete(da); + } + } + + file = FileAccess::open(base_path, FileAccess::WRITE); +} + +RotatedFileLogger::RotatedFileLogger(const String &p_base_path, int p_max_files) { + file = NULL; + base_path = p_base_path.simplify_path(); + max_files = p_max_files > 0 ? p_max_files : 1; + + rotate_file(); +} + +void RotatedFileLogger::logv(const char *p_format, va_list p_list, bool p_err) { + if (!should_log(p_err)) { + return; + } + + if (file) { + const int static_buf_size = 512; + char static_buf[static_buf_size]; + char *buf = static_buf; + int len = vsnprintf(buf, static_buf_size, p_format, p_list); + if (len >= static_buf_size) { + buf = (char *)Memory::alloc_static(len + 1); + vsnprintf(buf, len + 1, p_format, p_list); + } + file->store_buffer((uint8_t *)buf, len); + if (len >= static_buf_size) { + Memory::free_static(buf); + } +#ifdef DEBUG_ENABLED + const bool need_flush = true; +#else + bool need_flush = p_err; +#endif + if (need_flush) { + file->flush(); + } + } +} + +RotatedFileLogger::~RotatedFileLogger() { + close_file(); +} + +void StdLogger::logv(const char *p_format, va_list p_list, bool p_err) { + if (!should_log(p_err)) { + return; + } + + if (p_err) { + vfprintf(stderr, p_format, p_list); + } else { + vprintf(p_format, p_list); +#ifdef DEBUG_ENABLED + fflush(stdout); +#endif + } +} + +StdLogger::~StdLogger() {} + +CompositeLogger::CompositeLogger(Vector p_loggers) { + loggers = p_loggers; +} + +void CompositeLogger::logv(const char *p_format, va_list p_list, bool p_err) { + if (!should_log(p_err)) { + return; + } + + for (int i = 0; i < loggers.size(); ++i) { + va_list list_copy; + va_copy(list_copy, p_list); + loggers[i]->logv(p_format, list_copy, p_err); + va_end(list_copy); + } +} + +void CompositeLogger::log_error(const char *p_function, const char *p_file, int p_line, const char *p_code, const char *p_rationale, ErrorType p_type) { + if (!should_log(true)) { + return; + } + + for (int i = 0; i < loggers.size(); ++i) { + loggers[i]->log_error(p_function, p_file, p_line, p_code, p_rationale, p_type); + } +} + +CompositeLogger::~CompositeLogger() { + for (int i = 0; i < loggers.size(); ++i) { + memdelete(loggers[i]); + } +} diff --git a/core/io/logger.h b/core/io/logger.h new file mode 100644 index 00000000000..cf0cc7699f5 --- /dev/null +++ b/core/io/logger.h @@ -0,0 +1,107 @@ +/*************************************************************************/ +/* logger.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#ifndef LOGGER_H +#define LOGGER_H + +#include "os/file_access.h" +#include "ustring.h" +#include "vector.h" +#include + +class Logger { +protected: + bool should_log(bool p_err); + +public: + enum ErrorType { + ERR_ERROR, + ERR_WARNING, + ERR_SCRIPT, + ERR_SHADER + }; + + virtual void logv(const char *p_format, va_list p_list, bool p_err) = 0; + virtual void log_error(const char *p_function, const char *p_file, int p_line, const char *p_code, const char *p_rationale, ErrorType p_type = ERR_ERROR); + + void logf(const char *p_format, ...); + void logf_error(const char *p_format, ...); + + virtual ~Logger(); +}; + +/** + * Writes messages to stdout/stderr. + */ +class StdLogger : public Logger { + +public: + virtual void logv(const char *p_format, va_list p_list, bool p_err); + virtual ~StdLogger(); +}; + +/** + * Writes messages to the specified file. If the file already exists, creates a copy (backup) + * of it with timestamp appended to the file name. Maximum number of backups is configurable. + * When maximum is reached, the oldest backups are erased. With the maximum being equal to 1, + * it acts as a simple file logger. + */ +class RotatedFileLogger : public Logger { + String base_path; + int max_files; + + FileAccess *file; + + void rotate_file_without_closing(); + void close_file(); + void clear_old_backups(); + void rotate_file(); + +public: + RotatedFileLogger(const String &p_base_path, int p_max_files = 10); + + virtual void logv(const char *p_format, va_list p_list, bool p_err); + + virtual ~RotatedFileLogger(); +}; + +class CompositeLogger : public Logger { + Vector loggers; + +public: + CompositeLogger(Vector p_loggers); + + virtual void logv(const char *p_format, va_list p_list, bool p_err); + virtual void log_error(const char *p_function, const char *p_file, int p_line, const char *p_code, const char *p_rationale, ErrorType p_type = ERR_ERROR); + + virtual ~CompositeLogger(); +}; + +#endif \ No newline at end of file diff --git a/core/os/file_access.cpp b/core/os/file_access.cpp index b969b58bfb6..fcb3b58feda 100644 --- a/core/os/file_access.cpp +++ b/core/os/file_access.cpp @@ -55,7 +55,7 @@ FileAccess *FileAccess::create(AccessType p_access) { bool FileAccess::exists(const String &p_name) { - if (PackedData::get_singleton()->has_path(p_name)) + if (PackedData::get_singleton() && PackedData::get_singleton()->has_path(p_name)) return true; FileAccess *f = open(p_name, READ); diff --git a/core/os/file_access.h b/core/os/file_access.h index 34e7549fa3b..455dd1ea99c 100644 --- a/core/os/file_access.h +++ b/core/os/file_access.h @@ -119,6 +119,7 @@ public: virtual Error get_error() const = 0; ///< get last error + virtual void flush() = 0; virtual void store_8(uint8_t p_dest) = 0; ///< store a byte virtual void store_16(uint16_t p_dest); ///< store 16 bits uint virtual void store_32(uint32_t p_dest); ///< store 32 bits uint diff --git a/core/os/os.cpp b/core/os/os.cpp index 437ce01a5ec..ff17cdb508d 100644 --- a/core/os/os.cpp +++ b/core/os/os.cpp @@ -62,20 +62,20 @@ void OS::debug_break(){ // something }; -void OS::print_error(const char *p_function, const char *p_file, int p_line, const char *p_code, const char *p_rationale, ErrorType p_type) { - - const char *err_type = "**ERROR**"; - switch (p_type) { - case ERR_ERROR: err_type = "**ERROR**"; break; - case ERR_WARNING: err_type = "**WARNING**"; break; - case ERR_SCRIPT: err_type = "**SCRIPT ERROR**"; break; - case ERR_SHADER: err_type = "**SHADER ERROR**"; break; - default: ERR_PRINT("Unknown error type"); break; +void OS::_set_logger(Logger *p_logger) { + if (_logger) { + memdelete(_logger); } + _logger = p_logger; +} - if (p_rationale && *p_rationale) - print("%s: %s\n ", err_type, p_rationale); - print("%s: At: %s:%i:%s() - %s\n", err_type, p_file, p_line, p_function, p_code); +void OS::initialize_logger() { + _set_logger(memnew(StdLogger)); +} + +void OS::print_error(const char *p_function, const char *p_file, int p_line, const char *p_code, const char *p_rationale, Logger::ErrorType p_type) { + + _logger->log_error(p_function, p_file, p_line, p_code, p_rationale, p_type); } void OS::print(const char *p_format, ...) { @@ -83,17 +83,16 @@ void OS::print(const char *p_format, ...) { va_list argp; va_start(argp, p_format); - vprint(p_format, argp); + _logger->logv(p_format, argp, false); va_end(argp); }; void OS::printerr(const char *p_format, ...) { - va_list argp; va_start(argp, p_format); - vprint(p_format, argp, true); + _logger->logv(p_format, argp, true); va_end(argp); }; @@ -533,9 +532,12 @@ OS::OS() { _allow_hidpi = true; _stack_bottom = (void *)(&stack_bottom); + + _logger = NULL; + _set_logger(memnew(StdLogger)); } OS::~OS() { - + memdelete(_logger); singleton = NULL; } diff --git a/core/os/os.h b/core/os/os.h index 38bbbc0a575..0b622905401 100644 --- a/core/os/os.h +++ b/core/os/os.h @@ -32,6 +32,7 @@ #include "engine.h" #include "image.h" +#include "io/logger.h" #include "list.h" #include "os/main_loop.h" #include "ustring.h" @@ -61,6 +62,11 @@ class OS { void *_stack_bottom; + Logger *_logger; + +protected: + void _set_logger(Logger *p_logger); + public: typedef void (*ImeCallback)(void *p_inp, String p_text, Point2 p_selection); @@ -108,6 +114,7 @@ protected: virtual int get_audio_driver_count() const = 0; virtual const char *get_audio_driver_name(int p_driver) const = 0; + virtual void initialize_logger(); virtual void initialize_core() = 0; virtual void initialize(const VideoMode &p_desired, int p_video_driver, int p_audio_driver) = 0; @@ -127,18 +134,10 @@ public: static OS *get_singleton(); - enum ErrorType { - ERR_ERROR, - ERR_WARNING, - ERR_SCRIPT, - ERR_SHADER - }; + void print_error(const char *p_function, const char *p_file, int p_line, const char *p_code, const char *p_rationale, Logger::ErrorType p_type = Logger::ERR_ERROR); + void print(const char *p_format, ...); + void printerr(const char *p_format, ...); - virtual void print_error(const char *p_function, const char *p_file, int p_line, const char *p_code, const char *p_rationale, ErrorType p_type = ERR_ERROR); - - virtual void print(const char *p_format, ...); - virtual void printerr(const char *p_format, ...); - virtual void vprint(const char *p_format, va_list p_list, bool p_stderr = false) = 0; virtual void alert(const String &p_alert, const String &p_title = "ALERT!") = 0; virtual String get_stdin_string(bool p_block = true) = 0; diff --git a/drivers/unix/file_access_unix.cpp b/drivers/unix/file_access_unix.cpp index 649f874cf4f..206f57d4a22 100644 --- a/drivers/unix/file_access_unix.cpp +++ b/drivers/unix/file_access_unix.cpp @@ -223,6 +223,12 @@ Error FileAccessUnix::get_error() const { return last_error; } +void FileAccessUnix::flush() { + + ERR_FAIL_COND(!f); + fflush(f); +} + void FileAccessUnix::store_8(uint8_t p_dest) { ERR_FAIL_COND(!f); diff --git a/drivers/unix/file_access_unix.h b/drivers/unix/file_access_unix.h index e2848e41282..96f2ff8e26f 100644 --- a/drivers/unix/file_access_unix.h +++ b/drivers/unix/file_access_unix.h @@ -72,6 +72,7 @@ public: virtual Error get_error() const; ///< get last error + virtual void flush(); virtual void store_8(uint8_t p_dest); ///< store a byte virtual bool file_exists(const String &p_path); ///< return true if a file exists diff --git a/drivers/unix/os_unix.cpp b/drivers/unix/os_unix.cpp index 75c8a153f6e..29fe73f1705 100644 --- a/drivers/unix/os_unix.cpp +++ b/drivers/unix/os_unix.cpp @@ -64,39 +64,7 @@ #include #include #include - -extern bool _print_error_enabled; - -void OS_Unix::print_error(const char *p_function, const char *p_file, int p_line, const char *p_code, const char *p_rationale, ErrorType p_type) { - - if (!_print_error_enabled) - return; - - const char *err_details; - if (p_rationale && p_rationale[0]) - err_details = p_rationale; - else - err_details = p_code; - - switch (p_type) { - case ERR_ERROR: - print("\E[1;31mERROR: %s: \E[0m\E[1m%s\n", p_function, err_details); - print("\E[0;31m At: %s:%i.\E[0m\n", p_file, p_line); - break; - case ERR_WARNING: - print("\E[1;33mWARNING: %s: \E[0m\E[1m%s\n", p_function, err_details); - print("\E[0;33m At: %s:%i.\E[0m\n", p_file, p_line); - break; - case ERR_SCRIPT: - print("\E[1;35mSCRIPT ERROR: %s: \E[0m\E[1m%s\n", p_function, err_details); - print("\E[0;35m At: %s:%i.\E[0m\n", p_file, p_line); - break; - case ERR_SHADER: - print("\E[1;36mSHADER ERROR: %s: \E[0m\E[1m%s\n", p_function, err_details); - print("\E[0;36m At: %s:%i.\E[0m\n", p_file, p_line); - break; - } -} +#include void OS_Unix::debug_break() { @@ -165,29 +133,16 @@ void OS_Unix::initialize_core() { } } +void OS_Unix::initialize_logger() { + Vector loggers; + loggers.push_back(memnew(UnixTerminalLogger)); + loggers.push_back(memnew(RotatedFileLogger("user://logs/log.txt"))); + _set_logger(memnew(CompositeLogger(loggers))); +} + void OS_Unix::finalize_core() { } -void OS_Unix::vprint(const char *p_format, va_list p_list, bool p_stder) { - - if (p_stder) { - - vfprintf(stderr, p_format, p_list); - fflush(stderr); - } else { - - vprintf(p_format, p_list); - fflush(stdout); - } -} - -void OS_Unix::print(const char *p_format, ...) { - - va_list argp; - va_start(argp, p_format); - vprintf(p_format, argp); - va_end(argp); -} void OS_Unix::alert(const String &p_alert, const String &p_title) { fprintf(stderr, "ERROR: %s\n", p_alert.utf8().get_data()); @@ -559,4 +514,38 @@ String OS_Unix::get_executable_path() const { #endif } +void UnixTerminalLogger::log_error(const char *p_function, const char *p_file, int p_line, const char *p_code, const char *p_rationale, ErrorType p_type) { + if (!should_log(true)) { + return; + } + + const char *err_details; + if (p_rationale && p_rationale[0]) + err_details = p_rationale; + else + err_details = p_code; + + switch (p_type) { + case ERR_WARNING: + logf_error("\E[1;33mWARNING: %s: \E[0m\E[1m%s\n", p_function, err_details); + logf_error("\E[0;33m At: %s:%i.\E[0m\n", p_file, p_line); + break; + case ERR_SCRIPT: + logf_error("\E[1;35mSCRIPT ERROR: %s: \E[0m\E[1m%s\n", p_function, err_details); + logf_error("\E[0;35m At: %s:%i.\E[0m\n", p_file, p_line); + break; + case ERR_SHADER: + logf_error("\E[1;36mSHADER ERROR: %s: \E[0m\E[1m%s\n", p_function, err_details); + logf_error("\E[0;36m At: %s:%i.\E[0m\n", p_file, p_line); + break; + case ERR_ERROR: + default: + logf_error("\E[1;31mERROR: %s: \E[0m\E[1m%s\n", p_function, err_details); + logf_error("\E[0;31m At: %s:%i.\E[0m\n", p_file, p_line); + break; + } +} + +UnixTerminalLogger::~UnixTerminalLogger() {} + #endif diff --git a/drivers/unix/os_unix.h b/drivers/unix/os_unix.h index 19e79728fb3..1cc44c0ffd1 100644 --- a/drivers/unix/os_unix.h +++ b/drivers/unix/os_unix.h @@ -54,11 +54,11 @@ protected: virtual int get_audio_driver_count() const; virtual const char *get_audio_driver_name(int p_driver) const; + virtual void initialize_logger(); virtual void initialize_core(); virtual int unix_initialize_audio(int p_audio_driver); //virtual void initialize(int p_video_driver,int p_audio_driver); - //virtual void finalize(); virtual void finalize_core(); String stdin_buf; @@ -66,10 +66,6 @@ protected: String get_global_settings_path() const; public: - virtual void print_error(const char *p_function, const char *p_file, int p_line, const char *p_code, const char *p_rationale, ErrorType p_type = ERR_ERROR); - - virtual void print(const char *p_format, ...); - virtual void vprint(const char *p_format, va_list p_list, bool p_stder = false); virtual void alert(const String &p_alert, const String &p_title = "ALERT!"); virtual String get_stdin_string(bool p_block); @@ -120,6 +116,12 @@ public: //virtual void run( MainLoop * p_main_loop ); }; +class UnixTerminalLogger : public StdLogger { +public: + virtual void log_error(const char *p_function, const char *p_file, int p_line, const char *p_code, const char *p_rationale, ErrorType p_type = ERR_ERROR); + virtual ~UnixTerminalLogger(); +}; + #endif #endif diff --git a/drivers/unix/syslog_logger.cpp b/drivers/unix/syslog_logger.cpp new file mode 100644 index 00000000000..d57f391325c --- /dev/null +++ b/drivers/unix/syslog_logger.cpp @@ -0,0 +1,71 @@ +/*************************************************************************/ +/* syslog_logger.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#ifdef UNIX_ENABLED + +#include "syslog_logger.h" +#include "print_string.h" +#include + +void SyslogLogger::logv(const char *p_format, va_list p_list, bool p_err) { + if (!should_log(p_err)) { + return; + } + + vsyslog(p_err ? LOG_ERR : LOG_INFO, p_format, p_list); +} + +void SyslogLogger::print_error(const char *p_function, const char *p_file, int p_line, const char *p_code, const char *p_rationale, ErrorType p_type) { + if (!should_log(true)) { + return; + } + + const char *err_type = "**ERROR**"; + switch (p_type) { + case ERR_ERROR: err_type = "**ERROR**"; break; + case ERR_WARNING: err_type = "**WARNING**"; break; + case ERR_SCRIPT: err_type = "**SCRIPT ERROR**"; break; + case ERR_SHADER: err_type = "**SHADER ERROR**"; break; + default: ERR_PRINT("Unknown error type"); break; + } + + const char *err_details; + if (p_rationale && *p_rationale) + err_details = p_rationale; + else + err_details = p_code; + + syslog(p_type == ERR_WARNING ? LOG_WARNING : LOG_ERR, "%s: %s\n At: %s:%i:%s() - %s", err_type, err_details, p_file, p_line, p_function, p_code); +} + +SyslogLogger::~SyslogLogger() { +} + +#endif \ No newline at end of file diff --git a/drivers/unix/syslog_logger.h b/drivers/unix/syslog_logger.h new file mode 100644 index 00000000000..b3cf2f9e3ab --- /dev/null +++ b/drivers/unix/syslog_logger.h @@ -0,0 +1,48 @@ +/*************************************************************************/ +/* syslog_logger.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#ifndef SYSLOG_LOGGER_H +#define SYSLOG_LOGGER_H + +#ifdef UNIX_ENABLED + +#include "io/logger.h" + +class SyslogLogger : public Logger { +public: + virtual void logv(const char *p_format, va_list p_list, bool p_err); + virtual void print_error(const char *p_function, const char *p_file, int p_line, const char *p_code, const char *p_rationale, ErrorType p_type); + + virtual ~SyslogLogger(); +}; + +#endif + +#endif \ No newline at end of file diff --git a/drivers/windows/dir_access_windows.cpp b/drivers/windows/dir_access_windows.cpp index 6d6a6027d94..8d6e78dbee6 100644 --- a/drivers/windows/dir_access_windows.cpp +++ b/drivers/windows/dir_access_windows.cpp @@ -162,10 +162,10 @@ Error DirAccessWindows::make_dir(String p_dir) { GLOBAL_LOCK_FUNCTION + p_dir = fix_path(p_dir); if (p_dir.is_rel_path()) p_dir = get_current_dir().plus_file(p_dir); - p_dir = fix_path(p_dir); p_dir = p_dir.replace("/", "\\"); bool success; diff --git a/drivers/windows/file_access_windows.cpp b/drivers/windows/file_access_windows.cpp index d128b582446..3b6e469c9c4 100644 --- a/drivers/windows/file_access_windows.cpp +++ b/drivers/windows/file_access_windows.cpp @@ -207,6 +207,12 @@ Error FileAccessWindows::get_error() const { return last_error; } +void FileAccessWindows::flush() { + + ERR_FAIL_COND(!f); + fflush(f); +} + void FileAccessWindows::store_8(uint8_t p_dest) { ERR_FAIL_COND(!f); diff --git a/drivers/windows/file_access_windows.h b/drivers/windows/file_access_windows.h index 15cbdca7394..e5e7fd4a139 100644 --- a/drivers/windows/file_access_windows.h +++ b/drivers/windows/file_access_windows.h @@ -64,6 +64,7 @@ public: virtual Error get_error() const; ///< get last error + virtual void flush(); virtual void store_8(uint8_t p_dest); ///< store a byte virtual bool file_exists(const String &p_name); ///< return true if a file exists diff --git a/main/main.cpp b/main/main.cpp index 9096b935c24..9ae6d3e92c1 100644 --- a/main/main.cpp +++ b/main/main.cpp @@ -231,7 +231,6 @@ void Main::print_help(const char *p_binary) { } Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_phase) { - RID_OwnerBase::init_rid(); OS::get_singleton()->initialize_core(); @@ -254,6 +253,8 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph register_core_settings(); //here globals is present + OS::get_singleton()->initialize_logger(); + translation_server = memnew(TranslationServer); performance = memnew(Performance); globals->add_singleton(ProjectSettings::Singleton("Performance", performance)); diff --git a/platform/android/file_access_android.cpp b/platform/android/file_access_android.cpp index c7b0d9afcd0..0fdf9002d7e 100644 --- a/platform/android/file_access_android.cpp +++ b/platform/android/file_access_android.cpp @@ -146,6 +146,11 @@ Error FileAccessAndroid::get_error() const { return eof ? ERR_FILE_EOF : OK; //not sure what else it may happen } +void FileAccessAndroid::flush() { + + ERR_FAIL(); +} + void FileAccessAndroid::store_8(uint8_t p_dest) { ERR_FAIL(); diff --git a/platform/android/file_access_android.h b/platform/android/file_access_android.h index beccf494dd0..c8fedbe6847 100644 --- a/platform/android/file_access_android.h +++ b/platform/android/file_access_android.h @@ -63,6 +63,7 @@ public: virtual Error get_error() const; ///< get last error + virtual void flush(); virtual void store_8(uint8_t p_dest); ///< store a byte virtual bool file_exists(const String &p_path); ///< return true if a file exists diff --git a/platform/android/file_access_jandroid.cpp b/platform/android/file_access_jandroid.cpp index fe934c89fb8..980afd8f464 100644 --- a/platform/android/file_access_jandroid.cpp +++ b/platform/android/file_access_jandroid.cpp @@ -157,6 +157,9 @@ Error FileAccessJAndroid::get_error() const { return OK; } +void FileAccessJAndroid::flush() { +} + void FileAccessJAndroid::store_8(uint8_t p_dest) { } diff --git a/platform/android/file_access_jandroid.h b/platform/android/file_access_jandroid.h index 75a6a213357..368d2c98fae 100644 --- a/platform/android/file_access_jandroid.h +++ b/platform/android/file_access_jandroid.h @@ -67,6 +67,7 @@ public: virtual Error get_error() const; ///< get last error + virtual void flush(); virtual void store_8(uint8_t p_dest); ///< store a byte virtual bool file_exists(const String &p_path); ///< return true if a file exists diff --git a/platform/android/os_android.cpp b/platform/android/os_android.cpp index dbea2d75319..0eb14f6af3f 100644 --- a/platform/android/os_android.cpp +++ b/platform/android/os_android.cpp @@ -47,6 +47,15 @@ #include "file_access_jandroid.h" #endif +class AndroidLogger : public Logger { +public: + virtual void logv(const char *p_format, va_list p_list, bool p_err) { + __android_log_vprint(p_err ? ANDROID_LOG_ERROR : ANDROID_LOG_INFO, "godot", p_format, p_list); + } + + virtual ~AndroidLogger() {} +}; + int OS_Android::get_video_driver_count() const { return 1; @@ -111,6 +120,13 @@ void OS_Android::initialize_core() { #endif } +void OS_Android::initialize_logger() { + Vector loggers; + loggers.push_back(memnew(AndroidLogger)); + loggers.push_back(memnew(RotatedFileLogger("user://logs/log.txt"))); + _set_logger(memnew(CompositeLogger(loggers))); +} + void OS_Android::set_opengl_extensions(const char *p_gl_extensions) { ERR_FAIL_COND(!p_gl_extensions); @@ -162,23 +178,9 @@ void OS_Android::delete_main_loop() { } void OS_Android::finalize() { - memdelete(input); } -void OS_Android::vprint(const char *p_format, va_list p_list, bool p_stderr) { - - __android_log_vprint(p_stderr ? ANDROID_LOG_ERROR : ANDROID_LOG_INFO, "godot", p_format, p_list); -} - -void OS_Android::print(const char *p_format, ...) { - - va_list argp; - va_start(argp, p_format); - __android_log_vprint(ANDROID_LOG_INFO, "godot", p_format, argp); - va_end(argp); -} - void OS_Android::alert(const String &p_alert, const String &p_title) { //print("ALERT: %s\n", p_alert.utf8().get_data()); @@ -737,6 +739,8 @@ OS_Android::OS_Android(GFXInitFunc p_gfx_init_func, void *p_gfx_init_ud, OpenURI set_keep_screen_on_func = p_set_keep_screen_on_func; alert_func = p_alert_func; use_reload_hooks = false; + + _set_logger(memnew(AndroidLogger)); } OS_Android::~OS_Android() { diff --git a/platform/android/os_android.h b/platform/android/os_android.h index 119c14bff3d..a614bb80677 100644 --- a/platform/android/os_android.h +++ b/platform/android/os_android.h @@ -149,6 +149,7 @@ public: virtual int get_audio_driver_count() const; virtual const char *get_audio_driver_name(int p_driver) const; + virtual void initialize_logger(); virtual void initialize_core(); virtual void initialize(const VideoMode &p_desired, int p_video_driver, int p_audio_driver); @@ -161,8 +162,6 @@ public: static OS *get_singleton(); - virtual void vprint(const char *p_format, va_list p_list, bool p_stderr = false); - virtual void print(const char *p_format, ...); virtual void alert(const String &p_alert, const String &p_title = "ALERT!"); virtual void set_mouse_show(bool p_show); diff --git a/platform/iphone/os_iphone.cpp b/platform/iphone/os_iphone.cpp index 0e3eeed114f..3f570145152 100644 --- a/platform/iphone/os_iphone.cpp +++ b/platform/iphone/os_iphone.cpp @@ -42,6 +42,7 @@ #include "core/os/dir_access.h" #include "core/os/file_access.h" #include "core/project_settings.h" +#include "drivers/unix/syslog_logger.h" #include "sem_iphone.h" @@ -99,6 +100,13 @@ void OSIPhone::initialize_core() { SemaphoreIphone::make_default(); }; +void OSIPhone::initialize_logger() { + Vector loggers; + loggers.push_back(memnew(SyslogLogger)); + loggers.push_back(memnew(RotatedFileLogger("user://logs/log.txt"))); + _set_logger(memnew(CompositeLogger(loggers))); +} + void OSIPhone::initialize(const VideoMode &p_desired, int p_video_driver, int p_audio_driver) { supported_orientations = 0; @@ -570,6 +578,8 @@ OSIPhone::OSIPhone(int width, int height) { vm.resizable = false; set_video_mode(vm); event_count = 0; + + _set_logger(memnew(SyslogLogger)); }; OSIPhone::~OSIPhone() { diff --git a/platform/iphone/os_iphone.h b/platform/iphone/os_iphone.h index 475dceebf2e..7a95b50d059 100644 --- a/platform/iphone/os_iphone.h +++ b/platform/iphone/os_iphone.h @@ -91,6 +91,7 @@ private: virtual VideoMode get_default_video_mode() const; + virtual void initialize_logger(); virtual void initialize_core(); virtual void initialize(const VideoMode &p_desired, int p_video_driver, int p_audio_driver); diff --git a/platform/javascript/os_javascript.cpp b/platform/javascript/os_javascript.cpp index f103035b276..82a84096159 100644 --- a/platform/javascript/os_javascript.cpp +++ b/platform/javascript/os_javascript.cpp @@ -85,6 +85,10 @@ void OS_JavaScript::initialize_core() { FileAccess::make_default >(FileAccess::ACCESS_RESOURCES); } +void OS_JavaScript::initialize_logger() { + _set_logger(memnew(StdLogger)); +} + void OS_JavaScript::set_opengl_extensions(const char *p_gl_extensions) { ERR_FAIL_COND(!p_gl_extensions); diff --git a/platform/javascript/os_javascript.h b/platform/javascript/os_javascript.h index 4c6469cb589..1c7bcfef458 100644 --- a/platform/javascript/os_javascript.h +++ b/platform/javascript/os_javascript.h @@ -92,6 +92,7 @@ public: virtual int get_audio_driver_count() const; virtual const char *get_audio_driver_name(int p_driver) const; + virtual void initialize_logger(); virtual void initialize_core(); virtual void initialize(const VideoMode &p_desired, int p_video_driver, int p_audio_driver); @@ -104,11 +105,6 @@ public: //static OS* get_singleton(); - virtual void print_error(const char *p_function, const char *p_file, int p_line, const char *p_code, const char *p_rationale, ErrorType p_type) { - - OS::print_error(p_function, p_file, p_line, p_code, p_rationale, p_type); - } - virtual void alert(const String &p_alert, const String &p_title = "ALERT!"); virtual void set_mouse_mode(MouseMode p_mode); diff --git a/platform/osx/os_osx.h b/platform/osx/os_osx.h index 6c81da04f58..ed67107e9ea 100644 --- a/platform/osx/os_osx.h +++ b/platform/osx/os_osx.h @@ -129,6 +129,7 @@ protected: virtual const char *get_video_driver_name(int p_driver) const; virtual VideoMode get_default_video_mode() const; + virtual void initialize_logger(); virtual void initialize_core(); virtual void initialize(const VideoMode &p_desired, int p_video_driver, int p_audio_driver); virtual void finalize(); @@ -143,8 +144,6 @@ public: virtual String get_name(); - virtual void print_error(const char *p_function, const char *p_file, int p_line, const char *p_code, const char *p_rationale, ErrorType p_type = ERR_ERROR); - virtual void alert(const String &p_alert, const String &p_title = "ALERT!"); virtual void set_cursor_shape(CursorShape p_shape); diff --git a/platform/osx/os_osx.mm b/platform/osx/os_osx.mm index 9a26adc1554..e4f6ca1a340 100644 --- a/platform/osx/os_osx.mm +++ b/platform/osx/os_osx.mm @@ -1145,43 +1145,67 @@ String OS_OSX::get_name() { return "OSX"; } -void OS_OSX::print_error(const char *p_function, const char *p_file, int p_line, const char *p_code, const char *p_rationale, ErrorType p_type) { - #if MAC_OS_X_VERSION_MAX_ALLOWED >= 101200 - if (!_print_error_enabled) - return; +class OSXTerminalLogger : public StdLogger { +public: + virtual void log_error(const char *p_function, const char *p_file, int p_line, const char *p_code, const char *p_rationale, ErrorType p_type = ERR_ERROR) { + if (!should_log(true)) { + return; + } - const char *err_details; - if (p_rationale && p_rationale[0]) - err_details = p_rationale; - else - err_details = p_code; + const char *err_details; + if (p_rationale && p_rationale[0]) + err_details = p_rationale; + else + err_details = p_code; - switch (p_type) { - case ERR_ERROR: - os_log_error(OS_LOG_DEFAULT, "ERROR: %{public}s: %{public}s\nAt: %{public}s:%i.", p_function, err_details, p_file, p_line); - print("\E[1;31mERROR: %s: \E[0m\E[1m%s\n", p_function, err_details); - print("\E[0;31m At: %s:%i.\E[0m\n", p_file, p_line); - break; - case ERR_WARNING: - os_log_info(OS_LOG_DEFAULT, "WARNING: %{public}s: %{public}s\nAt: %{public}s:%i.", p_function, err_details, p_file, p_line); - print("\E[1;33mWARNING: %s: \E[0m\E[1m%s\n", p_function, err_details); - print("\E[0;33m At: %s:%i.\E[0m\n", p_file, p_line); - break; - case ERR_SCRIPT: - os_log_error(OS_LOG_DEFAULT, "SCRIPT ERROR: %{public}s: %{public}s\nAt: %{public}s:%i.", p_function, err_details, p_file, p_line); - print("\E[1;35mSCRIPT ERROR: %s: \E[0m\E[1m%s\n", p_function, err_details); - print("\E[0;35m At: %s:%i.\E[0m\n", p_file, p_line); - break; - case ERR_SHADER: - os_log_error(OS_LOG_DEFAULT, "SHADER ERROR: %{public}s: %{public}s\nAt: %{public}s:%i.", p_function, err_details, p_file, p_line); - print("\E[1;36mSHADER ERROR: %s: \E[0m\E[1m%s\n", p_function, err_details); - print("\E[0;36m At: %s:%i.\E[0m\n", p_file, p_line); - break; + switch (p_type) { + case ERR_WARNING: + os_log_info(OS_LOG_DEFAULT, + "WARNING: %{public}s: %{public}s\nAt: %{public}s:%i.", + p_function, err_details, p_file, p_line); + logf_error("\E[1;33mWARNING: %s: \E[0m\E[1m%s\n", p_function, + err_details); + logf_error("\E[0;33m At: %s:%i.\E[0m\n", p_file, p_line); + break; + case ERR_SCRIPT: + os_log_error(OS_LOG_DEFAULT, + "SCRIPT ERROR: %{public}s: %{public}s\nAt: %{public}s:%i.", + p_function, err_details, p_file, p_line); + logf_error("\E[1;35mSCRIPT ERROR: %s: \E[0m\E[1m%s\n", p_function, + err_details); + logf_error("\E[0;35m At: %s:%i.\E[0m\n", p_file, p_line); + break; + case ERR_SHADER: + os_log_error(OS_LOG_DEFAULT, + "SHADER ERROR: %{public}s: %{public}s\nAt: %{public}s:%i.", + p_function, err_details, p_file, p_line); + logf_error("\E[1;36mSHADER ERROR: %s: \E[0m\E[1m%s\n", p_function, + err_details); + logf_error("\E[0;36m At: %s:%i.\E[0m\n", p_file, p_line); + break; + case ERR_ERROR: + default: + os_log_error(OS_LOG_DEFAULT, + "ERROR: %{public}s: %{public}s\nAt: %{public}s:%i.", + p_function, err_details, p_file, p_line); + logf_error("\E[1;31mERROR: %s: \E[0m\E[1m%s\n", p_function, err_details); + logf_error("\E[0;31m At: %s:%i.\E[0m\n", p_file, p_line); + break; + } } +}; + #else - OS_Unix::print_error(p_function, p_file, p_line, p_code, p_rationale, p_type); + +typedef UnixTerminalLogger OSXTerminalLogger; #endif + +void OS_OSX::initialize_logger() { + Vector loggers; + loggers.push_back(memnew(OSXTerminalLogger)); + loggers.push_back(memnew(RotatedFileLogger("user://logs/log.txt"))); + _set_logger(memnew(CompositeLogger(loggers))); } void OS_OSX::alert(const String &p_alert, const String &p_title) { @@ -2003,6 +2027,8 @@ OS_OSX::OS_OSX() { window_size = Vector2(1024, 600); zoomed = false; display_scale = 1.0; + + _set_logger(memnew(OSXTerminalLogger)); } bool OS_OSX::_check_internal_feature_support(const String &p_feature) { diff --git a/platform/uwp/os_uwp.cpp b/platform/uwp/os_uwp.cpp index b909ccccd65..031c7145148 100644 --- a/platform/uwp/os_uwp.cpp +++ b/platform/uwp/os_uwp.cpp @@ -40,6 +40,7 @@ #include "platform/windows/packet_peer_udp_winsock.h" #include "platform/windows/stream_peer_winsock.h" #include "platform/windows/tcp_server_winsock.h" +#include "platform/windows/windows_terminal_logger.h" #include "project_settings.h" #include "servers/audio_server.h" #include "servers/visual/visual_server_raster.h" @@ -182,6 +183,13 @@ void OSUWP::initialize_core() { cursor_shape = CURSOR_ARROW; } +void OSUWP::initialize_logger() { + Vector loggers; + loggers.push_back(memnew(WindowsTerminalLogger)); + loggers.push_back(memnew(RotatedFileLogger("user://logs/log.txt"))); + _set_logger(memnew(CompositeLogger(loggers))); +} + bool OSUWP::can_draw() const { return !minimized; @@ -371,32 +379,6 @@ void OSUWP::finalize() { void OSUWP::finalize_core() { } -void OSUWP::vprint(const char *p_format, va_list p_list, bool p_stderr) { - - char buf[16384 + 1]; - int len = vsnprintf(buf, 16384, p_format, p_list); - if (len <= 0) - return; - buf[len] = 0; - - int wlen = MultiByteToWideChar(CP_UTF8, 0, buf, len, NULL, 0); - if (wlen < 0) - return; - - wchar_t *wbuf = (wchar_t *)malloc((len + 1) * sizeof(wchar_t)); - MultiByteToWideChar(CP_UTF8, 0, buf, len, wbuf, wlen); - wbuf[wlen] = 0; - - if (p_stderr) - fwprintf(stderr, L"%s", wbuf); - else - wprintf(L"%s", wbuf); - - free(wbuf); - - fflush(stdout); -}; - void OSUWP::alert(const String &p_alert, const String &p_title) { Platform::String ^ alert = ref new Platform::String(p_alert.c_str()); @@ -520,30 +502,6 @@ OS::VideoMode OSUWP::get_video_mode(int p_screen) const { void OSUWP::get_fullscreen_mode_list(List *p_list, int p_screen) const { } -void OSUWP::print_error(const char *p_function, const char *p_file, int p_line, const char *p_code, const char *p_rationale, ErrorType p_type) { - - const char *err_details; - if (p_rationale && p_rationale[0]) - err_details = p_rationale; - else - err_details = p_code; - - switch (p_type) { - case ERR_ERROR: - print("ERROR: %s: %s\n", p_function, err_details); - print(" At: %s:%i\n", p_file, p_line); - break; - case ERR_WARNING: - print("WARNING: %s: %s\n", p_function, err_details); - print(" At: %s:%i\n", p_file, p_line); - break; - case ERR_SCRIPT: - print("SCRIPT ERROR: %s: %s\n", p_function, err_details); - print(" At: %s:%i\n", p_file, p_line); - break; - } -} - String OSUWP::get_name() { return "UWP"; @@ -890,6 +848,8 @@ OSUWP::OSUWP() { mouse_mode_changed = CreateEvent(NULL, TRUE, FALSE, L"os_mouse_mode_changed"); AudioDriverManager::add_driver(&audio_driver); + + _set_logger(memnew(WindowsTerminalLogger)); } OSUWP::~OSUWP() { diff --git a/platform/uwp/os_uwp.h b/platform/uwp/os_uwp.h index a7a5d32cb9d..df38faa8e1e 100644 --- a/platform/uwp/os_uwp.h +++ b/platform/uwp/os_uwp.h @@ -163,6 +163,7 @@ protected: virtual int get_audio_driver_count() const; virtual const char *get_audio_driver_name(int p_driver) const; + virtual void initialize_logger(); virtual void initialize_core(); virtual void initialize(const VideoMode &p_desired, int p_video_driver, int p_audio_driver); @@ -180,9 +181,6 @@ public: // Event to send to the app wrapper HANDLE mouse_mode_changed; - void print_error(const char *p_function, const char *p_file, int p_line, const char *p_code, const char *p_rationale, ErrorType p_type); - - virtual void vprint(const char *p_format, va_list p_list, bool p_stderr = false); virtual void alert(const String &p_alert, const String &p_title = "ALERT!"); String get_stdin_string(bool p_block); diff --git a/platform/windows/SCsub b/platform/windows/SCsub index fd041e096e1..211a0e74061 100644 --- a/platform/windows/SCsub +++ b/platform/windows/SCsub @@ -19,6 +19,7 @@ common_win = [ "stream_peer_winsock.cpp", "joypad.cpp", "power_windows.cpp", + "windows_terminal_logger.cpp" ] restarget = "godot_res" + env["OBJSUFFIX"] diff --git a/platform/windows/os_windows.cpp b/platform/windows/os_windows.cpp index db7cd0b938d..cf53211f5ac 100644 --- a/platform/windows/os_windows.cpp +++ b/platform/windows/os_windows.cpp @@ -48,6 +48,7 @@ #include "servers/visual/visual_server_wrap_mt.h" #include "stream_peer_winsock.h" #include "tcp_server_winsock.h" +#include "windows_terminal_logger.h" #include #include @@ -205,6 +206,13 @@ void OS_Windows::initialize_core() { cursor_shape = CURSOR_ARROW; } +void OS_Windows::initialize_logger() { + Vector loggers; + loggers.push_back(memnew(WindowsTerminalLogger)); + loggers.push_back(memnew(RotatedFileLogger("user://logs/log.txt"))); + _set_logger(memnew(CompositeLogger(loggers))); +} + bool OS_Windows::can_draw() const { return !minimized; @@ -1231,38 +1239,6 @@ void OS_Windows::finalize_core() { StreamPeerWinsock::cleanup(); } -void OS_Windows::vprint(const char *p_format, va_list p_list, bool p_stderr) { - - const unsigned int BUFFER_SIZE = 16384; - char buf[BUFFER_SIZE + 1]; // +1 for the terminating character - int len = vsnprintf(buf, BUFFER_SIZE, p_format, p_list); - if (len <= 0) - return; - if (len >= BUFFER_SIZE) - len = BUFFER_SIZE; // Output is too big, will be truncated - buf[len] = 0; - - int wlen = MultiByteToWideChar(CP_UTF8, 0, buf, len, NULL, 0); - if (wlen < 0) - return; - - wchar_t *wbuf = (wchar_t *)malloc((len + 1) * sizeof(wchar_t)); - MultiByteToWideChar(CP_UTF8, 0, buf, len, wbuf, wlen); - wbuf[wlen] = 0; - - if (p_stderr) - fwprintf(stderr, L"%ls", wbuf); - else - wprintf(L"%ls", wbuf); - -#ifdef STDOUT_FILE -//vwfprintf(stdo,p_format,p_list); -#endif - free(wbuf); - - fflush(stdout); -}; - void OS_Windows::alert(const String &p_alert, const String &p_title) { if (!is_no_window_mode_enabled()) @@ -1676,107 +1652,6 @@ void OS_Windows::request_attention() { FlashWindowEx(&info); } -void OS_Windows::print_error(const char *p_function, const char *p_file, int p_line, const char *p_code, const char *p_rationale, ErrorType p_type) { - - HANDLE hCon = GetStdHandle(STD_OUTPUT_HANDLE); - if (!hCon || hCon == INVALID_HANDLE_VALUE) { - - const char *err_details; - if (p_rationale && p_rationale[0]) - err_details = p_rationale; - else - err_details = p_code; - - switch (p_type) { - case ERR_ERROR: - print("ERROR: %s: %s\n", p_function, err_details); - print(" At: %s:%i\n", p_file, p_line); - break; - case ERR_WARNING: - print("WARNING: %s: %s\n", p_function, err_details); - print(" At: %s:%i\n", p_file, p_line); - break; - case ERR_SCRIPT: - print("SCRIPT ERROR: %s: %s\n", p_function, err_details); - print(" At: %s:%i\n", p_file, p_line); - break; - case ERR_SHADER: - print("SHADER ERROR: %s: %s\n", p_function, err_details); - print(" At: %s:%i\n", p_file, p_line); - break; - } - - } else { - - CONSOLE_SCREEN_BUFFER_INFO sbi; //original - GetConsoleScreenBufferInfo(hCon, &sbi); - - WORD current_fg = sbi.wAttributes & (FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_INTENSITY); - WORD current_bg = sbi.wAttributes & (BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE | BACKGROUND_INTENSITY); - - uint32_t basecol = 0; - switch (p_type) { - case ERR_ERROR: basecol = FOREGROUND_RED; break; - case ERR_WARNING: basecol = FOREGROUND_RED | FOREGROUND_GREEN; break; - case ERR_SCRIPT: basecol = FOREGROUND_RED | FOREGROUND_BLUE; break; - case ERR_SHADER: basecol = FOREGROUND_GREEN | FOREGROUND_BLUE; break; - } - - basecol |= current_bg; - - if (p_rationale && p_rationale[0]) { - - SetConsoleTextAttribute(hCon, basecol | FOREGROUND_INTENSITY); - switch (p_type) { - case ERR_ERROR: print("ERROR: "); break; - case ERR_WARNING: print("WARNING: "); break; - case ERR_SCRIPT: print("SCRIPT ERROR: "); break; - case ERR_SHADER: print("SHADER ERROR: "); break; - } - - SetConsoleTextAttribute(hCon, current_fg | current_bg | FOREGROUND_INTENSITY); - print("%s\n", p_rationale); - - SetConsoleTextAttribute(hCon, basecol); - switch (p_type) { - case ERR_ERROR: print(" At: "); break; - case ERR_WARNING: print(" At: "); break; - case ERR_SCRIPT: print(" At: "); break; - case ERR_SHADER: print(" At: "); break; - } - - SetConsoleTextAttribute(hCon, current_fg | current_bg); - print("%s:%i\n", p_file, p_line); - - } else { - - SetConsoleTextAttribute(hCon, basecol | FOREGROUND_INTENSITY); - switch (p_type) { - case ERR_ERROR: print("ERROR: %s: ", p_function); break; - case ERR_WARNING: print("WARNING: %s: ", p_function); break; - case ERR_SCRIPT: print("SCRIPT ERROR: %s: ", p_function); break; - case ERR_SHADER: print("SCRIPT ERROR: %s: ", p_function); break; - } - - SetConsoleTextAttribute(hCon, current_fg | current_bg | FOREGROUND_INTENSITY); - print("%s\n", p_code); - - SetConsoleTextAttribute(hCon, basecol); - switch (p_type) { - case ERR_ERROR: print(" At: "); break; - case ERR_WARNING: print(" At: "); break; - case ERR_SCRIPT: print(" At: "); break; - case ERR_SHADER: print(" At: "); break; - } - - SetConsoleTextAttribute(hCon, current_fg | current_bg); - print("%s:%i\n", p_file, p_line); - } - - SetConsoleTextAttribute(hCon, sbi.wAttributes); - } -} - String OS_Windows::get_name() { return "Windows"; @@ -2402,6 +2277,8 @@ OS_Windows::OS_Windows(HINSTANCE _hInstance) { #ifdef XAUDIO2_ENABLED AudioDriverManager::add_driver(&driver_xaudio2); #endif + + _set_logger(memnew(WindowsTerminalLogger)); } OS_Windows::~OS_Windows() { diff --git a/platform/windows/os_windows.h b/platform/windows/os_windows.h index 8a955aa2243..f80563d6fc2 100644 --- a/platform/windows/os_windows.h +++ b/platform/windows/os_windows.h @@ -152,6 +152,7 @@ protected: virtual int get_audio_driver_count() const; virtual const char *get_audio_driver_name(int p_driver) const; + virtual void initialize_logger(); virtual void initialize_core(); virtual void initialize(const VideoMode &p_desired, int p_video_driver, int p_audio_driver); @@ -180,9 +181,6 @@ protected: public: LRESULT WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam); - void print_error(const char *p_function, const char *p_file, int p_line, const char *p_code, const char *p_rationale, ErrorType p_type); - - virtual void vprint(const char *p_format, va_list p_list, bool p_stderr = false); virtual void alert(const String &p_alert, const String &p_title = "ALERT!"); String get_stdin_string(bool p_block); diff --git a/platform/windows/windows_terminal_logger.cpp b/platform/windows/windows_terminal_logger.cpp new file mode 100644 index 00000000000..ef8140ffa7d --- /dev/null +++ b/platform/windows/windows_terminal_logger.cpp @@ -0,0 +1,157 @@ +/*************************************************************************/ +/* windows_terminal_logger.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#include "windows_terminal_logger.h" + +#ifdef WINDOWS_ENABLED + +#include +#include + +void WindowsTerminalLogger::logv(const char *p_format, va_list p_list, bool p_err) { + if (!should_log(p_err)) { + return; + } + + const unsigned int BUFFER_SIZE = 16384; + char buf[BUFFER_SIZE + 1]; // +1 for the terminating character + int len = vsnprintf(buf, BUFFER_SIZE, p_format, p_list); + if (len <= 0) + return; + if (len >= BUFFER_SIZE) + len = BUFFER_SIZE; // Output is too big, will be truncated + buf[len] = 0; + + int wlen = MultiByteToWideChar(CP_UTF8, 0, buf, len, NULL, 0); + if (wlen < 0) + return; + + wchar_t *wbuf = (wchar_t *)malloc((len + 1) * sizeof(wchar_t)); + MultiByteToWideChar(CP_UTF8, 0, buf, len, wbuf, wlen); + wbuf[wlen] = 0; + + if (p_err) + fwprintf(stderr, L"%ls", wbuf); + else + wprintf(L"%ls", wbuf); + + free(wbuf); + +#ifdef DEBUG_ENABLED + fflush(stdout); +#endif +} + +void WindowsTerminalLogger::log_error(const char *p_function, const char *p_file, int p_line, const char *p_code, const char *p_rationale, ErrorType p_type) { + if (!should_log(true)) { + return; + } + +#ifndef UWP_ENABLED + HANDLE hCon = GetStdHandle(STD_OUTPUT_HANDLE); + if (!hCon || hCon == INVALID_HANDLE_VALUE) { +#endif + StdLogger::log_error(p_function, p_file, p_line, p_code, p_rationale, p_type); +#ifndef UWP_ENABLED + } else { + + CONSOLE_SCREEN_BUFFER_INFO sbi; //original + GetConsoleScreenBufferInfo(hCon, &sbi); + + WORD current_fg = sbi.wAttributes & (FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_INTENSITY); + WORD current_bg = sbi.wAttributes & (BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE | BACKGROUND_INTENSITY); + + uint32_t basecol = 0; + switch (p_type) { + case ERR_ERROR: basecol = FOREGROUND_RED; break; + case ERR_WARNING: basecol = FOREGROUND_RED | FOREGROUND_GREEN; break; + case ERR_SCRIPT: basecol = FOREGROUND_RED | FOREGROUND_BLUE; break; + case ERR_SHADER: basecol = FOREGROUND_GREEN | FOREGROUND_BLUE; break; + } + + basecol |= current_bg; + + if (p_rationale && p_rationale[0]) { + + SetConsoleTextAttribute(hCon, basecol | FOREGROUND_INTENSITY); + switch (p_type) { + case ERR_ERROR: logf("ERROR: "); break; + case ERR_WARNING: logf("WARNING: "); break; + case ERR_SCRIPT: logf("SCRIPT ERROR: "); break; + case ERR_SHADER: logf("SHADER ERROR: "); break; + } + + SetConsoleTextAttribute(hCon, current_fg | current_bg | FOREGROUND_INTENSITY); + logf("%s\n", p_rationale); + + SetConsoleTextAttribute(hCon, basecol); + switch (p_type) { + case ERR_ERROR: logf(" At: "); break; + case ERR_WARNING: logf(" At: "); break; + case ERR_SCRIPT: logf(" At: "); break; + case ERR_SHADER: logf(" At: "); break; + } + + SetConsoleTextAttribute(hCon, current_fg | current_bg); + logf("%s:%i\n", p_file, p_line); + + } else { + + SetConsoleTextAttribute(hCon, basecol | FOREGROUND_INTENSITY); + switch (p_type) { + case ERR_ERROR: logf("ERROR: %s: ", p_function); break; + case ERR_WARNING: logf("WARNING: %s: ", p_function); break; + case ERR_SCRIPT: logf("SCRIPT ERROR: %s: ", p_function); break; + case ERR_SHADER: logf("SCRIPT ERROR: %s: ", p_function); break; + } + + SetConsoleTextAttribute(hCon, current_fg | current_bg | FOREGROUND_INTENSITY); + logf("%s\n", p_code); + + SetConsoleTextAttribute(hCon, basecol); + switch (p_type) { + case ERR_ERROR: logf(" At: "); break; + case ERR_WARNING: logf(" At: "); break; + case ERR_SCRIPT: logf(" At: "); break; + case ERR_SHADER: logf(" At: "); break; + } + + SetConsoleTextAttribute(hCon, current_fg | current_bg); + logf("%s:%i\n", p_file, p_line); + } + + SetConsoleTextAttribute(hCon, sbi.wAttributes); + } +#endif +} + +WindowsTerminalLogger::~WindowsTerminalLogger() {} + +#endif \ No newline at end of file diff --git a/platform/windows/windows_terminal_logger.h b/platform/windows/windows_terminal_logger.h new file mode 100644 index 00000000000..f6b1a68d18a --- /dev/null +++ b/platform/windows/windows_terminal_logger.h @@ -0,0 +1,47 @@ +/*************************************************************************/ +/* windows_terminal_logger.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#ifndef WINDOWS_TERMINAL_LOGGER_H +#define WINDOWS_TERMINAL_LOGGER_H + +#ifdef WINDOWS_ENABLED + +#include "io/logger.h" + +class WindowsTerminalLogger : public StdLogger { +public: + virtual void logv(const char *p_format, va_list p_list, bool p_err); + virtual void log_error(const char *p_function, const char *p_file, int p_line, const char *p_code, const char *p_rationale, ErrorType p_type = ERR_ERROR); + virtual ~WindowsTerminalLogger(); +}; + +#endif + +#endif \ No newline at end of file