changeset 5575:d7eaa568da15

Orthanc::Logging automatically detects whether the Orthanc core supports OrthancPluginLogMessage()
author Sebastien Jodogne <s.jodogne@gmail.com>
date Fri, 26 Apr 2024 17:17:34 +0200
parents 823aae1ea72a
children 3a6d6d35193c
files OrthancFramework/Sources/Logging.cpp OrthancFramework/Sources/Logging.h OrthancFramework/Sources/Toolbox.cpp OrthancFramework/Sources/Toolbox.h OrthancFramework/UnitTestsSources/FrameworkTests.cpp OrthancServer/Plugins/Engine/OrthancPlugins.cpp OrthancServer/Plugins/Include/orthanc/OrthancCPlugin.h OrthancServer/Plugins/Samples/Common/OrthancPluginCppWrapper.cpp OrthancServer/Plugins/Samples/Common/OrthancPluginCppWrapper.h
diffstat 9 files changed, 309 insertions(+), 50 deletions(-) [+]
line wrap: on
line diff
--- a/OrthancFramework/Sources/Logging.cpp	Fri Apr 26 16:01:26 2024 +0200
+++ b/OrthancFramework/Sources/Logging.cpp	Fri Apr 26 17:17:34 2024 +0200
@@ -525,6 +525,7 @@
 
 #include "Enumerations.h"
 #include "SystemToolbox.h"
+#include "Toolbox.h"
 
 #include <fstream>
 #include <boost/filesystem.hpp>
@@ -560,7 +561,8 @@
 static boost::mutex                             loggingStreamsMutex_;
 static Orthanc::Logging::NullStream             nullStream_;
 static OrthancPluginContext*                    pluginContext_ = NULL;    // this is != NULL only when running from a plugin
-static const char*                              pluginName_ = NULL;       // this is != NULL only when running from a plugin
+static std::string                              pluginName_;              // this string can only be non-empty if running from a plugin
+static bool                                     hasOrthancAdvancedLogging_ = false;  // Whether the Orthanc runtime is >= 1.12.4
 static boost::recursive_mutex                   threadNamesMutex_;
 static std::map<boost::thread::id, std::string> threadNames_;
 static bool                                     enableThreadNames_ = true;
@@ -784,14 +786,23 @@
     {
       assert(sizeof(_OrthancPluginService) == sizeof(int32_t));
 
+      if (pluginContext == NULL)
+      {
+        throw OrthancException(ErrorCode_NullPointer);
+      }
+
       boost::mutex::scoped_lock lock(loggingStreamsMutex_);
       loggingStreamsContext_.reset(NULL);
       pluginContext_ = reinterpret_cast<OrthancPluginContext*>(pluginContext);
 
+      // The value "hasOrthancAdvancedLogging_" is cached to avoid computing it on every logged message
+      hasOrthancAdvancedLogging_ = Toolbox::IsVersionAbove(pluginContext_->orthancVersion, 1, 12, 4);
+
       EnableInfoLevel(true);  // allow the plugin to log at info level (but the Orthanc Core still decides of the level)
     }
 
