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.
This commit is contained in:
Ruslan Mustakov 2017-09-22 12:56:02 +07:00
parent 14b4ad931f
commit 1a2311e350
49 changed files with 948 additions and 332 deletions

View file

@ -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;

View file

@ -76,6 +76,11 @@ protected:
};
public:
void flush() {
f.flush();
};
void store_8(uint8_t p_dest) {
f.store_8(p_dest);

View file

@ -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);

View file

@ -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

View file

@ -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);

View file

@ -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

View file

@ -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);

View file

@ -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

View file

@ -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();

View file

@ -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

View file

@ -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();

View file

@ -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);

View file

@ -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();

View file

@ -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

252
core/io/logger.cpp Normal file
View file

@ -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<String> 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<String>::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<Logger *> 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]);
}
}

107
core/io/logger.h Normal file
View file

@ -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 <stdarg.h>
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<Logger *> loggers;
public:
CompositeLogger(Vector<Logger *> 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

View file

@ -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);

View file

@ -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

View file

@ -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;
}

View file

@ -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;

View file

@ -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);

View file

@ -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

View file

@ -64,39 +64,7 @@
#include <string.h>
#include <sys/time.h>
#include <sys/wait.h>
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 <unistd.h>
void OS_Unix::debug_break() {
@ -165,29 +133,16 @@ void OS_Unix::initialize_core() {
}
}
void OS_Unix::initialize_logger() {
Vector<Logger *> 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

View file

@ -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

View file

@ -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 <syslog.h>
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

View file

@ -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

View file

@ -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;

View file

@ -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);

View file

@ -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

View file

@ -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));

View file

@ -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();

View file

@ -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

View file

@ -157,6 +157,9 @@ Error FileAccessJAndroid::get_error() const {
return OK;
}
void FileAccessJAndroid::flush() {
}
void FileAccessJAndroid::store_8(uint8_t p_dest) {
}

View file

@ -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

View file

@ -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<Logger *> 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() {

View file

@ -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);

View file

@ -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<Logger *> 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() {

View file

@ -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);

View file

@ -85,6 +85,10 @@ void OS_JavaScript::initialize_core() {
FileAccess::make_default<FileAccessBufferedFA<FileAccessUnix> >(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);

View file

@ -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);

View file

@ -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);

View file

@ -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<Logger *> 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) {

View file

@ -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<Logger *> 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<VideoMode> *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() {

View file

@ -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);

View file

@ -19,6 +19,7 @@ common_win = [
"stream_peer_winsock.cpp",
"joypad.cpp",
"power_windows.cpp",
"windows_terminal_logger.cpp"
]
restarget = "godot_res" + env["OBJSUFFIX"]

View file

@ -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 <process.h>
#include <regstr.h>
@ -205,6 +206,13 @@ void OS_Windows::initialize_core() {
cursor_shape = CURSOR_ARROW;
}
void OS_Windows::initialize_logger() {
Vector<Logger *> 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() {

View file

@ -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);

View file

@ -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 <stdio.h>
#include <windows.h>
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

View file

@ -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