[Libreoffice-commits] online.git: common/Log.cpp common/Log.hpp

Ashod Nakashian (via logerrit) logerrit at kemper.freedesktop.org
Thu May 21 22:40:59 UTC 2020


 common/Log.cpp |  155 +++++++++++++++++++++++++++++++++++++++++++++++++--------
 common/Log.hpp |   20 ++++---
 2 files changed, 148 insertions(+), 27 deletions(-)

New commits:
commit 287b70a50408d260f3c6c0d5306c081a40eea280
Author:     Ashod Nakashian <ashod.nakashian at collabora.co.uk>
AuthorDate: Sat Apr 25 13:03:32 2020 -0400
Commit:     Ashod Nakashian <ashnakash at gmail.com>
CommitDate: Fri May 22 00:40:37 2020 +0200

    wsd: logging cleanup and improvements
    
    We now don't need to call snprintf (which is best
    for signal-safetly), and are much faster thanks
    to a custom replacement.
    
    Change-Id: Iae5861e42e8e335967499f93b71b39b0b4b09bf6
    Reviewed-on: https://gerrit.libreoffice.org/c/online/+/94146
    Tested-by: Jenkins CollaboraOffice <jenkinscollaboraoffice at gmail.com>
    Tested-by: Jenkins
    Reviewed-by: Ashod Nakashian <ashnakash at gmail.com>

diff --git a/common/Log.cpp b/common/Log.cpp
index f9d0b5578..6cb376c9e 100644
--- a/common/Log.cpp
+++ b/common/Log.cpp
@@ -70,7 +70,7 @@ namespace Log
         const std::string& getName() const { return _name; }
 
         void setLogger(Poco::Logger* logger) { _logger = logger; };
-        Poco::Logger* getLogger() { return _logger; }
+        Poco::Logger* getLogger() const { return _logger; }
     };
     static StaticNameHelper Source;
     bool IsShutdown = false;
@@ -112,38 +112,153 @@ namespace Log
         signalLog(buf + i + 1);
     }
 
-    char* prefix(char* buffer, const std::size_t len, const char* level)
+    /// Convert an unsigned number to ascii with 0 padding.
+    template <int Width> void to_ascii_fixed(char* buf, size_t num)
     {
-        const char *threadName = Util::getThreadName();
-        Poco::DateTime time;
+        buf[Width - 1] = '0' + num % 10; // Units.
+
+        if (Width > 1)
+        {
+            num /= 10;
+            buf[Width - 2] = '0' + num % 10; // Tens.
+        }
+
+        if (Width > 2)
+        {
+            num /= 10;
+            buf[Width - 3] = '0' + num % 10; // Hundreds.
+        }
+
+        if (Width > 3)
+        {
+            num /= 10;
+            buf[Width - 4] = '0' + num % 10; // Thousands.
+        }
+
+        if (Width > 4)
+        {
+            num /= 10;
+            buf[Width - 5] = '0' + num % 10; // Ten-Thousands.
+        }
+
+        if (Width > 5)
+        {
+            num /= 10;
+            buf[Width - 6] = '0' + num % 10; // Hundred-Thousands.
+        }
+
+        static_assert(Width >= 1 && Width <= 6, "Width is invalid.");
+    }
+
+    /// Copy a null-terminated string into another.
+    /// Expects the destination to be large enough.
+    /// Note: unlike strcpy, this returns the *new* out
+    /// (destination) pointer, which saves a strlen call.
+    char* strcopy(const char* in, char* out)
+    {
+        while (*in)
+            *out++ = *in++;
+        return out;
+    }
+
+    /// Convert unsigned long num to base-10 ascii in place.
+    /// Returns the *end* position.
+    char* to_ascii(char* buf, size_t num)
+    {
+        int i = 0;
+        do
+        {
+            buf[i++] = '0' + num % 10;
+            num /= 10;
+        } while (num > 0);
+
+        // Reverse.
+        for (char *front = buf, *back = buf + i - 1; back > front; ++front, --back)
+        {
+            const char t = *front;
+            *front = *back;
+            *back = t;
+        }
+
+        return buf + i;
+    }
+
+    char* prefix(const Poco::DateTime& time, char* buffer, const char* level)
+    {
+        // Note that snprintf is deemed signal-safe in most common implementations.
+        char* pos = strcopy((Source.getInited() ? Source.getId().c_str() : "<shutdown>"), buffer);
+        *pos++ = '-';
+
+        // Thread ID.
 #ifdef __linux
         const long osTid = Util::getThreadId();
-        // Note that snprintf is deemed signal-safe in most common implementations.
-        snprintf(buffer, len, "%s-%.05lu %.4u-%.2u-%.2u %.2u:%.2u:%.2u.%.6u [ %s ] %s  ",
-                    (Source.getInited() ? Source.getId().c_str() : "<shutdown>"),
-                    osTid,
-                    time.year(), time.month(), time.day(),
-                    time.hour(), time.minute(), time.second(),
-                    time.millisecond() * 1000 + time.microsecond(),
-                    threadName, level);
+        if (osTid > 99999)
+        {
+            if (osTid > 999999)
+                pos = to_ascii(pos, osTid);
+            else
+            {
+                to_ascii_fixed<6>(pos, osTid);
+                pos += 6;
+            }
+        }
+        else
+        {
+            to_ascii_fixed<5>(pos, osTid);
+            pos += 5;
+        }
 #elif defined IOS
         uint64_t osTid;
         pthread_threadid_np(nullptr, &osTid);
-        snprintf(buffer, len, "%s-%#.05llx %.4u-%.2u-%.2u %.2u:%.2u:%.2u.%.6u [ %s ] %s  ",
-                    (Source.getInited() ? Source.getId().c_str() : "<shutdown>"),
-                    osTid,
-                    time.year(), time.month(), time.day(),
-                    time.hour(), time.minute(), time.second(),
-                    time.millisecond() * 1000 + time.microsecond(),
-                    threadName, level);
+        snprintf(pos, 32, "%#.05llx", osTid);
+        while (*pos++); // Skip to end.
 #endif
+
+        // YYYY-MM-DD.
+        *pos++ = ' ';
+        to_ascii_fixed<4>(pos, time.year());
+        pos[4] = '-';
+        pos += 5;
+        to_ascii_fixed<2>(pos, time.month());
+        pos[2] = '-';
+        pos += 3;
+        to_ascii_fixed<2>(pos, time.day());
+        pos[2] = ' ';
+        pos += 3;
+
+        // HH:MM:SS.uS
+        to_ascii_fixed<2>(pos, time.hour());
+        pos[2] = ':';
+        pos += 3;
+        to_ascii_fixed<2>(pos, time.minute());
+        pos[2] = ':';
+        pos += 3;
+        to_ascii_fixed<2>(pos, time.second());
+        pos[2] = '.';
+        pos += 3;
+        to_ascii_fixed<6>(pos, time.millisecond() * 1000 + time.microsecond());
+        pos[6] = ' ';
+        pos[7] = '[';
+        pos[8] = ' ';
+        pos += 9;
+
+        pos = strcopy(Util::getThreadName(), pos);
+        pos[0] = ' ';
+        pos[1] = ']';
+        pos[2] = ' ';
+        pos += 3;
+        pos = strcopy(level, pos);
+        pos[0] = ' ';
+        pos[1] = ' ';
+        pos[2] = '\0';
+
         return buffer;
     }
 
     void signalLogPrefix()
     {
         char buffer[1024];
-        prefix(buffer, sizeof(buffer) - 1, "SIG");
+        prefix<sizeof(buffer) - 1>(buffer, "SIG");
         signalLog(buffer);
     }
 