-    void InitializePluginContext(void* pluginContext, const char* pluginName)
+
+    void InitializePluginContext(void* pluginContext, const std::string& pluginName)
     {
       InitializePluginContext(pluginContext);
       pluginName_ = pluginName;
@@ -983,14 +994,15 @@
 
         if (pluginContext_ != NULL)
         {
-          if (pluginName_ != NULL) // this shall happen only if ORTHANC_FRAMEWORK_VERSION_IS_ABOVE(1, 12, 4) && ORTHANC_PLUGINS_VERSION_IS_ABOVE(1, 12, 4)
+          if (!pluginName_.empty() &&
+              hasOrthancAdvancedLogging_)
           {
             _OrthancPluginLogMessage m;
             m.category = category_;
             m.level = level_;
             m.file = file_;
             m.line = line_;
-            m.plugin = pluginName_;
+            m.plugin = pluginName_.c_str();
             m.message = message.c_str();
             pluginContext_->InvokeService(pluginContext_, _OrthancPluginService_LogMessage, &m);
           }
--- a/OrthancFramework/Sources/Logging.h	Fri Apr 26 16:01:26 2024 +0200
+++ b/OrthancFramework/Sources/Logging.h	Fri Apr 26 17:17:34 2024 +0200
@@ -80,8 +80,8 @@
     // "pluginContext" must be of type "OrthancPluginContext"
     ORTHANC_PUBLIC void InitializePluginContext(void* pluginContext);
 
-    // note: this variant shall be called only from a plugin and only if ORTHANC_FRAMEWORK_VERSION_IS_ABOVE(1, 12, 4) && ORTHANC_PLUGINS_VERSION_IS_ABOVE(1, 12, 4)
-    ORTHANC_PUBLIC void InitializePluginContext(void* pluginContext, const char* pluginName);
+    ORTHANC_PUBLIC void InitializePluginContext(void* pluginContext,
+                                                const std::string& pluginName);
 
     ORTHANC_PUBLIC void Initialize();
 
--- a/OrthancFramework/Sources/Toolbox.cpp	Fri Apr 26 16:01:26 2024 +0200
+++ b/OrthancFramework/Sources/Toolbox.cpp	Fri Apr 26 17:17:34 2024 +0200
@@ -2676,6 +2676,139 @@
   }
 
 
+  bool Toolbox::ParseVersion(unsigned int& major,
+                             unsigned int& minor,
+                             unsigned int& revision,
+                             const char* version)
+  {
+    if (version == NULL)
+    {
+      throw OrthancException(ErrorCode_NullPointer);
+    }
+
+#ifdef _MSC_VER
+#define ORTHANC_SCANF sscanf_s
+#else
+#define ORTHANC_SCANF sscanf
+#endif
+
+    int a, b, c;
+    if (ORTHANC_SCANF(version, "%4d.%4d.%4d", &a, &b, &c) == 3)
+    {
+      if (a >= 0 &&
+          b >= 0 &&
+          c >= 0)
+      {
+        major = static_cast<unsigned int>(a);
+        minor = static_cast<unsigned int>(b);
+        revision = static_cast<unsigned int>(c);
+        return true;
+      }
+      else
+      {
+        return false;
+      }
+    }
+    else if (ORTHANC_SCANF(version, "%4d.%4d", &a, &b) == 2)
+    {
+      if (a >= 0 &&
+          b >= 0)
+      {
+        major = static_cast<unsigned int>(a);
+        minor = static_cast<unsigned int>(b);
+        revision = 0;
+        return true;
+      }
+      else
+      {
+        return false;
+      }
+    }
+    else if (ORTHANC_SCANF(version, "%4d", &a) == 1 &&
+             a >= 0)
+    {
+      if (a >= 0)
+      {
+        major = static_cast<unsigned int>(a);
+        minor = 0;
+        revision = 0;
+        return true;
+      }
+      else
+      {
+        return false;
+      }
+    }
+    else
+    {
+      return false;
+    }
+  }
+
+
+  bool Toolbox::IsVersionAbove(const char* version,
+                               unsigned int major,
+                               unsigned int minor,
+                               unsigned int revision)
+  {
+    /**
+     * Note: Similar standalone functions are implemented in
+     * "OrthancCPlugin.h" and "OrthancPluginCppWrapper.cpp".
+     **/
+
+    unsigned int actualMajor, actualMinor, actualRevision;
+
+    if (version == NULL)
+    {
+      throw OrthancException(ErrorCode_NullPointer);
+    }
+    else if (!strcmp(version, "mainline"))
+    {
+      // Assume compatibility with the mainline
+      return true;
+    }
+    else if (ParseVersion(actualMajor, actualMinor, actualRevision, version))
+    {
+      if (actualMajor > major)
+      {
+        return true;
+      }
+
+      if (actualMajor < major)
+      {
+        return false;
+      }
+
+      // Check the minor version number
+      assert(actualMajor == major);
+
+      if (actualMinor > minor)
+      {
+        return true;
+      }
+
+      if (actualMinor < minor)
+      {
+        return false;
+      }
+
+      // Check the patch level version number
+      assert(actualMajor == major);
+
+      if (actualRevision >= revision)
+      {
+        return true;
+      }
+      else
+      {
+        return false;
+      }
+    }
+    else
+    {
+      throw OrthancException(ErrorCode_ParameterOutOfRange, "Not a valid version: " + std::string(version));
+    }
+  }
 }
 
 
