diff --git a/CMakeLists.txt b/CMakeLists.txt
index edb6c4f9740ebf5f5958aaf16fd6b525f8bfea6c..498df5aac7578066f286834fe18671f9a7e3ecdf 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -90,11 +90,18 @@ target_compile_features(Vivy PRIVATE
 
 # More options and warnings
 target_compile_options(Vivy PRIVATE
-    -Wall -Wextra -Wshadow -pedantic
-    -Wcast-align -Wconversion -Wsign-conversion -Wunused-variable
-    -Wmisleading-indentation -Wnull-dereference -Wdouble-promotion
+    -Wall -Wextra -Wpedantic
+    -Wshadow
+    -Wcast-align
+    -Wconversion
+    -Wsign-conversion
+    -Wunused-variable
+    -Wmisleading-indentation
+    -Wnull-dereference
+    -Wdouble-promotion
     -Wformat=2
-    -Woverloaded-virtual -Wnon-virtual-dtor
+    -Woverloaded-virtual
+    -Wnon-virtual-dtor
     -Wignored-qualifiers
 
     -fopenmp
@@ -117,8 +124,11 @@ if (${CMAKE_CXX_COMPILER_ID} STREQUAL "Clang")
 
         # Disable some things because we want C++20 and don't control some Qt
         # generated files...
-        -Wno-c++98-compat -Wno-c++98-c++11-c++14-c++17-compat-pedantic
+        -Wno-c++98-compat
         -Wno-c++98-compat-pedantic
+        -Wno-c++98-c++11-c++14-c++17-compat-pedantic
+        -Wno-c++20-compat
+
         -Wno-extra-semi-stmt
         -Wno-redundant-parens
         -Wno-padded
diff --git a/src/Lib/Log.cc b/src/Lib/Log.cc
index d23cabcc6e1e92fcb0ed3a30b254034a91cf8b6c..f26e77b3b7a89aa6221d0abebccfd3ab5200d7ff 100644
--- a/src/Lib/Log.cc
+++ b/src/Lib/Log.cc
@@ -1,10 +1,34 @@
 #include "Log.hh"
 
+// Vivy::LogLevel utility implementation
+namespace Vivy
+{
+const std::string_view
+LogLevel::toStdStringView(const LogLevel::Level lvl) noexcept
+{
+    return LevelsStringViews[static_cast<Array::size_type>(lvl)];
+}
+}
+
 // Vivy::LogSinkDispatcher and child classes implementation
 namespace Vivy
 {
 LogSinkDispatcher::~LogSinkDispatcher() noexcept {}
 
+const std::string_view
+StderrLogSinkDispatcher::trunkFileName(const char *fileName) noexcept
+{
+    using size_type = std::string_view::size_type;
+
+    static constexpr char basePrefix[]       = "/src/";
+    static constexpr size_type basePrefixLen = (sizeof(basePrefix) / sizeof(char)) - 1;
+
+    const std::string_view fileNameView{ fileName };
+    const size_type basePath = fileNameView.rfind(basePrefix);
+    return std::string_view{ fileNameView.data() + basePath + basePrefixLen,
+                             fileNameView.data() + fileNameView.size() };
+}
+
 StderrLogSinkDispatcher::StderrLogSinkDispatcher() noexcept
     : LogSinkDispatcher(std::string_view{ "stderr" })
 {
@@ -14,7 +38,10 @@ void
 StderrLogSinkDispatcher::handleLogMessage(const std::string_view category,
                                           const LogMessage &msg) noexcept
 {
-    std::cerr << '[' << category << "] " << msg.getTextBuffer() << '\n';
+    std::cerr << "#(" << trunkFileName(msg.getHeader().fileName) << " +"
+              << msg.getHeader().lineNumberInFile << " | "
+              << LogLevel::toStdStringView(msg.getHeader().severity) << " -> " << category << ")\t"
+              << msg.getTextBuffer() << '\n';
 }
 }
 
@@ -59,6 +86,12 @@ LogSink::registerLogDispatcher(std::shared_ptr<LogSinkDispatcher> dispatcher) no
 {
     logDispatchers.push_back(dispatcher);
 }
+
+void
+LogSink::registerLogger(std::shared_ptr<Logger> ptr) noexcept
+{
+    loggers.push_back(ptr);
+}
 }
 
 // Vivy::Logger implementation
@@ -72,7 +105,7 @@ Logger::sendLogMessage(LogMessage &&msg) const noexcept
 
 LogMessage
 Logger::logEvent(const char *fileName, const char *functionName, const int lineNumber,
-                 const LogLevel logSeverity) noexcept
+                 const LogLevel::Level logSeverity) noexcept
 {
     return LogMessage(this, LogMessage::Header{ .fileName         = fileName,
                                                 .functionName     = functionName,
@@ -129,6 +162,17 @@ LogMessage::operator<<(const long i) noexcept
     return (*this << std::to_string(i));
 }
 
+LogMessage &
+LogMessage::operator<<(const std::string_view strv) noexcept
+{
+    for (std::size_t i = 0; (i < strv.size()) && (indexInArray < messageBufferLength - 1);
+         ++i, ++indexInArray) {
+        textBuffer[indexInArray] = strv[i];
+    }
+    textBuffer[indexInArray] = '\0';
+    return *this;
+}
+
 LogMessage &
 LogMessage::operator<<(const char *str) noexcept
 {
diff --git a/src/Lib/Log.hh b/src/Lib/Log.hh
index 5b49381f4c705f2572730d535abe130544468b48..042df469398b7940ee8524bcf23449d98b7fc1f1 100644
--- a/src/Lib/Log.hh
+++ b/src/Lib/Log.hh
@@ -3,10 +3,10 @@
 #include "Utils.hh"
 
 // Create a logger with a category
-#define VIVY_GET_LOGGER(sink, cat) std::make_shared<Logger>((sink).get(), std::string_view{ #cat })
+#define VIVY_GET_LOGGER(sink, cat) (sink)->newLogger(std::string_view{ #cat })
 
 // Log something in a logger
-#define VIVY_LOG_WITH_LEVEL(log, level) log->logEvent(__FILE__, __func__, __LINE__, level)
+#define VIVY_LOG_WITH_LEVEL(log, level) (log)->logEvent(__FILE__, __func__, __LINE__, level)
 #define VIVY_LOG_WARN(log)              VIVY_LOG_WITH_LEVEL(log, Vivy::LogLevel::Warning)
 #define VIVY_LOG_DEBUG(log)             VIVY_LOG_WITH_LEVEL(log, Vivy::LogLevel::Debug)
 #define VIVY_LOG_INFO(log)              VIVY_LOG_WITH_LEVEL(log, Vivy::LogLevel::Info)
@@ -17,15 +17,15 @@
 // intended to be used in an object to not polluate namespaces.
 #define VIVY_DCL_LOG_SINK(sink)                          \
     std::shared_ptr<LogSink> sink{ LogSink::newSink() }; \
-    void flushLogSink() const noexcept { sink->flush(); }
+    void flushLogSink() const noexcept { (sink)->flush(); }
 
 // Declare a dispatch for a sink with no arguments in the constructor.
 #define VIVY_DCL_LOG_DISPATCH(sink, name, dispatch) \
-    std::shared_ptr<dispatch> name{ sink->newDispatcher<dispatch>() };
+    std::shared_ptr<dispatch> name{ (sink)->newDispatcher<dispatch>() };
 
 // Declare a dispatch for a sink with arguments in the constructor.
 #define VIVY_DCL_LOG_DISPATCH_WITH(sink, name, dispatch, ...) \
-    std::shared_ptr<dispatch> name{ sink->newDispatcher<dispatch>(__VA_ARGS__) };
+    std::shared_ptr<dispatch> name{ (sink)->newDispatcher<dispatch>(__VA_ARGS__) };
 
 // Install logger for the object.
 #define VIVY_LOGGABLE_OBJECT(sink, name, logger)                             \
@@ -36,8 +36,10 @@
     LogMessage logInfo() const noexcept { return VIVY_LOG_INFO(logger); }    \
     LogMessage logDebug() const noexcept { return VIVY_LOG_DEBUG(logger); }
 
-#define VIVY_LOG_CTOR(classname) logDebug() << #classname "::CTOR "
-#define VIVY_LOG_DTOR(classname) logDebug() << #classname "::DTOR "
+#define VIVY_LOG_CTOR() logDebug() << "<<CTOR>> "
+#define VIVY_LOG_DTOR() logDebug() << "<<DTOR>> "
+
+#define VIVY_LOG_QUOTED(something) '\'' << (something) << '\''
 
 // Install logger, use the global LogSink
 #define VIVY_APP_LOGGABLE_OBJECT(name, logger) \
@@ -52,13 +54,25 @@ class LogMessage;
 
 // The severity of an event. Critical will cause the LogSink to flush all
 // messages to its emeters and then abort.
-enum class LogLevel : int {
-    Critical = std::numeric_limits<int>::max(), // Will trigger qFatal
-    Error    = 4,
-    Warning  = 3,
-    Info     = 2,
-    Debug    = 1,
-    None     = std::numeric_limits<int>::min() // In option setup to disable logs
+struct LogLevel final {
+    enum Level : int {
+        None, // In option setup to disable logs
+        Debug,
+        Info,
+        Warning,
+        Error,
+        Critical, // Will trigger qFatal
+        ___MaxAndUnused
+    };
+
+    static const std::string_view toStdStringView(const LogLevel::Level) noexcept;
+
+private:
+    using Array = std::array<const std::string_view, ___MaxAndUnused>;
+    static inline constexpr Array LevelsStringViews = { "None",   "Debug", "Info",
+                                                        "Warnin", "Error", "Critical" };
+
+    LogLevel() {}
 };
 
 // A LogSinkDispatcher will excavate LogMessages from the Sink and do something
@@ -85,6 +99,8 @@ public:
 class StderrLogSinkDispatcher : public LogSinkDispatcher {
     VIVY_UNMOVABLE_OBJECT(StderrLogSinkDispatcher)
 
+    static const std::string_view trunkFileName(const char *) noexcept;
+
 public:
     explicit StderrLogSinkDispatcher() noexcept;
     void handleLogMessage(const std::string_view, const LogMessage &) noexcept override;
@@ -103,6 +119,7 @@ public:
     ~LogSink() noexcept;
 
     void registerLogDispatcher(std::shared_ptr<LogSinkDispatcher>) noexcept;
+    void registerLogger(std::shared_ptr<Logger>) noexcept;
     void recieveLogMessage(const Logger *const, LogMessage &&) noexcept;
     void flush() noexcept;
 
@@ -115,10 +132,18 @@ public:
         return dispatch;
     }
 
+    std::shared_ptr<Logger> newLogger(const StringType auto &category) noexcept
+    {
+        std::shared_ptr<Logger> logger = std::make_shared<Logger>(this, category);
+        registerLogger(logger);
+        return logger;
+    }
+
 private:
     std::mutex messageQueueLock{};
     std::vector<std::tuple<const std::string_view, LogMessage>> messageQueue;
     std::vector<std::shared_ptr<LogSinkDispatcher>> logDispatchers;
+    std::vector<std::shared_ptr<Logger>> loggers;
 };
 
 // Message to be logged, constructed by a logger then send
@@ -130,7 +155,7 @@ public:
     struct Header final {
         const char *fileName;
         const char *functionName;
-        const LogLevel severity;
+        const LogLevel::Level severity;
         const int lineNumberInFile;
     };
 
@@ -159,6 +184,7 @@ public:
     LogMessage &&sink() noexcept;
 
     LogMessage &operator<<(const std::string &) noexcept;
+    LogMessage &operator<<(const std::string_view) noexcept;
     LogMessage &operator<<(const QString &) noexcept;
     LogMessage &operator<<(const char *) noexcept;
     LogMessage &operator<<(const char) noexcept;
@@ -187,6 +213,6 @@ public:
 
     void sendLogMessage(LogMessage &&) const noexcept;
     LogMessage logEvent(const char *fileName, const char *functionName, const int lineNumber,
-                        const LogLevel) noexcept;
+                        const LogLevel::Level) noexcept;
 };
 }