Compare commits

...

7 Commits

5 changed files with 108 additions and 19 deletions

3
.gitmodules vendored
View File

@@ -1,3 +1,6 @@
[submodule "fmt"] [submodule "fmt"]
path = fmt path = fmt
url = https://github.com/fmtlib/fmt url = https://github.com/fmtlib/fmt
[submodule "sentry"]
path = sentry
url = git@github.com:getsentry/sentry-native.git

View File

@@ -15,7 +15,38 @@ add_library(logvisor
lib/logvisor.cpp lib/logvisor.cpp
include/logvisor/logvisor.hpp) include/logvisor/logvisor.hpp)
target_link_libraries(logvisor PUBLIC fmt) if ("${SENTRY_DSN}" STREQUAL "")
message(STATUS "SENTRY_DSN not set, not enabling Sentry")
target_compile_definitions(logvisor PUBLIC SENTRY_ENABLED=0)
set(SENTRY_LIB "")
set(BREAKPAD_CLIENT "")
else ()
message(STATUS "Enabling Sentry integration")
add_subdirectory(sentry)
target_compile_definitions(logvisor PUBLIC SENTRY_ENABLED=1)
target_compile_definitions(logvisor PRIVATE SENTRY_DSN="${SENTRY_DSN}")
set(SENTRY_LIB sentry)
if (CMAKE_SYSTEM_NAME STREQUAL "Linux")
set(BREAKPAD_CLIENT breakpad_client)
target_compile_options(breakpad_client PRIVATE -Wno-implicit-fallthrough -Wno-array-bounds)
target_compile_options(sentry PRIVATE "-Wno-implicit-fallthrough")
set_property(TARGET breakpad_client PROPERTY CXX_STANDARD 17)
set_property(TARGET sentry PROPERTY CXX_STANDARD 17)
else ()
set(BREAKPAD_CLIENT "")
endif ()
if (MSVC)
target_compile_options(crashpad_client PRIVATE "/W0")
target_compile_options(crashpad_util PRIVATE "/W0")
target_compile_options(crashpad_snapshot PRIVATE "/W0")
target_compile_options(mini_chromium PRIVATE "/W0")
if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang")
target_compile_options(crashpad_zlib PRIVATE "-mpclmul")
endif ()
endif ()
endif ()
target_link_libraries(logvisor PUBLIC fmt ${SENTRY_LIB})
if(NX) if(NX)
target_link_libraries(logvisor PUBLIC debug nxd optimized nx) target_link_libraries(logvisor PUBLIC debug nxd optimized nx)
else() else()
@@ -33,7 +64,7 @@ set(config_install_dir "lib/cmake/logvisor")
# Associate target with export # Associate target with export
install( install(
TARGETS logvisor fmt TARGETS logvisor fmt ${SENTRY_LIB} ${BREAKPAD_CLIENT}
EXPORT logvisorTargets EXPORT logvisorTargets
ARCHIVE DESTINATION "lib" ARCHIVE DESTINATION "lib"
INCLUDES DESTINATION include # This sets the INTERFACE_INCLUDE_DIRECTORIES property of the target. INCLUDES DESTINATION include # This sets the INTERFACE_INCLUDE_DIRECTORIES property of the target.

View File

@@ -17,6 +17,7 @@
#endif #endif
extern "C" void logvisorBp(); extern "C" void logvisorBp();
#define log_typeid(type) std::hash<std::string>()(#type)
namespace logvisor { namespace logvisor {
@@ -43,6 +44,10 @@ enum Level {
* @brief Backend interface for receiving app-wide log events * @brief Backend interface for receiving app-wide log events
*/ */
struct ILogger { struct ILogger {
private:
uint64_t m_typeHash;
public:
ILogger(uint64_t typeHash) : m_typeHash(typeHash) {}
virtual ~ILogger() = default; virtual ~ILogger() = default;
virtual void report(const char* modName, Level severity, fmt::string_view format, fmt::format_args args) = 0; virtual void report(const char* modName, Level severity, fmt::string_view format, fmt::format_args args) = 0;
virtual void report(const char* modName, Level severity, fmt::wstring_view format, fmt::wformat_args args) = 0; virtual void report(const char* modName, Level severity, fmt::wstring_view format, fmt::wformat_args args) = 0;
@@ -50,6 +55,8 @@ struct ILogger {
fmt::string_view format, fmt::format_args args) = 0; fmt::string_view format, fmt::format_args args) = 0;
virtual void reportSource(const char* modName, Level severity, const char* file, unsigned linenum, virtual void reportSource(const char* modName, Level severity, const char* file, unsigned linenum,
fmt::wstring_view format, fmt::wformat_args args) = 0; fmt::wstring_view format, fmt::wformat_args args) = 0;
[[nodiscard]] uint64_t getTypeId() const { return m_typeHash; }
}; };
/** /**
@@ -146,6 +153,16 @@ void RegisterFileLogger(const char* filepath);
*/ */
void RegisterStandardExceptions(); void RegisterStandardExceptions();
#if SENTRY_ENABLED
/**
* @brief Register Sentry crash reporting & logging.
* @param appName The application name
* @param appVersion The application version
* @param cacheDir Directory for Sentry cache files
*/
void RegisterSentry(const char* appName, const char* appVersion, const char* cacheDir);
#endif
#if _WIN32 #if _WIN32
/** /**
* @brief Spawn an application-owned cmd.exe window for displaying console output * @brief Spawn an application-owned cmd.exe window for displaying console output

View File

@@ -34,6 +34,10 @@
#include <csignal> #include <csignal>
#include "logvisor/logvisor.hpp" #include "logvisor/logvisor.hpp"
#if SENTRY_ENABLED
#include <sentry.h>
#endif
/* ANSI sequences */ /* ANSI sequences */
#define RED "\x1b[1;31m" #define RED "\x1b[1;31m"
#define YELLOW "\x1b[1;33m" #define YELLOW "\x1b[1;33m"
@@ -536,7 +540,7 @@ static const char* Term = nullptr;
#endif #endif
bool XtermColor = false; bool XtermColor = false;
struct ConsoleLogger : public ILogger { struct ConsoleLogger : public ILogger {
ConsoleLogger() { ConsoleLogger() : ILogger(log_typeid(ConsoleLogger)) {
#if _WIN32 #if _WIN32
#if !WINDOWS_STORE #if !WINDOWS_STORE
const char* conemuANSI = getenv("ConEmuANSI"); const char* conemuANSI = getenv("ConEmuANSI");
@@ -555,6 +559,7 @@ struct ConsoleLogger : public ILogger {
} }
#endif #endif
} }
~ConsoleLogger() override = default;
static void _reportHead(const char* modName, const char* sourceInfo, Level severity) { static void _reportHead(const char* modName, const char* sourceInfo, Level severity) {
/* Clear current line out */ /* Clear current line out */
@@ -736,10 +741,43 @@ void RegisterStandardExceptions() {
signal(SIGFPE, AbortHandler); signal(SIGFPE, AbortHandler);
} }
#if SENTRY_ENABLED
void RegisterSentry(const char* appName, const char* appVersion, const char* cacheDir) {
sentry_options_t *options = sentry_options_new();
sentry_options_set_database_path(options, cacheDir);
sentry_options_set_auto_session_tracking(options, true);
sentry_options_set_symbolize_stacktraces(options, true);
sentry_options_set_dsn(options, SENTRY_DSN);
#ifdef NDEBUG
sentry_options_set_environment(options, "release");
#else
sentry_options_set_environment(options, "debug");
#endif
std::string release = fmt::format(FMT_STRING("{}@{}"), appName, appVersion);
sentry_options_set_release(options, release.c_str());
sentry_init(options);
}
#endif
struct FileLogger : public ILogger { struct FileLogger : public ILogger {
FILE* fp; FILE* fp = nullptr;
FileLogger(uint64_t typeHash) : ILogger(typeHash) {}
virtual void openFile() = 0; virtual void openFile() = 0;
virtual void closeFile() { std::fclose(fp); } void openFileIfNeeded() {
if (!fp) {
openFile();
}
}
virtual void closeFile() {
if (fp) {
std::fclose(fp);
fp = nullptr;
}
}
virtual ~FileLogger() { closeFile(); }
void _reportHead(const char* modName, const char* sourceInfo, Level severity) { void _reportHead(const char* modName, const char* sourceInfo, Level severity) {
const std::chrono::steady_clock::duration tm = CurrentUptime(); const std::chrono::steady_clock::duration tm = CurrentUptime();
@@ -784,44 +822,41 @@ struct FileLogger : public ILogger {
} }
void report(const char* modName, Level severity, fmt::string_view format, fmt::format_args args) override { void report(const char* modName, Level severity, fmt::string_view format, fmt::format_args args) override {
openFile(); openFileIfNeeded();
_reportHead(modName, nullptr, severity); _reportHead(modName, nullptr, severity);
fmt::vprint(fp, format, args); fmt::vprint(fp, format, args);
std::fputc('\n', fp); std::fputc('\n', fp);
closeFile();
} }
void report(const char* modName, Level severity, fmt::wstring_view format, fmt::wformat_args args) override { void report(const char* modName, Level severity, fmt::wstring_view format, fmt::wformat_args args) override {
openFile(); openFileIfNeeded();
_reportHead(modName, nullptr, severity); _reportHead(modName, nullptr, severity);
fmt::vprint(fp, format, args); fmt::vprint(fp, format, args);
std::fputc('\n', fp); std::fputc('\n', fp);
closeFile();
} }
void reportSource(const char* modName, Level severity, const char* file, unsigned linenum, fmt::string_view format, void reportSource(const char* modName, Level severity, const char* file, unsigned linenum, fmt::string_view format,
fmt::format_args args) override { fmt::format_args args) override {
openFile(); openFileIfNeeded();
_reportHead(modName, fmt::format(FMT_STRING("{}:{}"), file, linenum).c_str(), severity); _reportHead(modName, fmt::format(FMT_STRING("{}:{}"), file, linenum).c_str(), severity);
fmt::vprint(fp, format, args); fmt::vprint(fp, format, args);
std::fputc('\n', fp); std::fputc('\n', fp);
closeFile();
} }
void reportSource(const char* modName, Level severity, const char* file, unsigned linenum, fmt::wstring_view format, void reportSource(const char* modName, Level severity, const char* file, unsigned linenum, fmt::wstring_view format,
fmt::wformat_args args) override { fmt::wformat_args args) override {
openFile(); openFileIfNeeded();
_reportHead(modName, fmt::format(FMT_STRING("{}:{}"), file, linenum).c_str(), severity); _reportHead(modName, fmt::format(FMT_STRING("{}:{}"), file, linenum).c_str(), severity);
fmt::vprint(fp, format, args); fmt::vprint(fp, format, args);
std::fputc('\n', fp); std::fputc('\n', fp);
closeFile();
} }
}; };
struct FileLogger8 : public FileLogger { struct FileLogger8 : public FileLogger {
const char* m_filepath; const char* m_filepath;
FileLogger8(const char* filepath) : m_filepath(filepath) {} FileLogger8(const char* filepath) : FileLogger(log_typeid(FileLogger8)), m_filepath(filepath) {}
void openFile() override { fp = std::fopen(m_filepath, "a"); } void openFile() override { fp = std::fopen(m_filepath, "a"); }
~FileLogger8() override = default;
}; };
void RegisterFileLogger(const char* filepath) { void RegisterFileLogger(const char* filepath) {
@@ -833,17 +868,19 @@ void RegisterFileLogger(const char* filepath) {
struct FileLogger16 : public FileLogger { struct FileLogger16 : public FileLogger {
const wchar_t* m_filepath; const wchar_t* m_filepath;
FileLogger16(const wchar_t* filepath) : m_filepath(filepath) {} FileLogger16(const wchar_t* filepath) : FileLogger(log_typeid(FileLogger16)), m_filepath(filepath) {}
void openFile() override { fp = _wfopen(m_filepath, L"a"); } void openFile() override { fp = _wfopen(m_filepath, L"a"); }
~FileLogger16() override = default;
}; };
void RegisterFileLogger(const wchar_t* filepath) { void RegisterFileLogger(const wchar_t* filepath) {
/* Determine if file logger already added */ /* Determine if file logger already added */
for (auto& logger : MainLoggers) { for (const auto& logger : MainLoggers) {
FileLogger16* filelogger = dynamic_cast<FileLogger16*>(logger.get()); if (logger->getTypeId() == log_typeid(FileLogger16)) {
if (filelogger) { const auto* fl = static_cast<const FileLogger16*>(logger.get());
if (!wcscmp(filepath, filelogger->m_filepath)) if (!wcscmp(filepath, fl->m_filepath)) {
return; return;
}
} }
} }

1
sentry Submodule

Submodule sentry added at aee5dc1a55