Compare commits

...

42 Commits

Author SHA1 Message Date
22e14d760a Use libbacktrace for Linux/macOS 2020-12-16 07:31:39 -05:00
81fb4e4c2d Link debug libnx & remove outdated nxstl includes 2020-10-21 00:35:07 -04:00
Jack Andersen
7f63cabaea Fixes for recent windows SDK changes 2020-08-22 17:28:34 -10:00
41432143fd Only use lm service when LOGVISOR_NX_LM set 2020-05-05 00:14:41 -04:00
Jack Andersen
14ea54f8b5 Add lm service for switch build 2020-05-03 20:09:21 -10:00
Jack Andersen
d62b4ce26e Update fmtlib 2020-04-11 12:44:21 -10:00
Jack Andersen
27814c5276 Exclude CMake CXX standard from MSVC 2020-04-10 18:55:45 -10:00
Jack Andersen
f04a9777eb Merge branch 'master' of ssh://git.axiodl.com:6431/AxioDL/logvisor 2019-09-30 21:21:21 -10:00
Jack Andersen
187c35f3c4 Ensure only one console logger is able to be registered 2019-09-30 21:20:45 -10:00
8c2e711362 Merge pull request #5 from lioncash/noreturn
logvisor: Mark logvisorAbort as [[noreturn]]
2019-09-06 23:26:44 -07:00
Lioncash
63cb911d09 logvisor: Mark logvisorAbort as [[noreturn]]
All variants of logvisorAbort do what they say in their name -- abort.
Given control isn't returned from this function, we can signify that
it's a noreturn function
2019-09-06 07:37:27 -04:00
f623ace3b4 Merge pull request #4 from lioncash/docs
logvisor: Amend documentation comments
2019-08-26 15:55:18 -07:00
8ea97c524c Merge pull request #3 from lioncash/forward
logvisor: std::forward arguments where applicable
2019-08-26 15:55:08 -07:00
81c72ad220 Merge pull request #2 from lioncash/char
logvisor: Use std::fputs/std::fputc where applicable
2019-08-26 15:54:58 -07:00
Lioncash
59f651f24b logvisor: Amend documentation comments
These use fmt-style formatting specifiers, not printf.
2019-08-26 10:57:19 -04:00
Lioncash
2a40c6dc92 logvisor: std::forward arguments where applicable
Forwards arguments into functions to preserve their value category
2019-08-26 10:50:35 -04:00
Lioncash
2f3f06e5ca logvisor: Add missing override specifiers 2019-08-26 10:34:40 -04:00
Lioncash
94d1c558a0 logvisor: Use std::fputs/std::fputc where applicable
We can just use std::fputc when inserting a single character instead of
using std::fputs. Likewise, we can use std::fputs over std::fprintf when
no formatting specifiers are present.
2019-08-26 10:31:45 -04:00
aa9aa0a82c Merge pull request #1 from lioncash/cexpr
logvisor: Make Module constructor constexpr
2019-08-17 22:56:59 -07:00
Lioncash
a57409828c logvisor: Make Module constructor constexpr
Allows the module instances to be constructed at compile time.
Otherwise, this is technically a runtime static constructor when an
instance is declared at file scope.
2019-08-17 19:47:20 -04:00
Jack Andersen
dcd0ffcaec Fix custom formatting of multiple character types 2019-07-25 16:31:54 -10:00
Jack Andersen
3bedd268e8 Integrate libfmt for format strings 2019-07-19 18:21:39 -10:00
Jack Andersen
a0ef17d895 Refactor of CMake for cleaner dependency handling 2019-06-11 15:53:17 -10:00
Jack Andersen
ebe7463e67 Ignore GCC truncation warning 2019-06-09 16:48:06 -10:00
Jack Andersen
7672485d81 Make logvisor publicly link libdl on platforms that have it 2019-05-25 00:14:41 -10:00
Jack Andersen
c54e2596c2 Add cmake package config files 2019-05-22 18:07:58 -10:00
Jack Andersen
c3f34aed0b Update include directory for proper installation 2019-05-22 17:58:40 -10:00
Jack Andersen
a2ffe70b4e Don't kill windows console on abort 2019-05-09 18:06:21 -10:00
Jack Andersen
3da29add5f Implicit switch fallthrough refactor 2019-02-17 19:45:51 -10:00
Jack Andersen
01e291833b New code style refactor 2018-12-07 19:17:15 -10:00
Jack Andersen
1b6c2ae715 Convert to pragma once 2018-10-06 17:35:33 -10:00
Jack Andersen
22ed01ffc5 Add nxstl 2018-10-06 16:56:33 -10:00
Jack Andersen
79506228ad Add nxstl mutex to logvisor 2018-09-29 12:59:14 -10:00
Jack Andersen
82f1df9c40 Use prctl on Linux to set thread name 2018-06-01 14:01:11 -10:00
Jack Andersen
2352699c65 Force console logger registration on Fatal 2018-05-26 16:17:12 -10:00
Jack Andersen
073cf1473b Minor printf fix 2018-05-24 20:32:04 -10:00
Jack Andersen
71bbb3d082 Don't print addr2line's stderr 2018-05-05 15:30:53 -10:00
Jack Andersen
2e595922be Add global log counter 2018-03-23 11:38:33 -10:00
Jack Andersen
bb0535f3a9 Use exit(1) instead of abort() for win32 release builds 2018-01-21 12:01:16 -10:00
Jack Andersen
b89d18c471 use exit(1) rather than abort() for release builds 2018-01-13 20:06:42 -10:00
Jack Andersen
f28fa0dbb2 Add KillProcessTree subroutine 2018-01-09 20:14:40 -10:00
Jack Andersen
beee8b3970 Use C++ standard library includes 2017-12-28 21:53:09 -10:00
6 changed files with 945 additions and 599 deletions

