changeset 97:ee8a86e2d3cb

added metrics + thread names
author Alain Mazy <am@orthanc.team>
date Thu, 11 Dec 2025 15:08:10 +0100
parents 3e73a429d8fa
children 32a8ecbf7cf1
files Framework/HttpQueries/DetectTransferPlugin.cpp Framework/HttpQueries/HttpQueriesRunner.cpp Framework/HttpQueries/HttpQueriesRunner.h Framework/OrthancInstancesCache.cpp Framework/OrthancInstancesCache.h Framework/PullMode/PullJob.cpp Framework/PushMode/ActivePushTransactions.cpp Framework/PushMode/ActivePushTransactions.h Framework/PushMode/PushJob.cpp NEWS Plugin/Plugin.cpp
diffstat 11 files changed, 144 insertions(+), 11 deletions(-) [+]
line wrap: on
line diff
--- a/Framework/HttpQueries/DetectTransferPlugin.cpp	Tue Dec 09 18:12:15 2025 +0100
+++ b/Framework/HttpQueries/DetectTransferPlugin.cpp	Thu Dec 11 15:08:10 2025 +0100
@@ -96,7 +96,7 @@
     }
 
     {
-      OrthancPlugins::HttpQueriesRunner runner(queue, threadsCount);
+      OrthancPlugins::HttpQueriesRunner runner(queue, threadsCount, "TF-DETECT-");
       queue.WaitComplete();
     }
   }
--- a/Framework/HttpQueries/HttpQueriesRunner.cpp	Tue Dec 09 18:12:15 2025 +0100
+++ b/Framework/HttpQueries/HttpQueriesRunner.cpp	Thu Dec 11 15:08:10 2025 +0100
@@ -22,14 +22,26 @@
 #include "HttpQueriesRunner.h"
 
 #include <OrthancException.h>
+#include <Logging.h>
 
 #include <boost/thread.hpp>
+#include <boost/thread/mutex.hpp>
 
 
 namespace OrthancPlugins
 {
+  static boost::mutex httpThreadsCounterMutex;
+  static uint32_t httpThreadsCounter = 0;
+
+ 
   void HttpQueriesRunner::Worker(HttpQueriesRunner* that)
   {
+    {
+      boost::mutex::scoped_lock lock(httpThreadsCounterMutex);
+      Orthanc::Logging::SetCurrentThreadName(std::string(that->threadNamePrefix_) + boost::lexical_cast<std::string>(httpThreadsCounter++));
+      httpThreadsCounter %= 1000000;
+    }
+
     while (that->continue_)
     {
       size_t size;
@@ -50,18 +62,25 @@
 
 
   HttpQueriesRunner::HttpQueriesRunner(HttpQueriesQueue& queue,
-                                       size_t threadsCount) :
+                                       size_t threadsCount,
+                                       const char* threadNamePrefix10charMax) :
     queue_(queue),
     continue_(true),
     start_(boost::posix_time::microsec_clock::local_time()),
     totalTraffic_(0),
-    lastUpdate_(start_)
+    lastUpdate_(start_),
+    threadNamePrefix_(threadNamePrefix10charMax)
   {
     if (threadsCount == 0)
     {
       throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange);
     }
       
+    if (strlen(threadNamePrefix_) > 10)
+    {
+      throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange);
+    }
+
     workers_.resize(threadsCount);
 
     for (size_t i = 0; i < threadsCount; i++)
--- a/Framework/HttpQueries/HttpQueriesRunner.h	Tue Dec 09 18:12:15 2025 +0100
+++ b/Framework/HttpQueries/HttpQueriesRunner.h	Thu Dec 11 15:08:10 2025 +0100
@@ -39,12 +39,14 @@
     boost::mutex                 mutex_;
     size_t                       totalTraffic_;
     boost::posix_time::ptime     lastUpdate_;
+    const char*                  threadNamePrefix_;
 
     static void Worker(HttpQueriesRunner* that);
 
   public:
     HttpQueriesRunner(HttpQueriesQueue& queue,
-                      size_t threadsCount);
+                      size_t threadsCount,
+                      const char* threadNamePrefix10charMax);
 
     ~HttpQueriesRunner();
 
--- a/Framework/OrthancInstancesCache.cpp	Tue Dec 09 18:12:15 2025 +0100
+++ b/Framework/OrthancInstancesCache.cpp	Thu Dec 11 15:08:10 2025 +0100
@@ -159,7 +159,9 @@
 
   OrthancInstancesCache::OrthancInstancesCache() :
     memorySize_(0),
-    maxMemorySize_(512 * MB)  // 512 MB by default
+    maxMemorySize_(512 * MB),  // 512 MB by default
+    cacheHitCount_(0),
+    cacheMissCount_(0)
   {
   }
     