--- a/OrthancFramework/Sources/Toolbox.h	Fri Apr 26 16:01:26 2024 +0200
+++ b/OrthancFramework/Sources/Toolbox.h	Fri Apr 26 17:17:34 2024 +0200
@@ -416,6 +416,15 @@
 
     static std::string GetHumanTransferSpeed(bool full, uint64_t sizeInBytes, uint64_t durationInNanoseconds);
 
+    static bool ParseVersion(unsigned int& major,
+                             unsigned int& minor,
+                             unsigned int& revision,
+                             const char* version);
+
+    static bool IsVersionAbove(const char* version,
+                               unsigned int major,
+                               unsigned int minor,
+                               unsigned int revision);
   };
 }
 
--- a/OrthancFramework/UnitTestsSources/FrameworkTests.cpp	Fri Apr 26 16:01:26 2024 +0200
+++ b/OrthancFramework/UnitTestsSources/FrameworkTests.cpp	Fri Apr 26 17:17:34 2024 +0200
@@ -1602,3 +1602,53 @@
   }
 }
 #endif
+
+
+TEST(Toolbox, IsVersionAbove)
+{
+  unsigned int a, b, c;
+  ASSERT_FALSE(Toolbox::ParseVersion(a, b, c, "nope"));
+  ASSERT_FALSE(Toolbox::ParseVersion(a, b, c, "mainline"));
+  ASSERT_FALSE(Toolbox::ParseVersion(a, b, c, ""));
+  ASSERT_FALSE(Toolbox::ParseVersion(a, b, c, "-1"));
+  ASSERT_FALSE(Toolbox::ParseVersion(a, b, c, "1.-1"));
+  ASSERT_FALSE(Toolbox::ParseVersion(a, b, c, "1.1.-1"));
+
+  ASSERT_TRUE(Toolbox::ParseVersion(a, b, c, "14.17.20"));
+  ASSERT_EQ(14u, a);
+  ASSERT_EQ(17u, b);
+  ASSERT_EQ(20u, c);
+
+  ASSERT_TRUE(Toolbox::ParseVersion(a, b, c, "18.19"));
+  ASSERT_EQ(18u, a);
+  ASSERT_EQ(19u, b);
+  ASSERT_EQ(0u, c);
+
+  ASSERT_TRUE(Toolbox::ParseVersion(a, b, c, "78"));
+  ASSERT_EQ(78u, a);
+  ASSERT_EQ(0u, b);
+  ASSERT_EQ(0u, c);
+
+  ASSERT_TRUE(Toolbox::IsVersionAbove("mainline", 99, 99, 99));
+
+  ASSERT_TRUE(Toolbox::IsVersionAbove("18", 17, 99, 99));
+  ASSERT_TRUE(Toolbox::IsVersionAbove("18", 18, 0, 0));
+  ASSERT_FALSE(Toolbox::IsVersionAbove("18", 18, 0, 1));
+  ASSERT_FALSE(Toolbox::IsVersionAbove("18", 18, 1, 0));
+  ASSERT_FALSE(Toolbox::IsVersionAbove("18", 19, 0, 0));
+
+  ASSERT_TRUE(Toolbox::IsVersionAbove("18.19", 17, 99, 99));
+  ASSERT_TRUE(Toolbox::IsVersionAbove("18.19", 18, 18, 99));
+  ASSERT_TRUE(Toolbox::IsVersionAbove("18.19", 18, 19, 0));
+  ASSERT_FALSE(Toolbox::IsVersionAbove("18.19", 18, 19, 1));
+  ASSERT_FALSE(Toolbox::IsVersionAbove("18.19", 18, 20, 0));
+  ASSERT_FALSE(Toolbox::IsVersionAbove("18.19", 19, 0, 0));
+
+  ASSERT_TRUE(Toolbox::IsVersionAbove("18.19.20", 17, 99, 99));
+  ASSERT_TRUE(Toolbox::IsVersionAbove("18.19.20", 18, 18, 99));
+  ASSERT_TRUE(Toolbox::IsVersionAbove("18.19.20", 18, 19, 19));
+  ASSERT_TRUE(Toolbox::IsVersionAbove("18.19.20", 18, 19, 20));
+  ASSERT_FALSE(Toolbox::IsVersionAbove("18.19.20", 18, 19, 21));
+  ASSERT_FALSE(Toolbox::IsVersionAbove("18.19.20", 18, 20, 0));
+  ASSERT_FALSE(Toolbox::IsVersionAbove("18.19.20", 19, 0, 0));
+}
--- a/OrthancServer/Plugins/Engine/OrthancPlugins.cpp	Fri Apr 26 16:01:26 2024 +0200
+++ b/OrthancServer/Plugins/Engine/OrthancPlugins.cpp	Fri Apr 26 17:17:34 2024 +0200
@@ -2090,6 +2090,8 @@
         sizeof(int32_t) != sizeof(OrthancPluginStorageCommitmentFailureReason) ||
         sizeof(int32_t) != sizeof(OrthancPluginReceivedInstanceAction) ||
         sizeof(int32_t) != sizeof(OrthancPluginLoadDicomInstanceMode) ||
