From 916ada108ffd66281bf633de877f1b7b5e55a714 Mon Sep 17 00:00:00 2001 From: Koncord Date: Wed, 25 Oct 2017 14:38:18 +0800 Subject: [PATCH 1/6] [General] Modernize Log utility * Reverse Log levels * Add LOG_TRACE * Spawn instance of Log in Get() function --- apps/openmw-mp/main.cpp | 2 -- components/openmw-mp/Log.cpp | 42 ++++++++++++++---------------------- components/openmw-mp/Log.hpp | 22 +++++++++---------- 3 files changed, 27 insertions(+), 39 deletions(-) diff --git a/apps/openmw-mp/main.cpp b/apps/openmw-mp/main.cpp index ef6ea55c5..3f8c06bbc 100644 --- a/apps/openmw-mp/main.cpp +++ b/apps/openmw-mp/main.cpp @@ -153,8 +153,6 @@ int main(int argc, char *argv[]) auto version = Version::getOpenmwVersion(variables["resources"].as().toStdString()); int logLevel = mgr.getInt("logLevel", "General"); - if (logLevel < Log::LOG_VERBOSE || logLevel > Log::LOG_FATAL) - logLevel = Log::LOG_VERBOSE; // Some objects used to redirect cout and cerr // Scope must be here, so this still works inside the catch block for logging exceptions diff --git a/components/openmw-mp/Log.cpp b/components/openmw-mp/Log.cpp index 0ed414337..0f07703e9 100644 --- a/components/openmw-mp/Log.cpp +++ b/components/openmw-mp/Log.cpp @@ -14,41 +14,25 @@ using namespace std; -Log *Log::sLog = nullptr; - Log::Log(int logLevel) : logLevel(logLevel) { } -void Log::Create(int logLevel) -{ - if (sLog != nullptr) - return; - sLog = new Log(logLevel); -} - -void Log::Delete() -{ - if (sLog == nullptr) - return; - delete sLog; - sLog = nullptr; -} - -const Log &Log::Get() +Log &Log::Get() { - return *sLog; + static Log instance(1000); + return instance; } void Log::SetLevel(int level) { - sLog->logLevel = level; + logLevel = level; } const char* getTime() { - time_t t = time(0); + time_t t = time(nullptr); struct tm *tm = localtime(&t); static char result[20]; sprintf(result, "%.4d-%.2d-%.2d %.2d:%.2d:%.2d", @@ -59,7 +43,7 @@ const char* getTime() void Log::print(int level, bool hasPrefix, const char *file, int line, const char *message, ...) const { - if (level < logLevel) return; + if (level > logLevel || logLevel == LOG_OFF) return; std::stringstream sstr; if (hasPrefix) @@ -67,7 +51,7 @@ void Log::print(int level, bool hasPrefix, const char *file, int line, const cha sstr << "[" << getTime() << "] "; - if (file != 0 && line != 0) + if (file != nullptr && line != 0) { sstr << "[" << file << ":"; sstr << line << "] "; @@ -85,6 +69,13 @@ void Log::print(int level, bool hasPrefix, const char *file, int line, const cha case LOG_FATAL: sstr << "FATAL"; break; + case LOG_TRACE: + sstr << "TRACE"; + break; + case LOG_VERBOSE: + case LOG_INFO: + sstr << "INFO"; + break; default: sstr << "INFO"; } @@ -108,10 +99,9 @@ void Log::print(int level, bool hasPrefix, const char *file, int line, const cha string Log::getFilenameTimestamp() { - time_t rawtime = time(0); + time_t rawtime = time(nullptr); struct tm *timeinfo = localtime(&rawtime); char buffer[25]; strftime(buffer, 25, "%Y-%m-%d-%H_%M_%S", timeinfo); - std::string timestamp(buffer); - return timestamp; + return string(buffer); } diff --git a/components/openmw-mp/Log.hpp b/components/openmw-mp/Log.hpp index 31d6565d9..c2a648037 100644 --- a/components/openmw-mp/Log.hpp +++ b/components/openmw-mp/Log.hpp @@ -17,8 +17,8 @@ #define LOG_MESSAGE(level, msg, ...) #define LOG_MESSAGE_SIMPLE(level, msg, ...) #else -#define LOG_INIT(logLevel) Log::Create(logLevel) -#define LOG_QUIT() Log::Delete() +#define LOG_INIT(logLevel) Log::Get().SetLevel(logLevel) +#define LOG_QUIT() #if defined(_MSC_VER) #define LOG_MESSAGE(level, msg, ...) Log::Get().print((level), (1), (__FILE__), (__LINE__), (msg), __VA_ARGS__) #define LOG_MESSAGE_SIMPLE(level, msg, ...) Log::Get().print((level), (1), (0), (0), (msg), __VA_ARGS__) @@ -35,16 +35,17 @@ class Log public: enum { - LOG_VERBOSE = 0, - LOG_INFO, - LOG_WARN, + LOG_OFF = 0, + LOG_FATAL, LOG_ERROR, - LOG_FATAL + LOG_WARN, + LOG_INFO, + LOG_VERBOSE, + LOG_TRACE, }; - static void Create(int logLevel); - static void Delete(); - static const Log &Get(); - static void SetLevel(int level); + + static Log &Get(); + void SetLevel(int level); void print(int level, bool hasPrefix, const char *file, int line, const char *message, ...) const; static std::string getFilenameTimestamp(); @@ -53,7 +54,6 @@ public: Log &operator=(Log &) = delete; private: explicit Log(int logLevel); - static Log *sLog; int logLevel; }; From a3d5fbbdcdf570585ad824685ec3e1ebd97fd2e5 Mon Sep 17 00:00:00 2001 From: Koncord Date: Wed, 25 Oct 2017 14:44:01 +0800 Subject: [PATCH 2/6] [Server] Add stacktrace --- apps/openmw-mp/stacktrace.cpp | 73 +++++++++++++++++++++++++++++++++++ apps/openmw-mp/stacktrace.hpp | 10 +++++ 2 files changed, 83 insertions(+) create mode 100644 apps/openmw-mp/stacktrace.cpp create mode 100644 apps/openmw-mp/stacktrace.hpp diff --git a/apps/openmw-mp/stacktrace.cpp b/apps/openmw-mp/stacktrace.cpp new file mode 100644 index 000000000..858462a93 --- /dev/null +++ b/apps/openmw-mp/stacktrace.cpp @@ -0,0 +1,73 @@ +// +// Created by koncord on 25.10.17. +// + +#include "stacktrace.hpp" +#include + +#ifndef _WIN32 + +#include + +void stacktrace() +{ + LOG_MESSAGE_SIMPLE(Log::LOG_FATAL, "Stacktrace:"); + + void *array[50]; + int size = backtrace(array, 50); + + auto messages = backtrace_symbols(array, size); + + size_t funcnamesize = 256; + auto funcname = (char *) malloc(funcnamesize); + //skip first stack frame (points here) + for (int i = 1; i < size && messages != nullptr; ++i) + { + char *beginName = nullptr, *beginOffset = nullptr, *endOffset = nullptr; + for (char *p = messages[i]; *p; ++p) + { + if (*p == '(') + beginName = p; + else if (*p == '+') + beginOffset = p; + else if (*p == ')' && beginOffset) + { + endOffset = p; + break; + } + } + + if (beginName && beginOffset && endOffset && beginName < beginOffset) + { + *beginName++ = '\0'; + *beginOffset++ = '\0'; + *endOffset = '\0'; + + // mangled name is now in [beginName, beginOffset) and caller offset in [beginOffset, endOffset). + + int status; + char *ret = abi::__cxa_demangle(beginName, funcname, &funcnamesize, &status); + if (status == 0) + { + funcname = ret; // use possibly realloc()-ed string + LOG_APPEND(Log::LOG_FATAL, "\t%s : %s+%s", messages[i], funcname, beginOffset); + } + else // demangling failed. + LOG_APPEND(Log::LOG_FATAL, "\t%s : %s()+%s", messages[i], beginName, beginOffset); + } + else + LOG_APPEND(Log::LOG_FATAL, "\t%s", messages[i]); + } + + free(messages); + free(funcname); +} + +#else + +void stacktrace() +{ + +} + +#endif \ No newline at end of file diff --git a/apps/openmw-mp/stacktrace.hpp b/apps/openmw-mp/stacktrace.hpp new file mode 100644 index 000000000..283cf3143 --- /dev/null +++ b/apps/openmw-mp/stacktrace.hpp @@ -0,0 +1,10 @@ +// +// Created by koncord on 25.10.17. +// + +#ifndef OPENMW_STACKTRACE_HPP +#define OPENMW_STACKTRACE_HPP + +void stacktrace(); + +#endif //OPENMW_STACKTRACE_HPP From dad0b38f25c70e19cf9296ed0e0afbeae25de897 Mon Sep 17 00:00:00 2001 From: Koncord Date: Wed, 25 Oct 2017 14:45:06 +0800 Subject: [PATCH 3/6] [Server] Add custom terminate handler with stacktrace --- apps/openmw-mp/main.cpp | 137 +++++++++++++++++++++------------------- 1 file changed, 73 insertions(+), 64 deletions(-) diff --git a/apps/openmw-mp/main.cpp b/apps/openmw-mp/main.cpp index 3f8c06bbc..96af274cc 100644 --- a/apps/openmw-mp/main.cpp +++ b/apps/openmw-mp/main.cpp @@ -139,8 +139,25 @@ boost::program_options::variables_map launchOptions(int argc, char *argv[], File return variables; } +#include "stacktrace.hpp" + + int main(int argc, char *argv[]) { + set_terminate([]() { + try + { + rethrow_exception(current_exception()); + } + catch (const exception &e) + { + LOG_MESSAGE_SIMPLE(Log::LOG_FATAL, " Woops, something wrong! Exception:\n\t%s", e.what()); + } + + stacktrace(); + abort(); + }); + Settings::Manager mgr; Files::ConfigurationManager cfgMgr; @@ -210,84 +227,76 @@ int main(int argc, char *argv[]) RakNet::SocketDescriptor sd((unsigned short) port, addr.c_str()); - //try + switch (peer->Startup((unsigned) players, &sd, 1)) { + case RakNet::RAKNET_STARTED: + break; + case RakNet::RAKNET_ALREADY_STARTED: + throw runtime_error("Already started"); + case RakNet::INVALID_SOCKET_DESCRIPTORS: + throw runtime_error("Incorrect port or address"); + case RakNet::INVALID_MAX_CONNECTIONS: + throw runtime_error("Max players cannot be negative or 0"); + case RakNet::SOCKET_FAILED_TO_BIND: + case RakNet::SOCKET_PORT_ALREADY_IN_USE: + case RakNet::PORT_CANNOT_BE_ZERO: + throw runtime_error("Failed to bind port"); + case RakNet::SOCKET_FAILED_TEST_SEND: + case RakNet::SOCKET_FAMILY_NOT_SUPPORTED: + case RakNet::FAILED_TO_CREATE_NETWORK_THREAD: + case RakNet::COULD_NOT_GENERATE_GUID: + case RakNet::STARTUP_OTHER_FAILURE: + throw runtime_error("Cannot start server"); + } - switch (peer->Startup((unsigned) players, &sd, 1)) - { - case RakNet::RAKNET_STARTED: - break; - case RakNet::RAKNET_ALREADY_STARTED: - throw runtime_error("Already started"); - case RakNet::INVALID_SOCKET_DESCRIPTORS: - throw runtime_error("Incorrect port or address"); - case RakNet::INVALID_MAX_CONNECTIONS: - throw runtime_error("Max players cannot be negative or 0"); - case RakNet::SOCKET_FAILED_TO_BIND: - case RakNet::SOCKET_PORT_ALREADY_IN_USE: - case RakNet::PORT_CANNOT_BE_ZERO: - throw runtime_error("Failed to bind port"); - case RakNet::SOCKET_FAILED_TEST_SEND: - case RakNet::SOCKET_FAMILY_NOT_SUPPORTED: - case RakNet::FAILED_TO_CREATE_NETWORK_THREAD: - case RakNet::COULD_NOT_GENERATE_GUID: - case RakNet::STARTUP_OTHER_FAILURE: - throw runtime_error("Cannot start server"); - } + peer->SetMaximumIncomingConnections((unsigned short) (players)); - peer->SetMaximumIncomingConnections((unsigned short) (players)); + Networking networking(peer); - Networking networking(peer); + string plugin_home = mgr.getString("home", "Plugins"); - string plugin_home = mgr.getString("home", "Plugins"); + if (mgr.getBool("autoSort", "Plugins")) + networking.getState().loadMods(plugin_home); + else + { + std::vector list; - if (mgr.getBool("autoSort", "Plugins")) - networking.getState().loadMods(plugin_home); - else + try { - std::vector list; - - try - { - for (int i = 0;; ++i) - list.push_back(mgr.getString("Plugin" + to_string(i), "Plugins")); - } - catch (...) {} // Manager::getString throws runtime_error exception if setting is not exist - - networking.getState().loadMods(plugin_home, &list); + for (int i = 0;; ++i) + list.push_back(mgr.getString("Plugin" + to_string(i), "Plugins")); } + catch (...) + {} // Manager::getString throws runtime_error exception if setting is not exist + networking.getState().loadMods(plugin_home, &list); + } - networking.setServerPassword(passw); - if (mgr.getBool("enabled", "MasterServer")) - { - LOG_MESSAGE_SIMPLE(Log::LOG_INFO, "Sharing server query info to master enabled."); - string masterAddr = mgr.getString("address", "MasterServer"); - int masterPort = mgr.getInt("port", "MasterServer"); - int updateRate = mgr.getInt("rate", "MasterServer"); - - networking.InitQuery(masterAddr, (unsigned short) masterPort); - networking.getMasterClient()->SetMaxPlayers((unsigned) players); - networking.getMasterClient()->SetUpdateRate((unsigned) updateRate); - string hostname = mgr.getString("hostname", "General"); - networking.getMasterClient()->SetHostname(hostname); - networking.getMasterClient()->SetRuleString("CommitHash", version.mCommitHash.substr(0, 10)); - - networking.getMasterClient()->Start(); - } + networking.setServerPassword(passw); - networking.postInit(); + if (mgr.getBool("enabled", "MasterServer")) + { + LOG_MESSAGE_SIMPLE(Log::LOG_INFO, "Sharing server query info to master enabled."); + string masterAddr = mgr.getString("address", "MasterServer"); + int masterPort = mgr.getInt("port", "MasterServer"); + int updateRate = mgr.getInt("rate", "MasterServer"); + + networking.InitQuery(masterAddr, (unsigned short) masterPort); + networking.getMasterClient()->SetMaxPlayers((unsigned) players); + networking.getMasterClient()->SetUpdateRate((unsigned) updateRate); + string hostname = mgr.getString("hostname", "General"); + networking.getMasterClient()->SetHostname(hostname); + networking.getMasterClient()->SetRuleString("CommitHash", version.mCommitHash.substr(0, 10)); + + networking.getMasterClient()->Start(); + } - code = networking.mainLoop(); + networking.postInit(); - networking.getMasterClient()->Stop(); - } - /*catch (std::exception &e) - { - LOG_MESSAGE_SIMPLE(Log::LOG_ERROR, e.what()); - throw; //fall through - }*/ + code = networking.mainLoop(); + + networking.getMasterClient()->Stop(); RakNet::RakPeerInterface::DestroyInstance(peer); From 04a844a9c000a58bdc41b51394061757d94725f6 Mon Sep 17 00:00:00 2001 From: Koncord Date: Wed, 25 Oct 2017 15:21:11 +0800 Subject: [PATCH 4/6] [Server] Use sol's default_handler --- apps/openmw-mp/Script/LuaState.cpp | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/apps/openmw-mp/Script/LuaState.cpp b/apps/openmw-mp/Script/LuaState.cpp index b9e930518..ab67c1125 100644 --- a/apps/openmw-mp/Script/LuaState.cpp +++ b/apps/openmw-mp/Script/LuaState.cpp @@ -80,16 +80,6 @@ LuaState::LuaState() configEnv = sol::environment(*lua, sol::create, lua->globals()); lua->set("Config", configEnv); // plain global environment for mod configuration - // errors in sol::functions are caught only in Debug or RelWithDebInfo builds for better performance -#ifdef SOL_SAFE_FUNCTIONS - lua->set_function("ErrorHandler", [](sol::object error_msg) { - LOG_MESSAGE_SIMPLE(Log::LOG_ERROR, ("Lua: " + error_msg.as()).c_str()); - }); - - sol::reference errHandler = (*lua)["ErrorHandler"]; - sol::protected_function::set_default_handler(errHandler); -#endif - sol::table Constants = lua->create_named_table("Constants"); Constants.set_function("getAttributeCount", []() { From 05abb8ace3c43dc20e1f42dfd6130baf42a20c04 Mon Sep 17 00:00:00 2001 From: Koncord Date: Wed, 25 Oct 2017 15:22:07 +0800 Subject: [PATCH 5/6] [Server] Add Log level constants to lua --- apps/openmw-mp/Script/LuaState.cpp | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/apps/openmw-mp/Script/LuaState.cpp b/apps/openmw-mp/Script/LuaState.cpp index ab67c1125..93f986607 100644 --- a/apps/openmw-mp/Script/LuaState.cpp +++ b/apps/openmw-mp/Script/LuaState.cpp @@ -138,6 +138,14 @@ LuaState::LuaState() LOG_APPEND(level, "%s", message); }); + lua->new_enum("Log" + "LOG_FATAL", Log::LOG_FATAL, + "LOG_ERROR", Log::LOG_ERROR, + "LOG_WARN", Log::LOG_WARN, + "LOG_INFO", Log::LOG_INFO, + "LOG_VERBOSE", Log::LOG_VERBOSE, + "LOG_TRACE", Log::LOG_TRACE); + lua->set_function("stopServer", [](int code) { mwmp::Networking::getPtr()->stopServer(code); }); @@ -425,7 +433,7 @@ vector::iterator> loadOrderSolver(vector *list) @@ -446,7 +454,7 @@ void LuaState::loadMods(const std::string &modDir, std::vector *lis ServerPluginInfo modInfo; - modInfo.path = std::make_pair(homePath.string(), modDir.path().filename().string()); + modInfo.path = make_pair(homePath.string(), modDir.path().filename().string()); modInfo.author = pt.get("author"); modInfo.version = pt.get("version"); From d44848ecbb35056dc7441b23219686787a69f5ee Mon Sep 17 00:00:00 2001 From: Koncord Date: Wed, 25 Oct 2017 16:05:45 +0800 Subject: [PATCH 6/6] [Server] Fix build --- apps/openmw-mp/Script/LuaState.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw-mp/Script/LuaState.cpp b/apps/openmw-mp/Script/LuaState.cpp index 93f986607..a5284cc18 100644 --- a/apps/openmw-mp/Script/LuaState.cpp +++ b/apps/openmw-mp/Script/LuaState.cpp @@ -138,7 +138,7 @@ LuaState::LuaState() LOG_APPEND(level, "%s", message); }); - lua->new_enum("Log" + lua->new_enum("Log", "LOG_FATAL", Log::LOG_FATAL, "LOG_ERROR", Log::LOG_ERROR, "LOG_WARN", Log::LOG_WARN,