6
.gitmodules vendored Normal file
View File

@@ -0,0 +1,6 @@
[submodule "fmt"]
path = fmt
url = https://github.com/fmtlib/fmt
[submodule "libbacktrace"]
path = libbacktrace
url = https://github.com/status-im/libbacktrace.git

View File

@@ -1,8 +1,91 @@
include_directories(include) if(CMAKE_SOURCE_DIR STREQUAL CMAKE_CURRENT_SOURCE_DIR)
cmake_minimum_required(VERSION 3.10 FATAL_ERROR) # because of c++17
project(nod VERSION 0.1)
if (NOT MSVC)
set(CMAKE_CXX_STANDARD 20)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
endif()
endif()
include (CMakePackageConfigHelpers)
add_subdirectory(fmt)
add_library(logvisor add_library(logvisor
lib/logvisor.cpp lib/logvisor.cpp
include/logvisor/logvisor.hpp) include/logvisor/logvisor.hpp)
set(LOGVISOR_INCLUDE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/include CACHE PATH "logvisor include path" FORCE) if(APPLE OR UNIX)
include(ExternalProject)
find_package(Git REQUIRED)
find_program(MAKE_EXE NAMES gmake make)
ExternalProject_Add(
project_libbacktrace
PREFIX ${PROJECT_BINARY_DIR}/libbacktrace
GIT_REPOSITORY https://github.com/status-im/libbacktrace.git
GIT_TAG 2e878a38dd7144c84b665019b1085ea38ebe56d1
CONFIGURE_COMMAND ${PROJECT_BINARY_DIR}/libbacktrace/src/project_libbacktrace/configure --enable-host-shared --prefix=${PROJECT_BINARY_DIR}/libbacktrace/install --enable-shared=no --enable-static=yes
BUILD_COMMAND ${MAKE_EXE}
INSTALL_COMMAND ${MAKE_EXE} install
BUILD_IN_SOURCE 1
)
add_library(libbacktrace STATIC IMPORTED GLOBAL)
set_target_properties(libbacktrace PROPERTIES IMPORTED_LOCATION "${PROJECT_BINARY_DIR}/libbacktrace/install/lib/libbacktrace.a")
set_target_properties(libbacktrace PROPERTIES INTERFACE_INCLUDE_DIRECTORIES "${PROJECT_BINARY_DIR}/libbacktrace/install/include")
# Hack for INTERFACE_INCLUDE_DIRECTORIES propagation
# https://gitlab.kitware.com/cmake/cmake/-/issues/15052
file(MAKE_DIRECTORY "${PROJECT_BINARY_DIR}/libbacktrace/install/include")
add_dependencies(libbacktrace project_libbacktrace)
set(BACKTRACE_LIBS libbacktrace)
else()
set(BACKTRACE_LIBS "")
endif()
install(DIRECTORY include/logvisor DESTINATION include/logvisor) target_link_libraries(logvisor PUBLIC fmt)
if(NX)
target_link_libraries(logvisor PUBLIC debug nxd optimized nx)
else()
target_link_libraries(logvisor PRIVATE ${CMAKE_DL_LIBS} ${BACKTRACE_LIBS})
endif()
target_include_directories(logvisor PUBLIC $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>)
install(DIRECTORY include/logvisor DESTINATION include)
install(DIRECTORY fmt/include/fmt DESTINATION include)
set(version_config_file "${PROJECT_BINARY_DIR}/logvisorConfigVersion.cmake")
set(config_file "${PROJECT_BINARY_DIR}/logvisorConfig.cmake")
set(config_install_dir "lib/cmake/logvisor")
# Associate target with export
install(
TARGETS logvisor fmt
EXPORT logvisorTargets
ARCHIVE DESTINATION "lib"
INCLUDES DESTINATION include # This sets the INTERFACE_INCLUDE_DIRECTORIES property of the target.
)
# Install the target config files
install(
EXPORT logvisorTargets
NAMESPACE "logvisor::"
DESTINATION "${config_install_dir}"
)
# Generate version config file
write_basic_package_version_file(
"${version_config_file}"
COMPATIBILITY SameMajorVersion
)
# Generate config file
configure_package_config_file(
"Config.cmake.in"
"${config_file}"
INSTALL_DESTINATION "lib/cmake/logvisor"
)
# Install the config files
install(
FILES "${config_file}" "${version_config_file}"
DESTINATION ${config_install_dir}
)

