Repository: bitcoin/bitcoin
File: src/logging.h (C/C++)

Code before:
extern const char * const DEFAULT_DEBUGLOGFILE;

extern bool fLogIPs;

struct SourceLocationEqual {
    bool operator()(const std::source_location& lhs, const std::source_location& rhs) const noexcept
    {
        return lhs.line() == rhs.line() && std::string_view(lhs.file_name()) == std::string_view(rhs.file_name());
    }
};

struct SourceLocationHasher {
    size_t operator()(const std::source_location& s) const noexcept
    {
        // Use CSipHasher(0, 0) as a simple way to get uniform distribution.
        return size_t(CSipHasher(0, 0)
                      .Write(s.line())
                      .Write(MakeUCharSpan(std::string_view{s.file_name()}))
                      .Finalize());
    }
};

struct LogCategory {
    std::string category;
    bool active;
};

namespace BCLog {
    using CategoryMask = uint64_t;
    enum LogFlags : CategoryMask {
        NONE        = CategoryMask{0},
        NET         = (CategoryMask{1} <<  0),
        TOR         = (CategoryMask{1} <<  1),
        MEMPOOL     = (CategoryMask{1} <<  2),
        HTTP        = (CategoryMask{1} <<  3),
        BENCH       = (CategoryMask{1} <<  4),
        ZMQ         = (CategoryMask{1} <<  5),
        WALLETDB    = (CategoryMask{1} <<  6),
        RPC         = (CategoryMask{1} <<  7),
        ESTIMATEFEE = (CategoryMask{1} <<  8),
        ADDRMAN     = (CategoryMask{1} <<  9),
        SELECTCOINS = (CategoryMask{1} << 10),
        REINDEX     = (CategoryMask{1} << 11),
        CMPCTBLOCK  = (CategoryMask{1} << 12),
        RAND        = (CategoryMask{1} << 13),
        PRUNE       = (CategoryMask{1} << 14),
        PROXY       = (CategoryMask{1} << 15),
        MEMPOOLREJ  = (CategoryMask{1} << 16),
        LIBEVENT    = (CategoryMask{1} << 17),
        COINDB      = (CategoryMask{1} << 18),
        QT          = (CategoryMask{1} << 19),

Review comment (performance):
I'm not sure we should replace all `std::source_location` usage. There is value in uniformity, but I think it's also good to keep places that don't require the shorter function name to stick with stdlib? This is fairly trivial to achieve with e.g.:

<details>
<summary>git diff on fa41dd987e</summary>

```diff
diff --git a/src/logging.cpp b/src/logging.cpp
index b5baac0721..b321991930 100644
--- a/src/logging.cpp
+++ b/src/logging.cpp
@@ -388,7 +388,7 @@ std::shared_ptr<BCLog::LogRateLimiter> BCLog::LogRateLimiter::Create(
 }
 
 BCLog::LogRateLimiter::Status BCLog::LogRateLimiter::Consume(
-    const SourceLocation& source_loc,
+    const std::source_location& source_loc,
     const std::string& str)
 {
     StdLockGuard scoped_lock(m_mutex);
diff --git a/src/logging.h b/src/logging.h
index 8c276d4606..f0eb23c48e 100644
--- a/src/logging.h
+++ b/src/logging.h
@@ -51,6 +51,7 @@ public:
     std::string_view file_name() const { return m_loc.file_name(); }
     std::uint_least32_t line() const { return m_loc.line(); }
     std::string_view function_name() const { return m_func; }
+    operator const std::source_location&(){ return m_loc; };
 
 private:
     std::string_view m_func;
@@ -58,14 +59,14 @@ private:
 };
 
 struct SourceLocationEqual {
-    bool operator()(const SourceLocation& lhs, const SourceLocation& rhs) const noexcept
+    bool operator()(const std::source_location& lhs, const std::source_location& rhs) const noexcept
     {
         return lhs.line() == rhs.line() && std::string_view(lhs.file_name()) == std::string_view(rhs.file_name());
     }
 };
 
 struct SourceLocationHasher {
-    size_t operator()(const SourceLocation& s) const noexcept
+    size_t operator()(const std::source_location& s) const noexcept
     {
         // Use CSipHasher(0, 0) as a simple way to get uniform distribution.
         return size_t(CSipHasher(0, 0)
@@ -151,7 +152,7 @@ namespace BCLog {
         mutable StdMutex m_mutex;
 
         //! Stats for each source location that has attempted to log something.
-        std::unordered_map<SourceLocation, Stats, SourceLocationHasher, SourceLocationEqual> m_source_locations GUARDED_BY(m_mutex);
+        std::unordered_map<std::source_location, Stats, SourceLocationHasher, SourceLocationEqual> m_source_locations GUARDED_BY(m_mutex);
         //! Whether any log locations are suppressed. Cached view on m_source_locations for performance reasons.
         std::atomic<bool> m_suppression_active{false};
         LogRateLimiter(uint64_t max_bytes, std::chrono::seconds reset_window);
@@ -183,7 +184,7 @@ namespace BCLog {
         //! Consumes `source_loc`'s available bytes corresponding to the size of the (formatted)
         //! `str` and returns its status.
         [[nodiscard]] Status Consume(
-            const SourceLocation& source_loc,
+            const std::source_location& source_loc,
             const std::string& str) EXCLUSIVE_LOCKS_REQUIRED(!m_mutex);
         //! Resets all usage to zero. Called periodically by the scheduler.
         void Reset() EXCLUSIVE_LOCKS_REQUIRED(!m_mutex);

```
</details>

With that diff (and perhaps without it too), it's probably better to expose the abbreviated name under a different name, e.g. `SourceLocation::function_name_short()`?

Code after:
extern const char * const DEFAULT_DEBUGLOGFILE;

extern bool fLogIPs;

/// Like std::source_location, but allowing to override the function name.
class SourceLocation
{
public:
    /// The func argument must be constructed from the C++11 __func__ macro.
    /// Ref: https://en.cppreference.com/w/cpp/language/function.html#func
    /// Non-static string literals are not supported.
    SourceLocation(const char* func,
                   std::source_location loc = std::source_location::current())
        : m_func{func}, m_loc{loc} {}

    std::string_view file_name() const { return m_loc.file_name(); }
    std::uint_least32_t line() const { return m_loc.line(); }
    std::string_view function_name_short() const { return m_func; }

private:
    std::string_view m_func;
    std::source_location m_loc;
};

struct SourceLocationEqual {
    bool operator()(const SourceLocation& lhs, const SourceLocation& rhs) const noexcept
    {
        return lhs.line() == rhs.line() && std::string_view(lhs.file_name()) == std::string_view(rhs.file_name());
    }
};

struct SourceLocationHasher {
    size_t operator()(const SourceLocation& s) const noexcept
    {
        // Use CSipHasher(0, 0) as a simple way to get uniform distribution.
        return size_t(CSipHasher(0, 0)
                      .Write(s.line())
                      .Write(MakeUCharSpan(std::string_view{s.file_name()}))
                      .Finalize());
    }
};

struct LogCategory {
    std::string category;
    bool active;
};

namespace BCLog {
    using CategoryMask = uint64_t;
    enum LogFlags : CategoryMask {
        NONE        = CategoryMask{0},