+        sizeof(int32_t) != sizeof(OrthancPluginLogLevel) ||
+        sizeof(int32_t) != sizeof(OrthancPluginLogCategory) ||
         static_cast<int>(OrthancPluginDicomToJsonFlags_IncludeBinary) != static_cast<int>(DicomToJsonFlags_IncludeBinary) ||
         static_cast<int>(OrthancPluginDicomToJsonFlags_IncludePrivateTags) != static_cast<int>(DicomToJsonFlags_IncludePrivateTags) ||
         static_cast<int>(OrthancPluginDicomToJsonFlags_IncludeUnknownTags) != static_cast<int>(DicomToJsonFlags_IncludeUnknownTags) ||
--- a/OrthancServer/Plugins/Include/orthanc/OrthancCPlugin.h	Fri Apr 26 16:01:26 2024 +0200
+++ b/OrthancServer/Plugins/Include/orthanc/OrthancCPlugin.h	Fri Apr 26 17:17:34 2024 +0200
@@ -1087,6 +1087,43 @@
 
 
   /**
+   * The log levels supported by Orthanc.
+   *
+   * These values must match those of enumeration "LogLevel" in the
+   * Orthanc Core.
+   **/
+  typedef enum
+  {
+    OrthancPluginLogLevel_Error = 0,    /*!< Error log level */
+    OrthancPluginLogLevel_Warning = 1,  /*!< Warning log level */
+    OrthancPluginLogLevel_Info = 2,     /*!< Info log level */
+    OrthancPluginLogLevel_Trace = 3,    /*!< Trace log level */
+
+    _OrthancPluginLogLevel_INTERNAL = 0x7fffffff
+  } OrthancPluginLogLevel;
+
+
+  /**
+   * The log categories supported by Orthanc.
+   *
+   * These values must match those of enumeration "LogCategory" in the
+   * Orthanc Core.
+   **/
+  typedef enum
+  {
+    OrthancPluginLogCategory_Generic = (1 << 0),  /*!< Generic (default) category */
+    OrthancPluginLogCategory_Plugins = (1 << 1),  /*!< Plugin engine related logs (shall not be used by plugins) */
+    OrthancPluginLogCategory_Http    = (1 << 2),  /*!< HTTP related logs */
+    OrthancPluginLogCategory_Sqlite  = (1 << 3),  /*!< SQLite related logs (shall not be used by plugins) */
+    OrthancPluginLogCategory_Dicom   = (1 << 4),  /*!< DICOM related logs */
+    OrthancPluginLogCategory_Jobs    = (1 << 5),  /*!< jobs related logs */
+    OrthancPluginLogCategory_Lua     = (1 << 6),  /*!< Lua related logs (shall not be used by plugins) */
+
+    _OrthancPluginLogCategory_INTERNAL = 0x7fffffff
+  } OrthancPluginLogCategory;
+
+
+  /**
    * @brief A 32-bit memory buffer allocated by the core system of Orthanc.
    *
    * A memory buffer allocated by the core system of Orthanc. When the
@@ -1971,7 +2008,9 @@
         sizeof(int32_t) != sizeof(OrthancPluginMetricsType) ||
         sizeof(int32_t) != sizeof(OrthancPluginDicomWebBinaryMode) ||
         sizeof(int32_t) != sizeof(OrthancPluginStorageCommitmentFailureReason) ||
-        sizeof(int32_t) != sizeof(OrthancPluginLoadDicomInstanceMode))
+        sizeof(int32_t) != sizeof(OrthancPluginLoadDicomInstanceMode) ||
+        sizeof(int32_t) != sizeof(OrthancPluginLogLevel) ||
+        sizeof(int32_t) != sizeof(OrthancPluginLogCategory))
     {
       /* Mismatch in the size of the enumerations */
       return 0;
