[lldb] Support file and function names in LLDB_LOGF macro
authorJonas Devlieghere <jonas@devlieghere.com>
Tue, 6 Jun 2023 17:37:12 +0000 (10:37 -0700)
committerJonas Devlieghere <jonas@devlieghere.com>
Tue, 6 Jun 2023 19:24:38 +0000 (12:24 -0700)
LLDB's logging machinery supports prepending log messages with the name
of the file and function that generates the log. However, currently this
functionality is limited to the LLDB_LOG macro. I meant to do this as a
follow up to D65128 but never got around to it.

Differential revision: https://reviews.llvm.org/D151764

lldb/include/lldb/Utility/Log.h
lldb/source/Utility/Log.cpp
lldb/unittests/Utility/LogTest.cpp

index 2984a4b..1fe28d6 100644 (file)
@@ -232,6 +232,9 @@ public:
                          std::forward<Args>(args)...));
   }
 
+  void Formatf(llvm::StringRef file, llvm::StringRef function,
+               const char *format, ...) __attribute__((format(printf, 4, 5)));
+
   /// Prefer using LLDB_LOGF whenever possible.
   void Printf(const char *format, ...) __attribute__((format(printf, 2, 3)));
 
@@ -249,6 +252,8 @@ public:
 
   void VAPrintf(const char *format, va_list args);
   void VAError(const char *format, va_list args);
+  void VAFormatf(llvm::StringRef file, llvm::StringRef function,
+                 const char *format, va_list args);
 
 private:
   Channel &m_channel;
@@ -345,7 +350,7 @@ template <typename Cat> Log *GetLog(Cat mask) {
   do {                                                                         \
     ::lldb_private::Log *log_private = (log);                                  \
     if (log_private)                                                           \
-      log_private->Printf(__VA_ARGS__);                                        \
+      log_private->Formatf(__FILE__, __func__, __VA_ARGS__);                   \
   } while (0)
 
 #define LLDB_LOGV(log, ...)                                                    \
index da8569e..7591268 100644 (file)
@@ -155,6 +155,21 @@ void Log::VAPrintf(const char *format, va_list args) {
   PutString(Content);
 }
 
+void Log::Formatf(llvm::StringRef file, llvm::StringRef function,
+                  const char *format, ...) {
+  va_list args;
+  va_start(args, format);
+  VAFormatf(file, function, format, args);
+  va_end(args);
+}
+
+void Log::VAFormatf(llvm::StringRef file, llvm::StringRef function,
+                    const char *format, va_list args) {
+  llvm::SmallString<64> Content;
+  lldb_private::VASprintf(Content, format, args);
+  Format(file, function, llvm::formatv("{0}", Content));
+}
+
 // Printing of errors that are not fatal.
 void Log::Error(const char *format, ...) {
   va_list args;
index 275bd0d..d3c878d 100644 (file)
@@ -100,6 +100,7 @@ protected:
   Log *getLog() { return m_log; }
   llvm::StringRef takeOutput();
   llvm::StringRef logAndTakeOutput(llvm::StringRef Message);
+  llvm::StringRef logAndTakeOutputf(llvm::StringRef Message);
 
 public:
   void SetUp() override;
@@ -136,6 +137,12 @@ LogChannelEnabledTest::logAndTakeOutput(llvm::StringRef Message) {
   return takeOutput();
 }
 
+llvm::StringRef
+LogChannelEnabledTest::logAndTakeOutputf(llvm::StringRef Message) {
+  LLDB_LOGF(m_log, "%s", Message.str().c_str());
+  return takeOutput();
+}
+
 TEST(LogTest, LLDB_LOG_nullptr) {
   Log *log = nullptr;
   LLDB_LOG(log, "{0}", 0); // Shouldn't crash
@@ -296,6 +303,21 @@ TEST_F(LogChannelEnabledTest, log_options) {
     EXPECT_STREQ("logAndTakeOutput", Function);
   }
 
+  {
+    EXPECT_TRUE(EnableChannel(getLogHandler(),
+                              LLDB_LOG_OPTION_PREPEND_FILE_FUNCTION, "chan", {},
+                              Err));
+    llvm::StringRef Msg = logAndTakeOutputf("Hello World");
+    char File[12];
+    char Function[17];
+
+    sscanf(Msg.str().c_str(),
+           "%[^:]:%s                                 Hello World", File,
+           Function);
+    EXPECT_STRCASEEQ("LogTest.cpp", File);
+    EXPECT_STREQ("logAndTakeOutputf", Function);
+  }
+
   EXPECT_TRUE(EnableChannel(getLogHandler(),
                             LLDB_LOG_OPTION_PREPEND_PROC_AND_THREAD, "chan", {},
                             Err));