diff --git a/common/Log.hpp b/common/Log.hpp
index bc96035e9..604c66ac7 100644
--- a/common/Log.hpp
+++ b/common/Log.hpp
@@ -67,7 +67,15 @@ namespace Log
     constexpr bool isShutdownCalled() { return false; }
 #endif
 
-    char* prefix(char* buffer, std::size_t len, const char* level);
+    /// Generates log entry prefix. Example follows (without the pipes).
+    /// |wsd-07272-07298 2020-04-25 17:29:28.928697 [ websrv_poll ] TRC  |
+    /// This is fully signal-safe. Buffer must be at least 128 bytes.
+    char* prefix(const Poco::DateTime& time, char* buffer, const char* level);
+    template <int Size> inline char* prefix(char buffer[Size], const char* level)
+    {
+        static_assert(Size >= 128, "Buffer size must be at least 128 bytes.");
+        return prefix(Poco::DateTime(), buffer, level);
+    }
 
     inline bool traceEnabled() { return logger().trace(); }
     inline bool debugEnabled() { return logger().debug(); }
@@ -109,7 +117,7 @@ namespace Log
             _enabled(true)
         {
             char buffer[1024];
-            _stream << prefix(buffer, sizeof(buffer) - 1, level);
+            _stream << prefix<sizeof(buffer) - 1>(buffer, level);
         }
 
         StreamLogger(StreamLogger&& sl) noexcept
@@ -274,7 +282,7 @@ namespace Log
 
 #define LOG_BODY_(LOG, PRIO, LVL, X, FILEP)                                                        \
     char b_[1024];                                                                                 \
-    std::ostringstream oss_(Log::prefix(b_, sizeof(b_) - 1, LVL), std::ostringstream::ate);        \
+    std::ostringstream oss_(Log::prefix<sizeof(b_) - 1>(b_, LVL), std::ostringstream::ate);        \
     oss_ << std::boolalpha << X;                                                                   \
     LOG_END(oss_, FILEP);                                                                          \
     ((void)__android_log_print(ANDROID_LOG_DEBUG, "loolwsd", "%s %s", LVL, oss_.str().c_str()))
@@ -282,13 +290,11 @@ namespace Log
 #else
 
 #define LOG_BODY_(LOG, PRIO, LVL, X, FILEP)                                                        \
-    Poco::Message m_(LOG.name(), "", Poco::Message::PRIO_##PRIO);                                  \
     char b_[1024];                                                                                 \
-    std::ostringstream oss_(Log::prefix(b_, sizeof(b_) - 1, LVL), std::ostringstream::ate);        \
+    std::ostringstream oss_(Log::prefix<sizeof(b_) - 1>(b_, LVL), std::ostringstream::ate);        \
     oss_ << std::boolalpha << X;                                                                   \
     LOG_END(oss_, FILEP);                                                                          \
-    m_.setText(oss_.str());                                                                        \
-    LOG.log(m_);
+    LOG.log(Poco::Message(LOG.name(), oss_.str(), Poco::Message::PRIO_##PRIO));
 
 #endif
 


More information about the Libreoffice-commits mailing list