Implement tier0 library logging bettererer
This commit is contained in:
parent
55eb398b1c
commit
c59dcfc614
|
@ -30,6 +30,7 @@ endfunction()
|
||||||
|
|
||||||
add_library(lcpu_native SHARED
|
add_library(lcpu_native SHARED
|
||||||
src/main.cpp
|
src/main.cpp
|
||||||
|
src/SourceSink.cpp
|
||||||
)
|
)
|
||||||
|
|
||||||
if(${CMAKE_SYSTEM_NAME} MATCHES "Linux")
|
if(${CMAKE_SYSTEM_NAME} MATCHES "Linux")
|
||||||
|
|
|
@ -0,0 +1,47 @@
|
||||||
|
#include "SourceSink.hpp"
|
||||||
|
|
||||||
|
#include <lucore/Library.hpp>
|
||||||
|
|
||||||
|
namespace tier0 {
|
||||||
|
// TODO: For now this'll leak..
|
||||||
|
lucore::Library* library = nullptr;
|
||||||
|
|
||||||
|
// TODO: Switch this to using the LoggingSystem. It is available on the x86-64 branch of
|
||||||
|
// gmod.
|
||||||
|
using Msg_t = void (*)(const char* format, ...);
|
||||||
|
Msg_t Msg = nullptr;
|
||||||
|
Msg_t Warning = nullptr;
|
||||||
|
} // namespace tier0
|
||||||
|
|
||||||
|
namespace lcpu {
|
||||||
|
|
||||||
|
SourceSink& SourceSink::The() {
|
||||||
|
static SourceSink sink;
|
||||||
|
return sink;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SourceSink::Init() {
|
||||||
|
// Modern 64-bit GMod has one tier0 library.
|
||||||
|
// I am not supporting non-x86-64 branch servers, so this is OK and I don't need to
|
||||||
|
// do any library scanning nonsense to pick the correct one.
|
||||||
|
//
|
||||||
|
// (note that the x86-64 branch also includes 32-bit binaries, rather
|
||||||
|
// weirdly. You can build the module for this too, but not the non-x86-64 branch
|
||||||
|
// 32-bit GMod, and it also shares having only one tier0 library.)
|
||||||
|
tier0::library = lucore::Library::Open("tier0");
|
||||||
|
tier0::Msg = tier0::library->Symbol<tier0::Msg_t>("Msg");
|
||||||
|
tier0::Warning = tier0::library->Symbol<tier0::Msg_t>("Warning");
|
||||||
|
}
|
||||||
|
|
||||||
|
void SourceSink::OutputMessage(const lucore::Logger::MessageData& data) {
|
||||||
|
auto formatted =
|
||||||
|
std::format("[LCPU Native/{}] [{}] {}\n", lucore::Logger::SeverityToString(data.severity),
|
||||||
|
data.time, std::vformat(data.format, data.args));
|
||||||
|
if(data.severity < lucore::Logger::MessageSeverity::Warning) {
|
||||||
|
tier0::Msg("%s", formatted.c_str());
|
||||||
|
} else {
|
||||||
|
tier0::Warning("%s", formatted.c_str());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace lcpu
|
|
@ -0,0 +1,15 @@
|
||||||
|
#include <lucore/Logger.hpp>
|
||||||
|
|
||||||
|
namespace lcpu {
|
||||||
|
|
||||||
|
/// A lucore logger sink which funnels to the Source engine's
|
||||||
|
/// Tier0 library's logging functionality.
|
||||||
|
struct SourceSink : public lucore::Logger::Sink {
|
||||||
|
static SourceSink& The();
|
||||||
|
|
||||||
|
static void Init();
|
||||||
|
|
||||||
|
void OutputMessage(const lucore::Logger::MessageData& data) override;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
|
@ -1,6 +1,17 @@
|
||||||
#include <GarrysMod/Lua/Interface.h>
|
#include <GarrysMod/Lua/Interface.h>
|
||||||
|
|
||||||
|
#include "SourceSink.hpp"
|
||||||
|
|
||||||
|
#include <lucore/Assert.hpp>
|
||||||
|
|
||||||
GMOD_MODULE_OPEN() {
|
GMOD_MODULE_OPEN() {
|
||||||
|
// Initalize the source logging sink and attach it to the lucore logger.
|
||||||
|
lcpu::SourceSink::Init();
|
||||||
|
lucore::Logger::The().AttachSink(lcpu::SourceSink::The());
|
||||||
|
|
||||||
|
lucore::LogInfo("Hello Source World :) {} {}", 123.456, "This should work");
|
||||||
|
lucore::LogWarning("test");
|
||||||
|
LUCORE_CHECK(false, "this should bring the process down");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -8,6 +8,9 @@ project(lucore
|
||||||
add_library(lucore
|
add_library(lucore
|
||||||
src/Assert.cpp
|
src/Assert.cpp
|
||||||
src/Logger.cpp
|
src/Logger.cpp
|
||||||
|
|
||||||
|
src/OsLibrary.cpp
|
||||||
|
src/Library.cpp
|
||||||
)
|
)
|
||||||
|
|
||||||
target_compile_features(lucore PUBLIC cxx_std_20)
|
target_compile_features(lucore PUBLIC cxx_std_20)
|
||||||
|
|
|
@ -5,27 +5,24 @@
|
||||||
#include <format>
|
#include <format>
|
||||||
|
|
||||||
namespace lucore {
|
namespace lucore {
|
||||||
|
[[noreturn]] void ExitMsg(const char* message);
|
||||||
// TODO: wrapper which uses source_location (we don't need no macros anymore!)
|
|
||||||
[[noreturn]] void ExitMsg(const char* fileName, int fileLine, const char* message);
|
|
||||||
|
|
||||||
} // namespace lucore
|
} // namespace lucore
|
||||||
|
|
||||||
#ifndef NDEBUG
|
#ifndef NDEBUG
|
||||||
#define LUCORE_ASSERT(expr, fmt, ...) \
|
#define LUCORE_ASSERT(expr, fmt, ...) \
|
||||||
if(!(expr)) [[unlikely]] { \
|
if(!(expr)) [[unlikely]] { \
|
||||||
auto msg = std::format("Assertion \"{}\" failed with message: {}", #expr, \
|
auto msg = std::format("Assertion \"{}\" @ {}:{} failed with message: {}", #expr, \
|
||||||
std::format(fmt, ##__VA_ARGS__)); \
|
__FILE__, __LINE__, std::format(fmt, ##__VA_ARGS__)); \
|
||||||
::lucore::ExitMsg(__FILE__, __LINE__, msg.c_str()); \
|
::lucore::ExitMsg(msg.c_str()); \
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
#define LUCORE_ASSERT(expr, format, ...)
|
#define LUCORE_ASSERT(expr, format, ...)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// CHECK() is always active, even in release builds
|
// CHECK() is always active, even in release builds
|
||||||
#define LUCORE_CHECK(expr, fmt, ...) \
|
#define LUCORE_CHECK(expr, fmt, ...) \
|
||||||
if(!(expr)) [[unlikely]] { \
|
if(!(expr)) [[unlikely]] { \
|
||||||
auto msg = std::format("Check \"{}\" failed with message: {}", #expr, \
|
auto msg = std::format("Check \"{}\" @ {}:{} failed with message: {}", #expr, __FILE__, \
|
||||||
std::format(fmt, ##__VA_ARGS__)); \
|
__LINE__, std::format(fmt, ##__VA_ARGS__)); \
|
||||||
::lucore::ExitMsg(__FILE__, __LINE__, msg.c_str()); \
|
::lucore::ExitMsg(msg.c_str()); \
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,27 @@
|
||||||
|
#include <string_view>
|
||||||
|
|
||||||
|
namespace lucore {
|
||||||
|
|
||||||
|
struct Library {
|
||||||
|
using Handle = void*;
|
||||||
|
|
||||||
|
/// Create a new library instance.
|
||||||
|
static Library* Open(std::string_view dllname);
|
||||||
|
|
||||||
|
/// Query if [dllname] is loaded in the process.
|
||||||
|
static bool Loaded(std::string_view dllname);
|
||||||
|
|
||||||
|
~Library();
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
T Symbol(std::string_view symbolName) {
|
||||||
|
return reinterpret_cast<T>(SymbolImpl(symbolName.data()));
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
void* SymbolImpl(const char* symbol);
|
||||||
|
constexpr explicit Library(Handle handle) : handle(handle) {}
|
||||||
|
Handle handle {};
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace lucore
|
|
@ -82,14 +82,36 @@ namespace lucore {
|
||||||
std::vector<Sink*> sinks;
|
std::vector<Sink*> sinks;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#if 0
|
||||||
/// A logger sink implementation that prints to standard output.
|
/// A logger sink implementation that prints to standard output.
|
||||||
struct StdoutSink : public Logger::Sink {
|
struct StdoutSink : public Logger::Sink {
|
||||||
static StdoutSink& The();
|
static StdoutSink& The();
|
||||||
|
|
||||||
virtual void OutputMessage(const Logger::MessageData& data) override;
|
virtual void OutputMessage(const Logger::MessageData& data) override;
|
||||||
};
|
};
|
||||||
|
#endif
|
||||||
|
|
||||||
/// Attach the stdout logger sink to the logger.
|
/// Attach the stdout logger sink to the logger.
|
||||||
void LoggerAttachStdout();
|
void LoggerAttachStdout();
|
||||||
|
|
||||||
|
template <class... Args>
|
||||||
|
void LogInfo(std::string_view format, Args... args) {
|
||||||
|
Logger::The().Info(format, std::forward<Args>(args)...);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class... Args>
|
||||||
|
void LogWarning(std::string_view format, Args... args) {
|
||||||
|
Logger::The().Warning(format, std::forward<Args>(args)...);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class... Args>
|
||||||
|
void LogError(std::string_view format, Args... args) {
|
||||||
|
Logger::The().Error(format, std::forward<Args>(args)...);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class... Args>
|
||||||
|
void LogFatal(std::string_view format, Args... args) {
|
||||||
|
Logger::The().Fatal(format, std::forward<Args>(args)...);
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace lucore
|
} // namespace lucore
|
||||||
|
|
|
@ -6,8 +6,8 @@
|
||||||
|
|
||||||
namespace lucore {
|
namespace lucore {
|
||||||
|
|
||||||
[[noreturn]] void ExitMsg(const char* fileName, int fileLine, const char* message) {
|
[[noreturn]] void ExitMsg(const char* message) {
|
||||||
Logger::The().Fatal(message);
|
LogFatal("{}", message);
|
||||||
std::quick_exit(0xAF);
|
std::quick_exit(0xAF);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,37 @@
|
||||||
|
#include <format>
|
||||||
|
#include <lucore/Library.hpp>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
#include "OsLibrary.hpp"
|
||||||
|
|
||||||
|
namespace lucore {
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
std::string FormatLibraryName(std::string_view dllName) {
|
||||||
|
#ifdef _WIN32
|
||||||
|
return std::format("{}.dll", dllName);
|
||||||
|
#else
|
||||||
|
return std::format("lib{}.so", dllName);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
Library* Library::Open(std::string_view dllname) {
|
||||||
|
return new Library(
|
||||||
|
static_cast<void*>(detail::OsOpenLibrary(FormatLibraryName(dllname).c_str())));
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Library::Loaded(std::string_view dllname) {
|
||||||
|
return detail::OsLibraryLoaded(FormatLibraryName(dllname).c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
Library::~Library() {
|
||||||
|
if(handle) {
|
||||||
|
detail::OsFreeLibrary(static_cast<detail::OsLibraryHandle>(handle));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void* Library::SymbolImpl(const char* symbolName) {
|
||||||
|
return detail::OsLibrarySymbol(static_cast<detail::OsLibraryHandle>(handle), symbolName);
|
||||||
|
}
|
||||||
|
} // namespace lucore
|
|
@ -31,7 +31,7 @@ namespace lucore {
|
||||||
for(auto sink : sinks)
|
for(auto sink : sinks)
|
||||||
sink->OutputMessage(data);
|
sink->OutputMessage(data);
|
||||||
}
|
}
|
||||||
|
#if 0
|
||||||
StdoutSink& StdoutSink::The() {
|
StdoutSink& StdoutSink::The() {
|
||||||
static StdoutSink sink;
|
static StdoutSink sink;
|
||||||
return sink;
|
return sink;
|
||||||
|
@ -69,5 +69,6 @@ namespace lucore {
|
||||||
void LoggerAttachStdout() {
|
void LoggerAttachStdout() {
|
||||||
Logger::The().AttachSink(StdoutSink::The());
|
Logger::The().AttachSink(StdoutSink::The());
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
} // namespace lucore
|
} // namespace lucore
|
||||||
|
|
|
@ -0,0 +1,9 @@
|
||||||
|
#include "OsLibrary.hpp"
|
||||||
|
|
||||||
|
#if defined(_WIN32)
|
||||||
|
#include "OsLibrary.win32.cpp"
|
||||||
|
#elif defined(__linux__)
|
||||||
|
#include "OsLibrary.linux.cpp"
|
||||||
|
#else
|
||||||
|
#error No OsLibrary implementation for this platform
|
||||||
|
#endif
|
|
@ -0,0 +1,21 @@
|
||||||
|
//! Operating-system independent utilities for opening
|
||||||
|
//! shared libraries. This is currently a detail-only
|
||||||
|
//! Lucore API, and its stability is NOT guaranteed.
|
||||||
|
|
||||||
|
namespace lucore::detail {
|
||||||
|
/// Opaque handle type for libraries.
|
||||||
|
using OsLibraryHandle = void*;
|
||||||
|
|
||||||
|
/// Open a library.
|
||||||
|
OsLibraryHandle OsOpenLibrary(const char* filename);
|
||||||
|
|
||||||
|
/// Query if the library with the given [filename] is loaded.
|
||||||
|
bool OsLibraryLoaded(const char* filename);
|
||||||
|
|
||||||
|
/// Get a pointer to the symbol of a library.
|
||||||
|
void* OsLibrarySymbol(OsLibraryHandle dll, const char* symbolName);
|
||||||
|
|
||||||
|
/// Free the library.
|
||||||
|
void OsFreeLibrary(OsLibraryHandle handle);
|
||||||
|
|
||||||
|
} // namespace lucore::detail
|
|
@ -0,0 +1,22 @@
|
||||||
|
#include <dlfcn.h>
|
||||||
|
|
||||||
|
namespace lucore::detail {
|
||||||
|
OsLibraryHandle OsOpenLibrary(const char* filename) {
|
||||||
|
return dlopen(filename, RTLD_LAZY);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool OsLibraryLoaded(const char* filename) {
|
||||||
|
return dlopen(filename, RTLD_NOLOAD | RTLD_LAZY) != nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void* OsLibrarySymbol(OsLibraryHandle dll, const char* symbolName) {
|
||||||
|
return dlsym(dll, symbolName);
|
||||||
|
}
|
||||||
|
|
||||||
|
void OsFreeLibrary(OsLibraryHandle handle) {
|
||||||
|
// The reference count on *Nix will be incremented by the launcher
|
||||||
|
// process itself, therefore we do not risk accidentally pulling the
|
||||||
|
// library out of the rug of the engine in either case.
|
||||||
|
dlclose(handle);
|
||||||
|
}
|
||||||
|
} // namespace lucore::detail
|
|
@ -0,0 +1,23 @@
|
||||||
|
#define _WIN32_LEAN_AND_MEAN
|
||||||
|
#include <windows.h>
|
||||||
|
|
||||||
|
namespace lucore::detail {
|
||||||
|
|
||||||
|
OsLibraryHandle OsOpenLibrary(const char* filename) {
|
||||||
|
return reinterpret_cast<OsLibraryHandle>(GetModuleHandleA(filename);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool OsLibraryLoaded(const char* filename) {
|
||||||
|
return GetModuleHandleA(filename) != nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void* OsLibrarySymbol(OsLibraryHandle dll, const char* symbolName) {
|
||||||
|
return GetProcAddressA(reinterpret_cast<HMODULE*>(dll), symbolName);
|
||||||
|
}
|
||||||
|
|
||||||
|
void OsFreeLibrary(OsLibraryHandle handle) {
|
||||||
|
// GetModuleHandle*() does not increment the reference count;
|
||||||
|
// therefore, we have nothing to do here on Windows.
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
Loading…
Reference in New Issue