|
|
|
|
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
|
|
|
|
| #include <FCConfig.h>
|
|
|
| #ifdef FC_OS_WIN32
|
| # include <windows.h>
|
| #endif
|
| #include <cstring>
|
| #include <Python.h>
|
|
|
| #include <frameobject.h>
|
|
|
| #include "ConsoleObserver.h"
|
| #include "Interpreter.h"
|
| #include "Tools.h"
|
|
|
|
|
| using namespace Base;
|
|
|
|
|
|
|
|
|
|
|
| ConsoleObserverFile::ConsoleObserverFile(const char* sFileName)
|
| : cFileStream(Base::FileInfo(sFileName))
|
| {
|
| if (!cFileStream.is_open()) {
|
| Console().warning("Cannot open log file '%s'.\n", sFileName);
|
| }
|
|
|
| unsigned char bom[3] = {0xef, 0xbb, 0xbf};
|
| cFileStream.write(reinterpret_cast<const char*>(bom), 3 * sizeof(char));
|
| }
|
|
|
| ConsoleObserverFile::~ConsoleObserverFile()
|
| {
|
| cFileStream.close();
|
| }
|
|
|
| void ConsoleObserverFile::sendLog(
|
| const std::string& notifiername,
|
| const std::string& msg,
|
| LogStyle level,
|
| IntendedRecipient recipient,
|
| ContentType content
|
| )
|
| {
|
| (void)notifiername;
|
|
|
|
|
| if (recipient == IntendedRecipient::User || content == ContentType::Translated) {
|
| return;
|
| }
|
|
|
| std::string prefix;
|
| switch (level) {
|
| case LogStyle::Warning:
|
| prefix = "Wrn: ";
|
| break;
|
| case LogStyle::Message:
|
| prefix = "Msg: ";
|
| break;
|
| case LogStyle::Error:
|
| prefix = "Err: ";
|
| break;
|
| case LogStyle::Log:
|
| prefix = "Log: ";
|
| break;
|
| case LogStyle::Critical:
|
| prefix = "Critical: ";
|
| break;
|
| default:
|
| break;
|
| }
|
|
|
| cFileStream << prefix << msg;
|
| cFileStream.flush();
|
| }
|
|
|
| ConsoleObserverStd::ConsoleObserverStd()
|
| :
|
| #if defined(FC_OS_WIN32)
|
| useColorStderr(true)
|
| #elif defined(FC_OS_LINUX) || defined(FC_OS_MACOSX) || defined(FC_OS_BSD)
|
| useColorStderr(isatty(STDERR_FILENO))
|
| #else
|
| useColorStderr(false)
|
| #endif
|
| {
|
| bLog = false;
|
| }
|
|
|
| ConsoleObserverStd::~ConsoleObserverStd() = default;
|
|
|
| void ConsoleObserverStd::sendLog(
|
| const std::string& notifiername,
|
| const std::string& msg,
|
| LogStyle level,
|
| IntendedRecipient recipient,
|
| ContentType content
|
| )
|
| {
|
| (void)notifiername;
|
|
|
|
|
| if (recipient == IntendedRecipient::User || content == ContentType::Translated) {
|
| return;
|
| }
|
|
|
| switch (level) {
|
| case LogStyle::Warning:
|
| this->Warning(msg.c_str());
|
| break;
|
| case LogStyle::Message:
|
| this->Message(msg.c_str());
|
| break;
|
| case LogStyle::Error:
|
| this->Error(msg.c_str());
|
| break;
|
| case LogStyle::Log:
|
| this->Log(msg.c_str());
|
| break;
|
| case LogStyle::Critical:
|
| this->Critical(msg.c_str());
|
| break;
|
| default:
|
| break;
|
| }
|
| }
|
|
|
| void ConsoleObserverStd::Message(const char* sMsg)
|
| {
|
| printf("%s", sMsg);
|
| }
|
|
|
| void ConsoleObserverStd::Warning(const char* sWarn)
|
| {
|
| if (useColorStderr) {
|
| #if defined(FC_OS_WIN32)
|
| ::SetConsoleTextAttribute(::GetStdHandle(STD_ERROR_HANDLE), FOREGROUND_GREEN | FOREGROUND_BLUE);
|
| #elif defined(FC_OS_LINUX) || defined(FC_OS_MACOSX) || defined(FC_OS_BSD)
|
| fprintf(stderr, "\033[1;33m");
|
| #endif
|
| }
|
|
|
| fprintf(stderr, "%s", sWarn);
|
|
|
| if (useColorStderr) {
|
| #if defined(FC_OS_WIN32)
|
| ::SetConsoleTextAttribute(
|
| ::GetStdHandle(STD_ERROR_HANDLE),
|
| FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE
|
| );
|
| #elif defined(FC_OS_LINUX) || defined(FC_OS_MACOSX) || defined(FC_OS_BSD)
|
| fprintf(stderr, "\033[0m");
|
| #endif
|
| }
|
| }
|
|
|
| void ConsoleObserverStd::Error(const char* sErr)
|
| {
|
| if (useColorStderr) {
|
| #if defined(FC_OS_WIN32)
|
| ::SetConsoleTextAttribute(
|
| ::GetStdHandle(STD_ERROR_HANDLE),
|
| FOREGROUND_RED | FOREGROUND_INTENSITY
|
| );
|
| #elif defined(FC_OS_LINUX) || defined(FC_OS_MACOSX) || defined(FC_OS_BSD)
|
| fprintf(stderr, "\033[1;31m");
|
| #endif
|
| }
|
|
|
| fprintf(stderr, "%s", sErr);
|
|
|
| if (useColorStderr) {
|
| #if defined(FC_OS_WIN32)
|
| ::SetConsoleTextAttribute(
|
| ::GetStdHandle(STD_ERROR_HANDLE),
|
| FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE
|
| );
|
| #elif defined(FC_OS_LINUX) || defined(FC_OS_MACOSX) || defined(FC_OS_BSD)
|
| fprintf(stderr, "\033[0m");
|
| #endif
|
| }
|
| }
|
|
|
| void ConsoleObserverStd::Log(const char* sLog)
|
| {
|
| if (useColorStderr) {
|
| #if defined(FC_OS_WIN32)
|
| ::SetConsoleTextAttribute(::GetStdHandle(STD_ERROR_HANDLE), FOREGROUND_RED | FOREGROUND_GREEN);
|
| #elif defined(FC_OS_LINUX) || defined(FC_OS_MACOSX) || defined(FC_OS_BSD)
|
| fprintf(stderr, "\033[1;36m");
|
| #endif
|
| }
|
|
|
| fprintf(stderr, "%s", sLog);
|
|
|
| if (useColorStderr) {
|
| #if defined(FC_OS_WIN32)
|
| ::SetConsoleTextAttribute(
|
| ::GetStdHandle(STD_ERROR_HANDLE),
|
| FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE
|
| );
|
| #elif defined(FC_OS_LINUX) || defined(FC_OS_MACOSX) || defined(FC_OS_BSD)
|
| fprintf(stderr, "\033[0m");
|
| #endif
|
| }
|
| }
|
|
|
| void ConsoleObserverStd::Critical(const char* sCritical)
|
| {
|
| if (useColorStderr) {
|
| #if defined(FC_OS_WIN32)
|
| ::SetConsoleTextAttribute(::GetStdHandle(STD_ERROR_HANDLE), FOREGROUND_GREEN | FOREGROUND_BLUE);
|
| #elif defined(FC_OS_LINUX) || defined(FC_OS_MACOSX) || defined(FC_OS_BSD)
|
| fprintf(stderr, "\033[1;33m");
|
| #endif
|
| }
|
|
|
| fprintf(stderr, "%s", sCritical);
|
|
|
| if (useColorStderr) {
|
| #if defined(FC_OS_WIN32)
|
| ::SetConsoleTextAttribute(
|
| ::GetStdHandle(STD_ERROR_HANDLE),
|
| FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE
|
| );
|
| #elif defined(FC_OS_LINUX) || defined(FC_OS_MACOSX) || defined(FC_OS_BSD)
|
| fprintf(stderr, "\033[0m");
|
| #endif
|
| }
|
| }
|
|
|
| RedirectStdOutput::RedirectStdOutput()
|
| {
|
| buffer.reserve(80);
|
| }
|
|
|
| int RedirectStdOutput::overflow(int ch)
|
| {
|
| if (ch != EOF) {
|
| buffer.push_back(static_cast<char>(ch));
|
| }
|
| return ch;
|
| }
|
|
|
| int RedirectStdOutput::sync()
|
| {
|
|
|
| if (!buffer.empty() && buffer.back() == '\n') {
|
| Base::Console().log("%s", buffer.c_str());
|
| buffer.clear();
|
| }
|
| return 0;
|
| }
|
|
|
| RedirectStdLog::RedirectStdLog()
|
| {
|
| buffer.reserve(80);
|
| }
|
|
|
| int RedirectStdLog::overflow(int ch)
|
| {
|
| if (ch != EOF) {
|
| buffer.push_back(static_cast<char>(ch));
|
| }
|
| return ch;
|
| }
|
|
|
| int RedirectStdLog::sync()
|
| {
|
|
|
| if (!buffer.empty() && buffer.back() == '\n') {
|
| Base::Console().log("%s", buffer.c_str());
|
| buffer.clear();
|
| }
|
| return 0;
|
| }
|
|
|
| RedirectStdError::RedirectStdError()
|
| {
|
| buffer.reserve(80);
|
| }
|
|
|
| int RedirectStdError::overflow(int ch)
|
| {
|
| if (ch != EOF) {
|
| buffer.push_back(static_cast<char>(ch));
|
| }
|
| return ch;
|
| }
|
|
|
| int RedirectStdError::sync()
|
| {
|
| if (!buffer.empty() && buffer.back() == '\n') {
|
| Base::Console().error("%s", buffer.c_str());
|
| buffer.clear();
|
| }
|
| return 0;
|
| }
|
|
|
|
|
|
|
| std::stringstream& LogLevel::prefix(std::stringstream& str, const char* src, int line)
|
| {
|
| static FC_TIME_POINT s_tstart;
|
| static bool s_timing = false;
|
| if (print_time) {
|
| if (!s_timing) {
|
| s_timing = true;
|
| _FC_TIME_INIT(s_tstart);
|
| }
|
| auto tnow = std::chrono::FC_TIME_CLOCK::now();
|
| auto dc = std::chrono::duration_cast<FC_DURATION>(tnow - s_tstart);
|
| str << dc.count() << ' ';
|
| }
|
| if (print_tag) {
|
| str << '<' << tag << "> ";
|
| }
|
| if (print_src == 2) {
|
| Base::PyGILStateLocker lock;
|
| PyFrameObject* frame = PyEval_GetFrame();
|
| if (frame) {
|
| line = PyFrame_GetLineNumber(frame);
|
| #if PY_VERSION_HEX < 0x030b0000
|
| src = PyUnicode_AsUTF8(frame->f_code->co_filename);
|
| #else
|
| PyCodeObject* code = PyFrame_GetCode(frame);
|
| src = PyUnicode_AsUTF8(code->co_filename);
|
| Py_DECREF(code);
|
| #endif
|
| }
|
| }
|
| if (print_src && !Base::Tools::isNullOrEmpty(src)) {
|
| #ifdef FC_OS_WIN32
|
| const char* _f = std::strrchr(src, '\\');
|
| #else
|
| const char* _f = std::strrchr(src, '/');
|
| #endif
|
| str << (_f ? _f + 1 : src) << "(" << line << "): ";
|
| }
|
| return str;
|
| }
|
|
|