changeset 4275:d7a50b7b8466

Dynamically access and/or change the verbosity of logging categories with the REST API
author Sebastien Jodogne <s.jodogne@gmail.com>
date Tue, 03 Nov 2020 14:41:27 +0100
parents 09ed936fd381
children 68e24935f258
files NEWS OrthancFramework/Resources/CMake/OrthancFrameworkParameters.cmake OrthancFramework/Sources/Logging.cpp OrthancFramework/Sources/Logging.h OrthancFramework/UnitTestsSources/LoggingTests.cpp OrthancServer/Sources/OrthancRestApi/OrthancRestSystem.cpp OrthancServer/UnitTestsSources/UnitTestsMain.cpp
diffstat 7 files changed, 134 insertions(+), 34 deletions(-) [+]
line wrap: on
line diff
--- a/NEWS	Tue Nov 03 12:28:25 2020 +0100
+++ b/NEWS	Tue Nov 03 14:41:27 2020 +0100
@@ -1,7 +1,19 @@
 Pending changes in the mainline
 ===============================
 
-* Logging categories (check out command-line options "--verbose=" and "--trace=")
+General
+-------
+
+* Logging categories (cf. command-line options starting with "--verbose-" and "--trace=")
+
+REST API
+--------
+
+* "/tools/log-level-*": Dynamically access and/or change the verbosity of logging categories
+
+Maintenance
+-----------
+
 * C-GET SCP: Fix responses and handling of cancel
 * Fix decoding sequence if "BuiltinDecoderTranscoderOrder" is "Before"
 * REST API returns 404 error if deleting an inexistent peer or modality
--- a/OrthancFramework/Resources/CMake/OrthancFrameworkParameters.cmake	Tue Nov 03 12:28:25 2020 +0100
+++ b/OrthancFramework/Resources/CMake/OrthancFrameworkParameters.cmake	Tue Nov 03 14:41:27 2020 +0100
@@ -37,7 +37,7 @@
 # Version of the Orthanc API, can be retrieved from "/system" URI in
 # order to check whether new URI endpoints are available even if using
 # the mainline version of Orthanc
-set(ORTHANC_API_VERSION "8")
+set(ORTHANC_API_VERSION "9")
 
 
 #####################################################################
--- a/OrthancFramework/Sources/Logging.cpp	Tue Nov 03 12:28:25 2020 +0100
+++ b/OrthancFramework/Sources/Logging.cpp	Tue Nov 03 14:41:27 2020 +0100
@@ -228,29 +228,42 @@
     }
 
 
-    size_t GetCategoriesCount()
+    unsigned int GetCategoriesCount()
     {
       return 5;
     }
 
 