@@ -221,6 +223,11 @@
       {
         size = accessor.GetInfo().GetSize();
         md5 = accessor.GetInfo().GetMD5();
+
+        {
+          boost::mutex::scoped_lock lock(cacheStatsMutex_);
+          ++cacheHitCount_;
+        }
         return;
       }
     }
@@ -235,6 +242,11 @@
       boost::mutex::scoped_lock lock(mutex_);
       Store(instanceId, instance);
     }
+
+    {
+      boost::mutex::scoped_lock lock(cacheStatsMutex_);
+      ++cacheMissCount_;
+    }
   }
       
     
--- a/Framework/OrthancInstancesCache.h	Tue Dec 09 18:12:15 2025 +0100
+++ b/Framework/OrthancInstancesCache.h	Thu Dec 11 15:08:10 2025 +0100
@@ -68,6 +68,9 @@
     Content        content_;
     size_t         memorySize_;
     size_t         maxMemorySize_;
+    boost::mutex   cacheStatsMutex_;
+    size_t         cacheHitCount_;
+    size_t         cacheMissCount_;
 
 
     // The mutex must be locked!
@@ -106,5 +109,16 @@
                   std::string& md5,
                   const TransferBucket& bucket,
                   size_t chunkIndex);
+
+    size_t GetCacheHitCount() const
+    {
+      return cacheHitCount_;
+    }
+
+    size_t GetCacheMissCount() const
+    {
+      return cacheMissCount_;
+    }
+
   };
 }
--- a/Framework/PullMode/PullJob.cpp	Tue Dec 09 18:12:15 2025 +0100
+++ b/Framework/PullMode/PullJob.cpp	Thu Dec 11 15:08:10 2025 +0100
@@ -120,7 +120,7 @@
     {
       if (runner_.get() == NULL)
       {
-        runner_.reset(new HttpQueriesRunner(queue_, job_.threadsCount_));
+        runner_.reset(new HttpQueriesRunner(queue_, job_.threadsCount_, "TF-PULL-"));
       }
 
       HttpQueriesQueue::Status status = queue_.WaitComplete(200);
--- a/Framework/PushMode/ActivePushTransactions.cpp	Tue Dec 09 18:12:15 2025 +0100
+++ b/Framework/PushMode/ActivePushTransactions.cpp	Thu Dec 11 15:08:10 2025 +0100
@@ -97,6 +97,8 @@
     delete found->second;
     content_.erase(found);
     index_.Invalidate(transactionUuid);
+
+    ++committedTransactionsCount_;
   }
 
 
@@ -111,7 +113,13 @@
       delete it->second;
     }
   }
-    
+   
+  size_t ActivePushTransactions::GetAvailablePushTransactions() const
+  {
+    boost::mutex::scoped_lock  lock(mutex_);
+    return maxSize_ - content_.size();
+  }
+
 
   void ActivePushTransactions::ListTransactions(std::vector<std::string>& target)
   {
@@ -138,10 +146,12 @@
     LOG(INFO) << "Creating transaction to receive " << instances.size()
               << " instances (" << ConvertToMegabytes(tmp->GetDownloadArea().GetTotalSize())
               << "MB) in push mode: " << uuid;
-      
+
     {
       boost::mutex::scoped_lock  lock(mutex_);
 
+      ++createdTransactionsCount_;
+
       // Drop the oldest active transaction, if not enough place
       if (content_.size() == maxSize_)
       {
@@ -155,6 +165,8 @@
         content_.erase(transaction);
 
         LOG(WARNING) << "An inactive push transaction has been discarded: " << oldest;
+      
+        ++abortedTransactionsCount_;
       }
 
       index_.Add(uuid);
--- a/Framework/PushMode/ActivePushTransactions.h	Tue Dec 09 18:12:15 2025 +0100
+++ b/Framework/PushMode/ActivePushTransactions.h	Thu Dec 11 15:08:10 2025 +0100
@@ -37,17 +37,23 @@
     typedef Orthanc::LeastRecentlyUsedIndex<std::string>  Index;
     typedef std::map<std::string, Transaction*>           Content;
 
-    boost::mutex  mutex_;
+    mutable boost::mutex  mutex_;
     Content       content_;
     Index         index_;
     size_t        maxSize_;
+    size_t        createdTransactionsCount_;
+    size_t        committedTransactionsCount_;
+    size_t        abortedTransactionsCount_;
 
     void FinalizeTransaction(const std::string& transactionUuid,
                              bool commit);
 
   public:
     explicit ActivePushTransactions(size_t maxSize) :
-      maxSize_(maxSize)
+      maxSize_(maxSize),
+      createdTransactionsCount_(0),
+      committedTransactionsCount_(0),
+      abortedTransactionsCount_(0)
     {
     }
 
@@ -73,5 +79,22 @@
     {
       FinalizeTransaction(transactionUuid, false);
     }
+
+    size_t GetAvailablePushTransactions() const;
+
+    size_t GetCreatedTransactionsCount() const
+    {
+      return createdTransactionsCount_;
+    }
+
+    size_t GetCommittedTransactionsCount() const
+    {
+      return committedTransactionsCount_;
+    }
+
+    size_t GetAbortedTransactionsCount() const
+    {
+      return abortedTransactionsCount_;
+    }
   };
 }
