Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 5 additions & 2 deletions Dockerfile.browser
Original file line number Diff line number Diff line change
Expand Up @@ -62,12 +62,15 @@ RUN source /opt/emsdk/emsdk_env.sh \
-DTOGGLE_BOT_PROTECTION=OFF \
-DCMAKE_BUILD_TYPE=${BUILD_TYPE} \
-DCMAKE_CXX_STANDARD=20 \
-DCMAKE_C_FLAGS="-pthread -matomics -mbulk-memory -fno-lto" \
-DCMAKE_CXX_FLAGS="-pthread -matomics -mbulk-memory -fno-lto -std=c++20 -D_LIBCPP_DISABLE_AVAILABILITY -fexperimental-library" \
-DCMAKE_C_FLAGS="-pthread -matomics -mbulk-memory -fno-lto -DFMT_USE_NONTYPE_TEMPLATE_ARGS=0 -DFMT_USE_CONSTEVAL=0" \
-DCMAKE_CXX_FLAGS="-pthread -matomics -mbulk-memory -fno-lto -std=c++20 -D_LIBCPP_DISABLE_AVAILABILITY -fexperimental-library -DFMT_USE_NONTYPE_TEMPLATE_ARGS=0 -DFMT_USE_CONSTEVAL=0" \
-DCMAKE_EXE_LINKER_FLAGS="-pthread -matomics -mbulk-memory -s ALLOW_MEMORY_GROWTH=1 -s USE_PTHREADS=1 -s PTHREAD_POOL_SIZE=4 -s WASM=1 -s NO_EXIT_RUNTIME=1 -fno-lto" \
-DCMAKE_CXX_FLAGS_RELEASE="-O2 -DNDEBUG -fno-lto" \
-DCMAKE_CXX_FLAGS_DEBUG="-O0 -g -fno-lto" \
-DCMAKE_INTERPROCEDURAL_OPTIMIZATION=OFF \
&& sed -i \
's/define SPDLOG_FMT_STRING(format_string) FMT_STRING(format_string)/define SPDLOG_FMT_STRING(format_string) (format_string)/' \
${BUILD_DIR}/vcpkg_installed/wasm32-emscripten-pthread/include/spdlog/common.h \
&& cmake --build ${BUILD_DIR} --target otclient -j"$(nproc)"

# NOSONAR: minimal BusyBox stage used only to package static artifacts, root default is acceptable
Expand Down
12 changes: 8 additions & 4 deletions browser/triplets/wasm32-emscripten-pthread.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,16 @@ set(VCPKG_CHAINLOAD_TOOLCHAIN_FILE "$ENV{EMSDK}/upstream/emscripten/cmake/Module

# Force pthread support with atomics and bulk-memory for all packages
# These flags are required for shared memory support in WebAssembly
set(VCPKG_C_FLAGS "-pthread -matomics -mbulk-memory")
set(VCPKG_CXX_FLAGS "-pthread -matomics -mbulk-memory")
# FMT_USE_CONSTEVAL=0: disables fmt's consteval format-string constructor which
# emscripten's Clang cannot satisfy inside catch blocks (SPDLOG_LOGGER_CATCH).
# FMT_USE_NONTYPE_TEMPLATE_ARGS=0: disables C++20 non-type template args in fmt
# which are not reliably supported by the emscripten toolchain.
set(VCPKG_C_FLAGS "-pthread -matomics -mbulk-memory -DFMT_USE_CONSTEVAL=0 -DFMT_USE_NONTYPE_TEMPLATE_ARGS=0")
set(VCPKG_CXX_FLAGS "-pthread -matomics -mbulk-memory -DFMT_USE_CONSTEVAL=0 -DFMT_USE_NONTYPE_TEMPLATE_ARGS=0")
set(VCPKG_LINKER_FLAGS "-pthread -matomics -mbulk-memory")

# Also set as CMAKE_*_FLAGS to ensure they're applied universally
set(VCPKG_CMAKE_CONFIGURE_OPTIONS
"-DCMAKE_C_FLAGS=-pthread -matomics -mbulk-memory"
"-DCMAKE_CXX_FLAGS=-pthread -matomics -mbulk-memory"
"-DCMAKE_C_FLAGS=-pthread -matomics -mbulk-memory -DFMT_USE_CONSTEVAL=0 -DFMT_USE_NONTYPE_TEMPLATE_ARGS=0"
"-DCMAKE_CXX_FLAGS=-pthread -matomics -mbulk-memory -DFMT_USE_CONSTEVAL=0 -DFMT_USE_NONTYPE_TEMPLATE_ARGS=0"
)
5 changes: 5 additions & 0 deletions src/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,7 @@ find_package(pugixml CONFIG REQUIRED)
find_package(ZLIB REQUIRED)
find_package(httplib CONFIG REQUIRED)
find_package(fmt CONFIG REQUIRED)
find_package(spdlog CONFIG REQUIRED)
find_package(utf8cpp REQUIRED)
find_package(unofficial-inih CONFIG REQUIRED)
find_package(Freetype REQUIRED)
Expand Down Expand Up @@ -558,6 +559,7 @@ if(MSVC)
winmm.lib
pugixml::pugixml
fmt::fmt-header-only
spdlog::spdlog_header_only
utf8cpp::utf8cpp
Freetype::Freetype
)
Expand Down Expand Up @@ -609,6 +611,7 @@ elseif(ANDROID)
log
pugixml::pugixml
fmt::fmt-header-only
spdlog::spdlog_header_only
utf8cpp::utf8cpp
)