@@ -9480,37 +9519,10 @@
     return context->InvokeService(context, _OrthancPluginService_SetCurrentThreadName, threadName);
   }
 
-  typedef enum
-  {
-    // these values must match LogLevel in the Orthanc Core
-    OrthancPluginLogLevel_Error = 0,    /*!< Error log level */
-    OrthancPluginLogLevel_Warning = 1,  /*!< Warning log level */
-    OrthancPluginLogLevel_Info = 2,     /*!< Info log level */
-    OrthancPluginLogLevel_Trace = 3,    /*!< Trace log level */
-  
-    // Force the enum to be 32 bits
-    OrthancPluginLogLevel_INTERNAL = 0x7FFFFFFF
-  } OrthancPluginLogLevel;
-
-  typedef enum
-  {
-    // these values must match LogCategory in the Orthanc Core
-    OrthancPluginLogCategory_Generic = (1 << 0),  /*!< Generic (default) category */
-    OrthancPluginLogCategory_Plugins = (1 << 1),  /*!< Plugin engine related logs (shall not be used by plugins) */
-    OrthancPluginLogCategory_Http    = (1 << 2),  /*!< HTTP related logs */
-    OrthancPluginLogCategory_Sqlite  = (1 << 3),  /*!< SQLite related logs (shall not be used by plugins) */
-    OrthancPluginLogCategory_Dicom   = (1 << 4),  /*!< DICOM related logs */
-    OrthancPluginLogCategory_Jobs    = (1 << 5),  /*!< jobs related logs */
-    OrthancPluginLogCategory_Lua     = (1 << 6),  /*!< Lua related logs (shall not be used by plugins) */
-
-    // Force the enum to be 32 bits
-    OrthancPluginLogCategory_INTERNAL = 0x7FFFFFFF
-  } OrthancPluginLogCategory;
-
-
-  // note: this structure is also defined in Logging.h and it must be binary compatible
+
   typedef struct
   {
+    /* Note: This structure is also defined in Logging.h and it must be binary compatible */
     const char*               message;
     const char*               plugin;
     const char*               file;
@@ -9524,7 +9536,7 @@
    * @brief Log a message.
    *
    * Log a message using the Orthanc logging system.
-   * 
+   *
    * @param context The Orthanc plugin context, as received by OrthancPluginInitialize().
    * @param message The message to be logged.
    * @param plugin The plugin name.
@@ -9546,8 +9558,8 @@
     m.message = message;
     m.plugin = plugin;
     m.file = file;
+    m.line = line;
     m.category = category;
-    m.line = line;
     m.level = level;
     context->InvokeService(context, _OrthancPluginService_LogMessage, &m);
   }
