From f3ba19b162a89b2081c0598b4a0bf126146e3671 Mon Sep 17 00:00:00 2001 From: Steven Le Rouzic Date: Thu, 4 Apr 2024 22:05:06 +0200 Subject: Add logging system --- deimos/core/BUILD | 5 ++- deimos/core/api_registry.cpp | 2 ++ deimos/core/base.h | 10 +++++- deimos/core/format.h | 5 +++ deimos/core/hash.h | 2 -- deimos/core/io.cpp | 18 ++++++++++ deimos/core/io.h | 20 +++++++++++ deimos/core/log.cpp | 82 ++++++++++++++++++++++++++++++++++++++++++++ deimos/core/log.h | 71 ++++++++++++++++++++++++++++++++++++++ main/main.cpp | 10 +++--- 10 files changed, 216 insertions(+), 9 deletions(-) create mode 100644 deimos/core/io.cpp create mode 100644 deimos/core/log.cpp create mode 100644 deimos/core/log.h diff --git a/deimos/core/BUILD b/deimos/core/BUILD index fcedb22..08f1ada 100644 --- a/deimos/core/BUILD +++ b/deimos/core/BUILD @@ -8,6 +8,7 @@ cc_library( "hash.h", "id_name.h", "io.h", + "log.h", "os.h", "std.h", "format.h", @@ -15,8 +16,10 @@ cc_library( srcs = [ "allocator.cpp", "api_registry.cpp", - "os_win32.cpp", "format.cpp", + "io.cpp", + "log.cpp", + "os_win32.cpp", ], visibility = ["//:__subpackages__"], ) diff --git a/deimos/core/api_registry.cpp b/deimos/core/api_registry.cpp index 1489484..24ea201 100644 --- a/deimos/core/api_registry.cpp +++ b/deimos/core/api_registry.cpp @@ -8,6 +8,7 @@ namespace deimos AllocatorApi* BootstrapAllocatorApi(); void RegisterOsApi(ApiRegistry*); +void RegisterLogApi(ApiRegistry*); struct ApiEntry { @@ -56,6 +57,7 @@ ApiRegistry* InitializeGlobalApiRegistry() api_registry->Set(g_allocator_api); RegisterOsApi(api_registry); + RegisterLogApi(api_registry); return api_registry; } diff --git a/deimos/core/base.h b/deimos/core/base.h index 21cad3d..4bcb7c7 100644 --- a/deimos/core/base.h +++ b/deimos/core/base.h @@ -53,6 +53,14 @@ struct SourceLocation {} }; +template T Min(T a, T b) { return (a < b) ? a : b; } +template T Max(T a, T b) { return (a > b) ? a : b; } + +constexpr void MemoryCopy(void* dst, const void* src, int64_t size) +{ + __builtin_memcpy(dst, src, (size_t)size); +} + template class Span { @@ -79,7 +87,7 @@ public: template requires std::convertible_to - constexpr Span(const Span& other) : // NOLINT + constexpr Span(const Span& other) : // NOLINT(*-explicit-conversions) m_begin{other.begin()}, m_size{other.size()} {} diff --git a/deimos/core/format.h b/deimos/core/format.h index 98d9001..be2e4bf 100644 --- a/deimos/core/format.h +++ b/deimos/core/format.h @@ -37,6 +37,11 @@ struct FormatArg unsigned_integer{value} {} + explicit FormatArg(Span value) : + type{kString}, + string{value} + {} + explicit FormatArg(gsl::czstring value) : type{kString}, string{value, (int64_t)__builtin_strlen(value)} diff --git a/deimos/core/hash.h b/deimos/core/hash.h index f0eeafd..3198541 100644 --- a/deimos/core/hash.h +++ b/deimos/core/hash.h @@ -43,8 +43,6 @@ constexpr uint64_t MurmurHash3_Fmix64(uint64_t k) constexpr uint128_t MurmurHash3_x64_128(const char* key, uint64_t len) { - if consteval { return { 12, 12 }; } - // NOLINTBEGIN const uint64_t nblocks = len / 16; diff --git a/deimos/core/io.cpp b/deimos/core/io.cpp new file mode 100644 index 0000000..7764ee2 --- /dev/null +++ b/deimos/core/io.cpp @@ -0,0 +1,18 @@ +#include "deimos/core/io.h" + +namespace deimos +{ + +void BufferWriter::Write(Span to_write) +{ + Expects(m_written <= m_size); + + int64_t n_to_write = Min(to_write.size(), m_size - m_written); + MemoryCopy(m_buffer + m_written, to_write.data(), n_to_write); // NOLINT + m_written += n_to_write; + + Ensures(m_written <= m_size); +} + +} // namespace deimos + diff --git a/deimos/core/io.h b/deimos/core/io.h index 90caadc..12de30e 100644 --- a/deimos/core/io.h +++ b/deimos/core/io.h @@ -17,5 +17,25 @@ public: virtual void Write(Span) = 0; }; +class BufferWriter : public IWriter +{ + std::byte* m_buffer; + int64_t m_size; + int64_t m_written = 0; + +public: + explicit BufferWriter(Span buffer) : + m_buffer{buffer.begin()}, + m_size{buffer.size()} + {} + + void Write(Span) override; + + constexpr Span GetWritten() const + { + return { m_buffer, m_written }; + } +}; + } // namespace deimos diff --git a/deimos/core/log.cpp b/deimos/core/log.cpp new file mode 100644 index 0000000..befe4b7 --- /dev/null +++ b/deimos/core/log.cpp @@ -0,0 +1,82 @@ +#include "deimos/core/log.h" +#include "deimos/core/api_registry.h" +#include "deimos/core/allocator.h" +#include "deimos/core/os.h" + +namespace deimos +{ + +class DefaultLogger : public ILogger +{ + OsConsoleWriter m_writer; + + static const char* SeverityToStr(LogSeverity s) + { + switch (s) + { + case LogSeverity::kInfo: return "INFO "; + case LogSeverity::kDebug: return "DEBUG"; + case LogSeverity::kError: return "ERROR"; + } + } + + static const char* SeverityToColor(LogSeverity s) + { + switch (s) + { + case LogSeverity::kInfo: return ""; + case LogSeverity::kDebug: return "\033[2m"; + case LogSeverity::kError: return "\033[91m"; + } + } + +public: + explicit DefaultLogger(OsConsoleApi* os_console_api) : + m_writer(os_console_api, OsConsoleType::kStdOut) + {} + + // @Todo Use string views + void Log(LogSeverity severity, const SourceLocation& location, Span msg) override + { + Format(&m_writer, "$[ $ ] $:$: $\033[0m\n", SeverityToColor(severity), + SeverityToStr(severity), location.file, location.line, msg); + } +}; + +class LogApiImpl : public LogApi +{ + ILogger* m_default_logger; + +public: + explicit LogApiImpl(ILogger* default_logger) : + m_default_logger{default_logger} + {} + + void LogVa( + LogSeverity severity, + const SourceLocation& location, + gsl::czstring msg, + Span args) override + { + std::byte buffer[1024]; + BufferWriter message_writer({&buffer[0], 1024}); + FormatVa(&message_writer, msg, args); + + auto written = message_writer.GetWritten(); + m_default_logger->Log(severity, location, {(const char*)written.data(), written.size()}); + } +}; + +void RegisterLogApi(ApiRegistry* api_registry) +{ + auto* allocator = api_registry->Get()->system; + auto* os_console_api = api_registry->Get()->console; + + auto* default_logger = allocator->New(os_console_api); + auto* log_api = allocator->New(default_logger); + + api_registry->Set(log_api); +} + +} // namespace deimos + diff --git a/deimos/core/log.h b/deimos/core/log.h new file mode 100644 index 0000000..cf92391 --- /dev/null +++ b/deimos/core/log.h @@ -0,0 +1,71 @@ +#pragma once + +#include "deimos/core/base.h" +#include "deimos/core/id_name.h" +#include "deimos/core/format.h" + +namespace deimos +{ + +enum class LogSeverity +{ + kInfo, + kDebug, + kError, +}; + +class ILogger +{ +public: + ILogger() = default; + deimos_NO_COPY_MOVE(ILogger); + virtual ~ILogger() = default; + + // @Todo Use string view + virtual void Log(LogSeverity, const SourceLocation&, Span) = 0; +}; + +// Just a helper to pass a SourceLocation without having to write {} to logging functions. +struct LogSourceLocation +{ + gsl::czstring fmt; + SourceLocation source_location; + + // NOLINTNEXTLINE(*-explicit-conversions) + LogSourceLocation(gsl::czstring fmt_, const SourceLocation& source_location_ = {}) : + fmt{fmt_}, source_location{source_location_} + {} +}; + +class LogApi +{ +public: + static constexpr IdName kApiName{"deimos::LogApi"}; + + LogApi() = default; + deimos_NO_COPY_MOVE(LogApi); + virtual ~LogApi() = default; + + virtual void LogVa(LogSeverity, const SourceLocation&, gsl::czstring msg, Span) = 0; + + template + void LogInfo(const LogSourceLocation& fmt_source_location, Args&&... args) + { + LogVa(LogSeverity::kInfo, fmt_source_location.source_location, fmt_source_location.fmt, { FormatArg(std::forward(args))... }); + } + + template + void LogDebug(const LogSourceLocation& fmt_source_location, Args&&... args) + { + LogVa(LogSeverity::kDebug, fmt_source_location.source_location, fmt_source_location.fmt, { FormatArg(std::forward(args))... }); + } + + template + void LogError(const LogSourceLocation& fmt_source_location, Args&&... args) + { + LogVa(LogSeverity::kError, fmt_source_location.source_location, fmt_source_location.fmt, { FormatArg(std::forward(args))... }); + } +}; + +} // namespace deimos + diff --git a/main/main.cpp b/main/main.cpp index 10a7dc4..03c2097 100644 --- a/main/main.cpp +++ b/main/main.cpp @@ -1,16 +1,16 @@ #include -#include -#include +#include using namespace deimos; int main(int /* argc */, char* /* argv */[]) { auto* api_registry = InitializeGlobalApiRegistry(); - auto* os_api = api_registry->Get(); + auto* log_api = api_registry->Get(); - OsConsoleWriter writer(os_api->console, OsConsoleType::kStdOut); - Format(&writer, "Hello, $!", "world"); + log_api->LogInfo("Hello, world!"); + log_api->LogDebug("Hello, $!", "world"); + log_api->LogError("This is an error OMG $ $ $", 1, 2, 3); return 0; } -- cgit