Expand Down Expand Up @@ -673,6 +676,7 @@ elseif(WASM)
OpenSSL::Crypto
httplib::httplib
fmt::fmt
spdlog::spdlog_header_only
utf8cpp::utf8cpp
Ogg::ogg
Vorbis::vorbisfile
Expand Down Expand Up @@ -790,6 +794,7 @@ else() # Linux
OpenSSL::Crypto
httplib::httplib
fmt::fmt-header-only
spdlog::spdlog_header_only
utf8cpp::utf8cpp
Ogg::ogg
Vorbis::vorbisfile
Expand Down
2 changes: 0 additions & 2 deletions src/framework/core/consoleapplication.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,6 @@
#include <framework/core/asyncdispatcher.h>
#include <framework/stdext/time.h>

#include <iostream>

#ifdef FW_NET
#include <framework/net/connection.h>
#endif
Expand Down
117 changes: 114 additions & 3 deletions src/framework/core/logger.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,12 @@
#include "eventdispatcher.h"
#include "framework/platform/platform.h"

#include <spdlog/logger.h>
#include <spdlog/sinks/basic_file_sink.h>
#include <spdlog/sinks/sink.h>
#include <spdlog/sinks/stdout_color_sinks.h>
#include <spdlog/spdlog.h>

#ifdef FRAMEWORK_GRAPHICS
#include <framework/platform/platformwindow.h>
#endif
Expand All @@ -38,11 +44,83 @@ Logger g_logger;
namespace
{
constexpr std::string_view s_logPrefixes[] = { "", "", "", "WARNING: ", "ERROR: ", "FATAL ERROR: " };
constexpr std::string_view s_spdConsolePattern = "[%Y-%m-%d %H:%M:%S.%e] [%^%l%$] %v";
constexpr std::string_view s_spdConsolePatternDebug = "[%Y-%m-%d %H:%M:%S.%e] [thread %t] [%^%l%$] %v";
constexpr std::string_view s_spdFilePattern = "[%Y-%m-%d %H:%M:%S.%e] [%l] %v";
constexpr std::string_view s_spdFilePatternDebug = "[%Y-%m-%d %H:%M:%S.%e] [thread %t] [%l] %v";
#if ENABLE_ENCRYPTION == 1
bool s_ignoreLogs = true;
#else
bool s_ignoreLogs = false;
#endif

std::string_view getConsolePattern()
{
#ifdef DEBUG_LOG
return s_spdConsolePatternDebug;
#else
return s_spdConsolePattern;
#endif
}

std::string_view getFilePattern()
{
#ifdef DEBUG_LOG
return s_spdFilePatternDebug;
#else
return s_spdFilePattern;
#endif
}

spdlog::level::level_enum toSpdLogLevel(const Fw::LogLevel level)
{
switch (level) {
case Fw::LogFine:
return spdlog::level::trace;
case Fw::LogDebug:
return spdlog::level::debug;
case Fw::LogInfo:
return spdlog::level::info;
case Fw::LogWarning:
return spdlog::level::warn;
case Fw::LogError:
return spdlog::level::err;
case Fw::LogFatal:
return spdlog::level::critical;
default:
return spdlog::level::info;
}
}

std::shared_ptr<spdlog::logger> createSpdLogger()
{
try {
auto sink = std::make_shared<spdlog::sinks::stdout_color_sink_mt>();
sink->set_color_mode(spdlog::color_mode::always);
sink->set_pattern(std::string{ getConsolePattern() });

auto logger = std::make_shared<spdlog::logger>("otclient", sink);
logger->set_level(spdlog::level::trace);
logger->flush_on(spdlog::level::warn);
spdlog::set_default_logger(logger);

return logger;
} catch (...) {
return nullptr;
}
}

std::shared_ptr<spdlog::logger>& getSpdLogger()
{
static std::shared_ptr<spdlog::logger> s_logger = createSpdLogger();
return s_logger;
}

std::shared_ptr<spdlog::sinks::sink>& getSpdLogFileSink()
{
static std::shared_ptr<spdlog::sinks::sink> s_fileSink;
return s_fileSink;
}
}