-    const char* GetCategoryName(size_t i)
+    const char* GetCategoryName(unsigned int i)
     {
-      switch (i)
+      if (i < GetCategoriesCount())
+      {
+        return GetCategoryName(static_cast<LogCategory>(1 << i));
+      }
+      else
       {
-        case 0:
+        throw OrthancException(ErrorCode_ParameterOutOfRange);
+      }
+    }
+    
+
+    const char* GetCategoryName(LogCategory category)
+    {
+      switch (category)
+      {
+        case LogCategory_GENERIC:
           return "generic";
-          
-        case 1:
+            
+        case LogCategory_PLUGINS:
           return "plugins";
-          
-        case 2:
+            
+        case LogCategory_REST:
           return "rest";
-          
-        case 3:
+            
+        case LogCategory_DICOM:
           return "dicom";
-          
-        case 4:
+            
+        case LogCategory_SQLITE:
           return "sqlite";
 
         default:
--- a/OrthancFramework/Sources/Logging.h	Tue Nov 03 12:28:25 2020 +0100
+++ b/OrthancFramework/Sources/Logging.h	Tue Nov 03 14:41:27 2020 +0100
@@ -100,9 +100,11 @@
     ORTHANC_PUBLIC bool LookupCategory(LogCategory& target,
                                        const std::string& category);
 
-    ORTHANC_PUBLIC size_t GetCategoriesCount();
+    ORTHANC_PUBLIC unsigned int GetCategoriesCount();
 
-    ORTHANC_PUBLIC const char* GetCategoryName(size_t i);
+    ORTHANC_PUBLIC const char* GetCategoryName(unsigned int i);
+
+    ORTHANC_PUBLIC const char* GetCategoryName(LogCategory category);
 
     ORTHANC_PUBLIC void SetTargetFile(const std::string& path);
 
--- a/OrthancFramework/UnitTestsSources/LoggingTests.cpp	Tue Nov 03 12:28:25 2020 +0100
+++ b/OrthancFramework/UnitTestsSources/LoggingTests.cpp	Tue Nov 03 14:41:27 2020 +0100
@@ -359,3 +359,42 @@
   ASSERT_TRUE(IsCategoryEnabled(LogLevel_INFO, LogCategory_SQLITE));
   ASSERT_FALSE(IsCategoryEnabled(LogLevel_TRACE, LogCategory_SQLITE));
 }
+
+
+TEST(Logging, Enumerations)
+{
+  using namespace Orthanc;
+  
+  Logging::LogCategory c;
+  ASSERT_TRUE(Logging::LookupCategory(c, "generic"));  ASSERT_EQ(Logging::LogCategory_GENERIC, c);
+  ASSERT_TRUE(Logging::LookupCategory(c, "plugins"));  ASSERT_EQ(Logging::LogCategory_PLUGINS, c);
+  ASSERT_TRUE(Logging::LookupCategory(c, "rest"));     ASSERT_EQ(Logging::LogCategory_REST, c);
+  ASSERT_TRUE(Logging::LookupCategory(c, "sqlite"));   ASSERT_EQ(Logging::LogCategory_SQLITE, c);
+  ASSERT_TRUE(Logging::LookupCategory(c, "dicom"));    ASSERT_EQ(Logging::LogCategory_DICOM, c);
+  ASSERT_FALSE(Logging::LookupCategory(c, "nope"));
+
+  ASSERT_EQ(5u, Logging::GetCategoriesCount());
+
+  std::set<std::string> s;
+  for (size_t i = 0; i < Logging::GetCategoriesCount(); i++)
+  {
+    Logging::LogCategory c;
+    ASSERT_TRUE(Logging::LookupCategory(c, Logging::GetCategoryName(i)));
+    s.insert(Logging::GetCategoryName(i));
+  }
+
+  ASSERT_EQ(5u, s.size());
+  ASSERT_NE(s.end(), s.find("generic"));
+  ASSERT_NE(s.end(), s.find("plugins"));
+  ASSERT_NE(s.end(), s.find("rest"));
+  ASSERT_NE(s.end(), s.find("sqlite"));
+  ASSERT_NE(s.end(), s.find("dicom"));
+
+  ASSERT_THROW(Logging::GetCategoryName(Logging::GetCategoriesCount()), OrthancException);
+
+  ASSERT_STREQ("generic", Logging::GetCategoryName(Logging::LogCategory_GENERIC));
+  ASSERT_STREQ("plugins", Logging::GetCategoryName(Logging::LogCategory_PLUGINS));
+  ASSERT_STREQ("rest", Logging::GetCategoryName(Logging::LogCategory_REST));
+  ASSERT_STREQ("sqlite", Logging::GetCategoryName(Logging::LogCategory_SQLITE));
+  ASSERT_STREQ("dicom", Logging::GetCategoryName(Logging::LogCategory_DICOM));
+}
--- a/OrthancServer/Sources/OrthancRestApi/OrthancRestSystem.cpp	Tue Nov 03 12:28:25 2020 +0100
+++ b/OrthancServer/Sources/OrthancRestApi/OrthancRestSystem.cpp	Tue Nov 03 14:41:27 2020 +0100
@@ -42,6 +42,8 @@
 #include "../OrthancInitialization.h"
 #include "../ServerContext.h"
 
+#include <boost/algorithm/string/predicate.hpp>
+
 
 namespace Orthanc
 {
@@ -511,6 +513,49 @@
   }
 
 
+  static Logging::LogCategory GetCategory(const RestApiCall& call)
+  {
+    static const std::string PREFIX = "log-level-";
+
+    if (call.GetFullUri().size() == 2 &&
+        call.GetFullUri() [0] == "tools" &&
+        boost::starts_with(call.GetFullUri() [1], PREFIX))
+    {
+      Logging::LogCategory category;
+      if (Logging::LookupCategory(category, call.GetFullUri() [1].substr(PREFIX.size())))
+      {
+        return category;
+      }
+    }
+
+    throw OrthancException(ErrorCode_InternalError);
+  }
+  
+
+  static void GetLogLevelCategory(RestApiGetCall& call)
+  {
+    const std::string s = EnumerationToString(GetCategoryVerbosity(GetCategory(call)));
+    call.GetOutput().AnswerBuffer(s, MimeType_PlainText);
+  }
+
+
+  static void PutLogLevelCategory(RestApiPutCall& call)
+  {
+    std::string body;
+    call.BodyToString(body);
+
+    Verbosity verbosity = StringToVerbosity(body);
+    Logging::LogCategory category = GetCategory(call);
+    SetCategoryVerbosity(category, verbosity);
+    
+    // Success
+    LOG(WARNING) << "REST API call has switched the log level of category \""
+                 << Logging::GetCategoryName(category) << "\" to \""
+                 << EnumerationToString(verbosity) << "\"";
+    call.GetOutput().AnswerBuffer("", MimeType_PlainText);
+  }
+
+
   void OrthancRestApi::RegisterSystem()
   {
     Register("/", ServeRoot);
@@ -529,6 +574,13 @@
     Register("/tools/log-level", GetLogLevel);
     Register("/tools/log-level", PutLogLevel);
 
+    for (size_t i = 0; i < Logging::GetCategoriesCount(); i++)
+    {
+      const std::string name(Logging::GetCategoryName(i));
+      Register("/tools/log-level-" + name, GetLogLevelCategory);
+      Register("/tools/log-level-" + name, PutLogLevelCategory);
+    }
+
     Register("/plugins", ListPlugins);
     Register("/plugins/{id}", GetPlugin);
     Register("/plugins/explorer.js", GetOrthancExplorerPlugins);
--- a/OrthancServer/UnitTestsSources/UnitTestsMain.cpp	Tue Nov 03 12:28:25 2020 +0100
+++ b/OrthancServer/UnitTestsSources/UnitTestsMain.cpp	Tue Nov 03 14:41:27 2020 +0100
@@ -131,24 +131,6 @@
   ASSERT_STREQ("verbose", EnumerationToString(StringToVerbosity("verbose")));
   ASSERT_STREQ("trace", EnumerationToString(StringToVerbosity("trace")));
   ASSERT_THROW(StringToVerbosity("nope"), OrthancException);
-
-  Logging::LogCategory c;
-  ASSERT_TRUE(Logging::LookupCategory(c, "generic"));  ASSERT_EQ(Logging::LogCategory_GENERIC, c);
-  ASSERT_TRUE(Logging::LookupCategory(c, "plugins"));  ASSERT_EQ(Logging::LogCategory_PLUGINS, c);
-  ASSERT_TRUE(Logging::LookupCategory(c, "rest"));     ASSERT_EQ(Logging::LogCategory_REST, c);
-  ASSERT_TRUE(Logging::LookupCategory(c, "sqlite"));   ASSERT_EQ(Logging::LogCategory_SQLITE, c);
-  ASSERT_TRUE(Logging::LookupCategory(c, "dicom"));    ASSERT_EQ(Logging::LogCategory_DICOM, c);
-  ASSERT_FALSE(Logging::LookupCategory(c, "nope"));
-
-  ASSERT_EQ(5u, Logging::GetCategoriesCount());
-
-  for (size_t i = 0; i < Logging::GetCategoriesCount(); i++)
-  {
-    Logging::LogCategory c;
-    ASSERT_TRUE(Logging::LookupCategory(c, Logging::GetCategoryName(i)));
-  }
-
-  ASSERT_THROW(Logging::GetCategoryName(Logging::GetCategoriesCount()), OrthancException);
 }