--- a/Framework/PushMode/PushJob.cpp	Tue Dec 09 18:12:15 2025 +0100
+++ b/Framework/PushMode/PushJob.cpp	Thu Dec 11 15:08:10 2025 +0100
@@ -242,7 +242,7 @@
     {
       if (runner_.get() == NULL)
       {
-        runner_.reset(new HttpQueriesRunner(queue_, job_.threadsCount_));
+        runner_.reset(new HttpQueriesRunner(queue_, job_.threadsCount_, "TF-PUSH-"));
       }
 
       HttpQueriesQueue::Status status = queue_.WaitComplete(200);
--- a/NEWS	Tue Dec 09 18:12:15 2025 +0100
+++ b/NEWS	Thu Dec 11 15:08:10 2025 +0100
@@ -5,6 +5,14 @@
   perform the "commit" phase of a Push/Pull transfer.  A value > 1 is meaningful 
   only if the storage is a distributed network storage (e.g object storage plugin).
   A value of 1 means reading and writing are performed in sequence (default behaviour).
+* new metrics:
+  - orthanc_transfers_used_cache_size_mb
+  - orthanc_transfers_cache_hit_count
+  - orthanc_transfers_cache_miss_count
+  - orthanc_transfers_available_push_transactions_count
+  - orthanc_transfers_created_push_transfers_count
+  - orthanc_transfers_committed_push_transfers_count
+  - orthanc_transfers_aborted_push_transfers_count
 
 
 Version 1.6 (2025-10-07)
--- a/Plugin/Plugin.cpp	Tue Dec 09 18:12:15 2025 +0100
+++ b/Plugin/Plugin.cpp	Thu Dec 11 15:08:10 2025 +0100
@@ -498,6 +498,48 @@
   }
 }
 
+void RefreshMetricsCallback()
+{
+  OrthancPlugins::PluginContext& context = OrthancPlugins::PluginContext::GetInstance();
+
+  OrthancPluginSetMetricsIntegerValue(OrthancPlugins::GetGlobalContext(), 
+                                      "orthanc_transfers_used_cache_size_mb", 
+                                      static_cast<int64_t>(context.GetCache().GetMemorySize() / (1024 * 1024)),
+                                      OrthancPluginMetricsType_Default);
+
+  OrthancPluginSetMetricsIntegerValue(OrthancPlugins::GetGlobalContext(), 
+                                      "orthanc_transfers_cache_hit_count", 
+                                      static_cast<int64_t>(context.GetCache().GetCacheHitCount()),
+                                      OrthancPluginMetricsType_Default);
+
+  OrthancPluginSetMetricsIntegerValue(OrthancPlugins::GetGlobalContext(), 
+                                      "orthanc_transfers_cache_miss_count", 
+                                      static_cast<int64_t>(context.GetCache().GetCacheMissCount()),
+                                      OrthancPluginMetricsType_Default);
+
+  OrthancPluginSetMetricsIntegerValue(OrthancPlugins::GetGlobalContext(), 
+                                      "orthanc_transfers_available_push_transactions_count", 
+                                      static_cast<int64_t>(context.GetActivePushTransactions().GetAvailablePushTransactions()),
+                                      OrthancPluginMetricsType_Default);
+
+  OrthancPluginSetMetricsIntegerValue(OrthancPlugins::GetGlobalContext(), 
+                                      "orthanc_transfers_created_push_transfers_count", 
+                                      static_cast<int64_t>(context.GetActivePushTransactions().GetCreatedTransactionsCount()),
+                                      OrthancPluginMetricsType_Default);
+
+  OrthancPluginSetMetricsIntegerValue(OrthancPlugins::GetGlobalContext(), 
+                                      "orthanc_transfers_committed_push_transfers_count", 
+                                      static_cast<int64_t>(context.GetActivePushTransactions().GetCommittedTransactionsCount()),
+                                      OrthancPluginMetricsType_Default);
+
+  OrthancPluginSetMetricsIntegerValue(OrthancPlugins::GetGlobalContext(), 
+                                      "orthanc_transfers_aborted_push_transfers_count", 
+                                      static_cast<int64_t>(context.GetActivePushTransactions().GetAbortedTransactionsCount()),
+                                      OrthancPluginMetricsType_Default);
+
+
+}
+
 
 OrthancPluginJob* Unserializer(const char* jobType,
                                const char* serialized)
@@ -735,6 +777,7 @@
       }
 
       OrthancPluginRegisterJobsUnserializer(context, Unserializer);
+      OrthancPluginRegisterRefreshMetricsCallback(context, RefreshMetricsCallback);
 
       /* Extend the default Orthanc Explorer with custom JavaScript */
       std::string explorer;