mirror of
https://github.com/AxioDL/logvisor.git
synced 2025-12-08 21:17:44 +00:00
Compare commits
42 Commits
408ae926d7
...
libbacktra
| Author | SHA1 | Date | |
|---|---|---|---|
| 22e14d760a | |||
| 81fb4e4c2d | |||
|
|
7f63cabaea | ||
| 41432143fd | |||
|
|
14ea54f8b5 | ||
|
|
d62b4ce26e | ||
|
|
27814c5276 | ||
|
|
f04a9777eb | ||
|
|
187c35f3c4 | ||
| 8c2e711362 | |||
|
|
63cb911d09 | ||
| f623ace3b4 | |||
| 8ea97c524c | |||
| 81c72ad220 | |||
|
|
59f651f24b | ||
|
|
2a40c6dc92 | ||
|
|
2f3f06e5ca | ||
|
|
94d1c558a0 | ||
| aa9aa0a82c | |||
|
|
a57409828c | ||
|
|
dcd0ffcaec | ||
|
|
3bedd268e8 | ||
|
|
a0ef17d895 | ||
|
|
ebe7463e67 | ||
|
|
7672485d81 | ||
|
|
c54e2596c2 | ||
|
|
c3f34aed0b | ||
|
|
a2ffe70b4e | ||
|
|
3da29add5f | ||
|
|
01e291833b | ||
|
|
1b6c2ae715 | ||
|
|
22ed01ffc5 | ||
|
|
79506228ad | ||
|
|
82f1df9c40 | ||
|
|
2352699c65 | ||
|
|
073cf1473b | ||
|
|
71bbb3d082 | ||
|
|
2e595922be | ||
|
|
bb0535f3a9 | ||
|
|
b89d18c471 | ||
|
|
f28fa0dbb2 | ||
|
|
beee8b3970 |
6
.gitmodules
vendored
Normal file
6
.gitmodules
vendored
Normal 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
|
||||||
@@ -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
4
Config.cmake.in
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
@PACKAGE_INIT@
|
||||||
|
|
||||||
|
include("${CMAKE_CURRENT_LIST_DIR}/logvisorTargets.cmake")
|
||||||
|
check_required_components(logvisor)
|
||||||
1
fmt
Submodule
1
fmt
Submodule
Submodule fmt added at 9bdd1596ce
@@ -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)...)));
|
||||||
|
}
|
||||||
|
|||||||
1144
lib/logvisor.cpp
1144
lib/logvisor.cpp
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user