4
Config.cmake.in Normal file
View File

@@ -0,0 +1,4 @@
@PACKAGE_INIT@
include("${CMAKE_CURRENT_LIST_DIR}/logvisorTargets.cmake")
check_required_components(logvisor)

1
fmt Submodule

Submodule fmt added at 9bdd1596ce

View File

@@ -1,21 +1,26 @@
#ifndef __LOG_VISOR_HPP__ #pragma once
#define __LOG_VISOR_HPP__
#include <stdarg.h> #include <cstring>
#include <string.h> #include <cstdio>
#include <stdio.h> #include <cstdlib>
#include <stdlib.h>
#include <vector> #include <vector>
#include <atomic> #include <atomic>
#include <memory> #include <memory>
#include <mutex> #include <mutex>
#define FMT_STRING_ALIAS 1
#define FMT_ENFORCE_COMPILE_STRING 1
#include <fmt/format.h>
#if defined(__SWITCH__) && !defined(LOGVISOR_NX_LM)
#define LOGVISOR_NX_LM 0
#endif
extern "C" void logvisorBp(); extern "C" void logvisorBp();
namespace logvisor namespace logvisor {
{
void logvisorAbort(); [[noreturn]] void logvisorAbort();
#if _WIN32 && UNICODE #if _WIN32 && UNICODE
#define LOG_UCS2 1 #define LOG_UCS2 1
@@ -27,32 +32,33 @@ extern bool XtermColor;
/** /**
* @brief Severity level for log messages * @brief Severity level for log messages
*/ */
enum Level enum Level {
{ Info, /**< Non-error informative message */
Info, /**< Non-error informative message */ Warning, /**< Non-error warning message */
Warning, /**< Non-error warning message */ Error, /**< Recoverable error message */
Error, /**< Recoverable error message */ Fatal /**< Non-recoverable error message (throws exception) */
Fatal /**< Non-recoverable error message (throws exception) */
}; };
/** /**
* @brief Backend interface for receiving app-wide log events * @brief Backend interface for receiving app-wide log events
*/ */
struct ILogger struct ILogger {
{ virtual ~ILogger() = default;
virtual ~ILogger() {} 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, virtual void report(const char* modName, Level severity, fmt::wstring_view format, fmt::wformat_args args) = 0;
const char* format, va_list ap)=0; virtual void reportSource(const char* modName, Level severity, const char* file, unsigned linenum,
virtual void report(const char* modName, Level severity, fmt::string_view format, fmt::format_args args) = 0;
const wchar_t* format, va_list ap)=0; virtual void reportSource(const char* modName, Level severity, const char* file, unsigned linenum,
virtual void reportSource(const char* modName, Level severity, fmt::wstring_view format, fmt::wformat_args args) = 0;
const char* file, unsigned linenum,
const char* format, va_list ap)=0;
virtual void reportSource(const char* modName, Level severity,
const char* file, unsigned linenum,
const wchar_t* format, va_list ap)=0;
}; };
/**
* @brief Terminate all child processes
*
* Implicitly called on abort condition.
*/
void KillProcessTree();
/** /**
* @brief Assign calling thread a descriptive name * @brief Assign calling thread a descriptive name
* @param name Descriptive thread name * @param name Descriptive thread name
@@ -87,18 +93,16 @@ extern std::atomic_uint_fast64_t FrameIndex;
* *
* Ensures logging streams aren't written concurrently * Ensures logging streams aren't written concurrently
*/ */
struct LogMutex struct LogMutex {
{ bool enabled = true;
bool enabled = true; std::recursive_mutex mutex;
std::recursive_mutex mutex; ~LogMutex() { enabled = false; }
~LogMutex() { enabled = false; } std::unique_lock<std::recursive_mutex> lock() {
std::unique_lock<std::recursive_mutex> lock() if (enabled)
{ return std::unique_lock<std::recursive_mutex>(mutex);
if (enabled) else
return std::unique_lock<std::recursive_mutex>(mutex); return std::unique_lock<std::recursive_mutex>();
else }
return std::unique_lock<std::recursive_mutex>();
}
}; };
extern LogMutex _LogMutex; extern LogMutex _LogMutex;
@@ -106,15 +110,20 @@ extern LogMutex _LogMutex;
* @brief Take a centralized lock for the logging output stream(s) * @brief Take a centralized lock for the logging output stream(s)
* @return RAII mutex lock * @return RAII mutex lock
*/ */
static inline std::unique_lock<std::recursive_mutex> LockLog() inline std::unique_lock<std::recursive_mutex> LockLog() { return _LogMutex.lock(); }
{
return _LogMutex.lock(); extern uint64_t _LogCounter;
}
/**
* @brief Get current count of logging events
* @return Log Count
*/
inline uint64_t GetLogCounter() { return _LogCounter; }
/** /**
* @brief Restore centralized logger vector to default state (silent operation) * @brief Restore centralized logger vector to default state (silent operation)
*/ */
static inline void UnregisterLoggers() {MainLoggers.clear();} inline void UnregisterLoggers() { MainLoggers.clear(); }
/** /**
* @brief Construct and register a real-time console logger singleton * @brief Construct and register a real-time console logger singleton
@@ -157,86 +166,141 @@ void RegisterFileLogger(const wchar_t* filepath);
#endif #endif
/** /**
* @brief This is constructed per-subsystem in a locally centralized fashon * @brief This is constructed per-subsystem in a locally centralized fashion
*/ */
class Module class Module {
{ const char* m_modName;
const char* m_modName;
template <typename Char>
void _vreport(Level severity, fmt::basic_string_view<Char> format,
fmt::basic_format_args<fmt::buffer_context<Char>> args) {
auto lk = LockLog();
++_LogCounter;
if (severity == Fatal)
RegisterConsoleLogger();
for (auto& logger : MainLoggers)
logger->report(m_modName, severity, format, args);
if (severity == Error || severity == Fatal)
logvisorBp();
if (severity == Fatal)
logvisorAbort();
else if (severity == Error)
++ErrorCount;
}
template <typename Char>
void _vreportSource(Level severity, const char* file, unsigned linenum, fmt::basic_string_view<Char> format,
fmt::basic_format_args<fmt::buffer_context<Char>> args) {
auto lk = LockLog();
++_LogCounter;
if (severity == Fatal)
RegisterConsoleLogger();
for (auto& logger : MainLoggers)
logger->reportSource(m_modName, severity, file, linenum, format, args);
if (severity == Error || severity == Fatal)
logvisorBp();
if (severity == Fatal)
logvisorAbort();
else if (severity == Error)
++ErrorCount;
}
public: public:
Module(const char* modName) : m_modName(modName) {} constexpr Module(const char* modName) : m_modName(modName) {}
/** /**
* @brief Route new log message to centralized ILogger * @brief Route new log message to centralized ILogger
* @param severity Level of log report severity * @param severity Level of log report severity
* @param format Standard printf-style format string * @param format fmt-style format string
*/ */
template <typename CharType> template <typename S, typename... Args, typename Char = fmt::char_t<S>>
inline void report(Level severity, const CharType* format, ...) void report(Level severity, const S& format, Args&&... args) {
{ if (MainLoggers.empty() && severity != Level::Fatal)
if (MainLoggers.empty() && severity != Level::Fatal) return;
return; _vreport(severity, fmt::to_string_view<Char>(format),
va_list ap; fmt::basic_format_args<fmt::buffer_context<Char>>(
va_start(ap, format); fmt::internal::make_args_checked<Args...>(format, std::forward<Args>(args)...)));
report(severity, format, ap); }
va_end(ap);
}
template <typename CharType> template <typename Char>
inline void report(Level severity, const CharType* format, va_list ap) void vreport(Level severity, fmt::basic_string_view<Char> format,
{ fmt::basic_format_args<fmt::buffer_context<Char>> args) {
auto lk = LockLog(); if (MainLoggers.empty() && severity != Level::Fatal)
for (auto& logger : MainLoggers) return;
{ _vreport(severity, format, args);
va_list apc; }
va_copy(apc, ap);
logger->report(m_modName, severity, format, apc);
va_end(apc);
}
if (severity == Error || severity == Fatal)
logvisorBp();
if (severity == Fatal)
logvisorAbort();
else if (severity == Error)
++ErrorCount;
}
/** /**
* @brief Route new log message with source info to centralized ILogger * @brief Route new log message with source info to centralized ILogger
* @param severity Level of log report severity * @param severity Level of log report severity
* @param file Source file name from __FILE__ macro * @param file Source file name from __FILE__ macro
* @param linenum Source line number from __LINE__ macro * @param linenum Source line number from __LINE__ macro
* @param format Standard printf-style format string * @param format fmt-style format string
*/ */
template <typename CharType> template <typename S, typename... Args, typename Char = fmt::char_t<S>>
inline void reportSource(Level severity, const char* file, unsigned linenum, const CharType* format, ...) void reportSource(Level severity, const char* file, unsigned linenum, const S& format, Args&&... args) {
{ if (MainLoggers.empty() && severity != Level::Fatal)
if (MainLoggers.empty() && severity != Level::Fatal) return;
return; _vreportSource(severity, file, linenum, fmt::to_string_view<Char>(format),
va_list ap; fmt::basic_format_args<fmt::buffer_context<Char>>(
va_start(ap, format); fmt::internal::make_args_checked<Args...>(format, std::forward<Args>(args)...)));
reportSource(severity, file, linenum, format, ap); }
va_end(ap);
}
template <typename CharType> template <typename Char>
inline void reportSource(Level severity, const char* file, unsigned linenum, const CharType* format, va_list ap) void vreportSource(Level severity, const char* file, unsigned linenum, fmt::basic_string_view<Char> format,
{ fmt::basic_format_args<fmt::buffer_context<Char>> args) {
auto lk = LockLog(); if (MainLoggers.empty() && severity != Level::Fatal)
for (auto& logger : MainLoggers) return;
{ _vreportSource(severity, file, linenum, format, args);
va_list apc; }
va_copy(apc, ap);
logger->reportSource(m_modName, severity, file, linenum, format, apc);
va_end(apc);
}
if (severity == Fatal)
logvisorAbort();
else if (severity == Error)
++ErrorCount;
}
}; };
#define FMT_CUSTOM_FORMATTER(tp, fmtstr, ...) \
namespace fmt { \
template <> \
struct formatter<tp, char> { \
template <typename ParseContext> \
constexpr auto parse(ParseContext &ctx) { return ctx.begin(); } \
template <typename FormatContext> \
auto format(const tp &obj, FormatContext &ctx) { \
return format_to(ctx.out(), FMT_STRING(fmtstr), __VA_ARGS__); \
} \
}; \
template <> \
struct formatter<tp, wchar_t> { \
template <typename ParseContext> \
constexpr auto parse(ParseContext &ctx) { return ctx.begin(); } \
template <typename FormatContext> \
auto format(const tp &obj, FormatContext &ctx) { \
return format_to(ctx.out(), FMT_STRING(L##fmtstr), __VA_ARGS__); \
} \
}; \
template <> \
struct formatter<tp, char16_t> { \
template <typename ParseContext> \
constexpr auto parse(ParseContext &ctx) { return ctx.begin(); } \
template <typename FormatContext> \
auto format(const tp &obj, FormatContext &ctx) { \
return format_to(ctx.out(), FMT_STRING(u##fmtstr), __VA_ARGS__); \
} \
}; \
template <> \
struct formatter<tp, char32_t> { \
template <typename ParseContext> \
constexpr auto parse(ParseContext &ctx) { return ctx.begin(); } \
template <typename FormatContext> \
auto format(const tp &obj, FormatContext &ctx) { \
return format_to(ctx.out(), FMT_STRING(U##fmtstr), __VA_ARGS__); \
} \
}; \
} }
#endif // __LOG_VISOR_HPP__ } // namespace logvisor
template <typename S, typename... Args, typename Char = fmt::char_t<S>>
void quicklog(const S& format, Args&&... args) {
logvisor::MainLoggers[0]->report(
"quick", logvisor::Info, fmt::to_string_view<Char>(format),
fmt::basic_format_args<fmt::buffer_context<Char>>(
fmt::internal::make_args_checked<Args...>(format, std::forward<Args>(args)...)));
}

File diff suppressed because it is too large Load Diff