Improve logging facilities.
authorDavin McCall <davmac@davmac.org>
Tue, 17 Nov 2015 19:23:29 +0000 (19:23 +0000)
committerDavin McCall <davmac@davmac.org>
Tue, 17 Nov 2015 19:23:29 +0000 (19:23 +0000)
Allow variadic 'log' calls, and automatically convert std::string
and int arguments to char * in an exception-free manner.

dinit-log.cc
dinit-log.h

index fe5bc30c0703760f9b00d5df427cd92b2c88f555..8e031e7fa57b378e4ab04f71a12b91d87268f80d 100644 (file)
@@ -3,6 +3,7 @@
 
 LogLevel log_level = LogLevel::WARN;
 bool log_to_console = true;    // whether we should output log messages to console
+bool log_current_line;
 
 // Log a message
 void log(LogLevel lvl, const char *msg) noexcept
@@ -14,6 +15,37 @@ void log(LogLevel lvl, const char *msg) noexcept
     }
 }
 
+// Log a multi-part message beginning
+void logMsgBegin(LogLevel lvl, const char *msg) noexcept
+{
+    log_current_line = lvl >= log_level;
+    if (log_current_line) {
+        if (log_to_console) {
+            std::cout << "dinit: " << msg;
+        }
+    }
+}
+
+// Continue a multi-part log message
+void logMsgPart(const char *msg) noexcept
+{
+    if (log_current_line) {
+        if (log_to_console) {
+            std::cout << msg;
+        }
+    }
+}
+
+// Complete a multi-part log message
+void logMsgEnd(const char *msg) noexcept
+{
+    if (log_current_line) {
+        if (log_to_console) {
+            std::cout << msg << std::endl;
+        }
+    }
+}
+
 void logServiceStarted(const char *service_name) noexcept
 {
     if (log_to_console) {
index e7718258f1b75a349a22b4ebddc490d370d521ba..b54664e8a0d55474edc39e2760e1d7a0ee91f28c 100644 (file)
@@ -4,6 +4,8 @@
 // Logging for Dinit
 
 #include <string>
+#include <cstdio>
+#include <climits>
 
 enum class LogLevel {
     DEBUG,
@@ -17,28 +19,94 @@ extern LogLevel log_level;
 extern bool log_to_console;
 
 void log(LogLevel lvl, const char *msg) noexcept;
+void logMsgBegin(LogLevel lvl, const char *msg) noexcept;
+void logMsgPart(const char *msg) noexcept;
+void logMsgEnd(const char *msg) noexcept;
 void logServiceStarted(const char *service_name) noexcept;
 void logServiceFailed(const char *service_name) noexcept;
 void logServiceStopped(const char *service_name) noexcept;
 
-static inline void log(LogLevel lvl, const std::string &str)
+// Convenience methods which perform type conversion of the argument.
+// There is some duplication here that could possibly be avoided, but
+// it doesn't seem like a big deal.
+static inline void log(LogLevel lvl, const std::string &str) noexcept
 {
     log(lvl, str.c_str());
 }
 
-static inline void logServiceStarted(const std::string &str)
+static inline void logMsgBegin(LogLevel lvl, const std::string &str) noexcept
+{
+    logMsgBegin(lvl, str.c_str());
+}
+
+static inline void logMsgBegin(LogLevel lvl, int a) noexcept
+{
+    constexpr int bufsz = (CHAR_BIT * sizeof(int) - 1) / 3 + 2;
+    char nbuf[bufsz];
+    snprintf(nbuf, bufsz, "%d", a);
+    logMsgBegin(lvl, nbuf);
+}
+
+static inline void logMsgPart(const std::string &str) noexcept
+{
+    logMsgPart(str.c_str());
+}
+
+static inline void logMsgPart(int a) noexcept
+{
+    constexpr int bufsz = (CHAR_BIT * sizeof(int) - 1) / 3 + 2;
+    char nbuf[bufsz];
+    snprintf(nbuf, bufsz, "%d", a);
+    logMsgPart(nbuf);
+}
+
+static inline void logMsgEnd(const std::string &str) noexcept
+{
+    logMsgEnd(str.c_str());
+}
+
+static inline void logMsgEnd(int a) noexcept
+{
+    constexpr int bufsz = (CHAR_BIT * sizeof(int) - 1) / 3 + 2;
+    char nbuf[bufsz];
+    snprintf(nbuf, bufsz, "%d", a);
+    logMsgEnd(nbuf);
+}
+
+static inline void logServiceStarted(const std::string &str) noexcept
 {
     logServiceStarted(str.c_str());
 }
 
-static inline void logServiceFailed(const std::string &str)
+static inline void logServiceFailed(const std::string &str) noexcept
 {
     logServiceFailed(str.c_str());
 }
 
-static inline void logServiceStopped(const std::string &str)
+static inline void logServiceStopped(const std::string &str) noexcept
 {
     logServiceStopped(str.c_str());
 }
 
+// It's not intended that methods in this namespace be called directly:
+namespace dinit_log {
+    template <typename A> static inline void logParts(A a) noexcept
+    {
+        logMsgEnd(a);
+    }
+
+    template <typename A, typename ...B> static inline void logParts(A a, B... b) noexcept
+    {
+        logMsgPart(a);
+        logParts(b...);
+    }
+}
+
+// Variadic 'log' method.
+template <typename A, typename ...B> static inline void log(LogLevel lvl, A a, B ...b) noexcept
+{
+    logMsgBegin(lvl, a);
+    dinit_log::logParts(b...);
+}
+
 #endif