void Logger::log(Fw::LogLevel level, const std::string_view message)
Expand All @@ -65,14 +143,26 @@ void Logger::log(Fw::LogLevel level, const std::string_view message)
return;
}

std::string outmsg{ s_logPrefixes[level] };
std::string outmsg{ s_logPrefixes[static_cast<std::size_t>(level)] };
outmsg.append(message);

#ifdef ANDROID
__android_log_print(ANDROID_LOG_INFO, "OTClientMobile", "%s", outmsg.c_str());
#endif // ANDROID

std::cout << outmsg << std::endl;
auto& spdLogger = getSpdLogger();
if (spdLogger) {
spdLogger->log(toSpdLogLevel(level), "{}", message);
if (level >= Fw::LogError) {
spdLogger->flush();
}
} else {
auto fallbackLogger = spdlog::default_logger();
fallbackLogger->log(toSpdLogLevel(level), "{}", message);
if (level >= Fw::LogError) {
fallbackLogger->flush();
}
}

if (m_outFile.good()) {
m_outFile << outmsg << std::endl;
Expand Down Expand Up @@ -138,10 +228,31 @@ void Logger::fireOldMessages()

void Logger::setLogFile(const std::string_view file)
{
auto& spdLogger = getSpdLogger();
if (spdLogger) {
try {
auto fileSink = std::make_shared<spdlog::sinks::basic_file_sink_mt>(stdext::utf8_to_latin1(file), true);
fileSink->set_pattern(std::string{ getFilePattern() });

auto& currentLogFileSink = getSpdLogFileSink();
auto& sinks = spdLogger->sinks();
if (currentLogFileSink) {
std::erase(sinks, currentLogFileSink);
}

currentLogFileSink = fileSink;
sinks.push_back(currentLogFileSink);
spdLogger->flush();
return;
} catch (const spdlog::spdlog_ex& e) {
g_logger.error("Unable to save log to '{}' using spdlog: {}", file, e.what());
}
}

m_outFile.open(stdext::utf8_to_latin1(file), std::ios::out | std::ios::app);
if (!m_outFile.is_open() || !m_outFile.good()) {
g_logger.error("Unable to save log to '{}'", file);
return;
}
m_outFile.flush();
}
}
Loading