--- a/OrthancServer/Plugins/Samples/Common/OrthancPluginCppWrapper.cpp	Fri Apr 26 16:01:26 2024 +0200
+++ b/OrthancServer/Plugins/Samples/Common/OrthancPluginCppWrapper.cpp	Fri Apr 26 17:17:34 2024 +0200
@@ -113,6 +113,8 @@
     }
   }
 
+
+#if HAS_ORTHANC_PLUGIN_LOG_MESSAGE == 1
   void LogMessage(OrthancPluginLogLevel level,
                   const char* file,
                   uint32_t line,
@@ -120,7 +122,7 @@
   {
     if (HasGlobalContext())
     {
-#if ORTHANC_PLUGINS_VERSION_IS_ABOVE(1, 12, 4)
+#if HAS_ORTHANC_PLUGIN_LOG_MESSAGE == 1
       const char* pluginName = (pluginName_.empty() ? NULL : pluginName_.c_str());
       OrthancPluginLogMessage(GetGlobalContext(), message.c_str(), pluginName, file, line, OrthancPluginLogCategory_Generic, level);
 #else
@@ -144,6 +146,8 @@
 #endif
     }
   }
+#endif
+
 
   void LogError(const std::string& message)
   {
--- a/OrthancServer/Plugins/Samples/Common/OrthancPluginCppWrapper.h	Fri Apr 26 16:01:26 2024 +0200
+++ b/OrthancServer/Plugins/Samples/Common/OrthancPluginCppWrapper.h	Fri Apr 26 17:17:34 2024 +0200
@@ -53,6 +53,16 @@
 #endif
 
 
+#if !defined(ORTHANC_FRAMEWORK_VERSION_IS_ABOVE)
+#define ORTHANC_FRAMEWORK_VERSION_IS_ABOVE(major, minor, revision)      \
+  (ORTHANC_VERSION_MAJOR > major ||                                     \
+   (ORTHANC_VERSION_MAJOR == major &&                                   \
+    (ORTHANC_VERSION_MINOR > minor ||                                   \
+     (ORTHANC_VERSION_MINOR == minor &&                                 \
+      ORTHANC_VERSION_REVISION >= revision))))
+#endif
+
+
 #if ORTHANC_PLUGINS_VERSION_IS_ABOVE(1, 2, 0)
 // The "OrthancPluginFindMatcher()" primitive was introduced in Orthanc 1.2.0
 #  define HAS_ORTHANC_PLUGIN_FIND_MATCHER  1
@@ -117,16 +127,22 @@
 #  define HAS_ORTHANC_PLUGIN_WEBDAV  0
 #endif
 
+#if ORTHANC_PLUGINS_VERSION_IS_ABOVE(1, 12, 4)
+#  define HAS_ORTHANC_PLUGIN_LOG_MESSAGE  1
+#else
+#  define HAS_ORTHANC_PLUGIN_LOG_MESSAGE  0
+#endif
 
-// Macro "ORTHANC_PLUGINS_DEPRECATED" tags a function as having been deprecated
+
+// Macro to tag a function as having been deprecated
 #if (__cplusplus >= 201402L)  // C++14
-#  define ORTHANC_PLUGINS_DEPRECATED(f) [[deprecated]] f
+#  define ORTHANC_PLUGIN_CPP_WRAPPER_DEPRECATED(f) [[deprecated]] f
 #elif defined(__GNUC__) || defined(__clang__)
-#  define ORTHANC_PLUGINS_DEPRECATED(f) f __attribute__((deprecated))
+#  define ORTHANC_PLUGIN_CPP_WRAPPER_DEPRECATED(f) f __attribute__((deprecated))
 #elif defined(_MSC_VER)
-#  define ORTHANC_PLUGINS_DEPRECATED(f) __declspec(deprecated) f
+#  define ORTHANC_PLUGIN_CPP_WRAPPER_DEPRECATED(f) __declspec(deprecated) f
 #else
-#  define ORTHANC_PLUGINS_DEPRECATED
+#  define ORTHANC_PLUGIN_CPP_WRAPPER_DEPRECATED
 #endif
 
 
@@ -139,9 +155,16 @@
 #  define __ORTHANC_FILE__ __FILE__
 #endif
 
-#define ORTHANC_PLUGINS_LOG_ERROR(msg)   ::OrthancPlugins::LogMessage(OrthancPluginLogLevel_Error, __ORTHANC_FILE__, __LINE__, msg);
-#define ORTHANC_PLUGINS_LOG_WARNING(msg) ::OrthancPlugins::LogMessage(OrthancPluginLogLevel_Warning, __ORTHANC_FILE__, __LINE__, msg);
-#define ORTHANC_PLUGINS_LOG_INFO(msg)    ::OrthancPlugins::LogMessage(OrthancPluginLogLevel_Info, __ORTHANC_FILE__, __LINE__, msg);
+
+#if HAS_ORTHANC_PLUGIN_LOG_MESSAGE == 1
+#  define ORTHANC_PLUGINS_LOG_ERROR(msg)   ::OrthancPlugins::LogMessage(OrthancPluginLogLevel_Error, __ORTHANC_FILE__, __LINE__, msg)
+#  define ORTHANC_PLUGINS_LOG_WARNING(msg) ::OrthancPlugins::LogMessage(OrthancPluginLogLevel_Warning, __ORTHANC_FILE__, __LINE__, msg)
+#  define ORTHANC_PLUGINS_LOG_INFO(msg)    ::OrthancPlugins::LogMessage(OrthancPluginLogLevel_Info, __ORTHANC_FILE__, __LINE__, msg)
+#else
+#  define ORTHANC_PLUGINS_LOG_ERROR(msg)   ::OrthancPlugins::LogError(msg)
+#  define ORTHANC_PLUGINS_LOG_WARNING(msg) ::OrthancPlugins::LogWarning(msg)
+#  define ORTHANC_PLUGINS_LOG_INFO(msg)    ::OrthancPlugins::LogInfo(msg)
+#endif
 
 
 namespace OrthancPlugins
@@ -655,19 +678,33 @@
   const char* AutodetectMimeType(const std::string& path);
 #endif
 
+#if HAS_ORTHANC_PLUGIN_LOG_MESSAGE == 1
   void LogMessage(OrthancPluginLogLevel level,
                   const char* file,
                   uint32_t line,
                   const std::string& message);
+#endif
 
+#if HAS_ORTHANC_PLUGIN_LOG_MESSAGE == 1
   // Use macro ORTHANC_PLUGINS_LOG_ERROR() instead
-  ORTHANC_PLUGINS_DEPRECATED(void LogError(const std::string& message));
+  ORTHANC_PLUGIN_CPP_WRAPPER_DEPRECATED(void LogError(const std::string& message));
+#else
+  void LogError(const std::string& message);
+#endif
 
+#if HAS_ORTHANC_PLUGIN_LOG_MESSAGE == 1
   // Use macro ORTHANC_PLUGINS_LOG_WARNING() instead
-  ORTHANC_PLUGINS_DEPRECATED(void LogWarning(const std::string& message));
+  ORTHANC_PLUGIN_CPP_WRAPPER_DEPRECATED(void LogWarning(const std::string& message));
+#else
+  void LogWarning(const std::string& message);
+#endif
 
+#if HAS_ORTHANC_PLUGIN_LOG_MESSAGE == 1
   // Use macro ORTHANC_PLUGINS_LOG_INFO() instead
-  ORTHANC_PLUGINS_DEPRECATED(void LogInfo(const std::string& message));
+  ORTHANC_PLUGIN_CPP_WRAPPER_DEPRECATED(void LogInfo(const std::string& message));
+#else
+  void LogInfo(const std::string& message);
+#endif
 
   void ReportMinimalOrthancVersion(unsigned int major,
                                    unsigned int minor,