Mercurial > hg > orthanc
changeset 6542:6b9133fa6e88
logged errors/warnings metrics
| author | Alain Mazy <am@orthanc.team> |
|---|---|
| date | Wed, 10 Dec 2025 12:01:24 +0100 |
| parents | 770d6037b79f |
| children | d12e34b27f11 |
| files | NEWS OrthancFramework/Sources/Logging.cpp OrthancFramework/Sources/Logging.h OrthancServer/Sources/main.cpp TODO |
| diffstat | 5 files changed, 87 insertions(+), 4 deletions(-) [+] |
line wrap: on
line diff
--- a/NEWS Tue Dec 09 14:51:25 2025 +0100 +++ b/NEWS Wed Dec 10 12:01:24 2025 +0100 @@ -4,6 +4,13 @@ * Upgraded dependencies for static builds: - boost 1.89.0 +REST API +-------- + +* Added new metrics in "/tools/metrics-prometheus": + - "orthanc_logged_errors_count" + - "orthanc_logged_warnings_count" + Version 1.12.10 (2025-11-26) ============================
--- a/OrthancFramework/Sources/Logging.cpp Tue Dec 09 14:51:25 2025 +0100 +++ b/OrthancFramework/Sources/Logging.cpp Wed Dec 10 12:01:24 2025 +0100 @@ -34,6 +34,7 @@ # include <pthread.h> #endif +#include "MetricsRegistry.h" /********************************************************* * Common section @@ -572,7 +573,8 @@ static boost::recursive_mutex threadNamesMutex_; static std::map<boost::thread::id, std::string> threadNames_; static bool enableThreadNames_ = true; - +static std::list<Orthanc::Logging::ILoggingListener*> loggingListeners_; +static boost::mutex loggingListenersMutex_; namespace Orthanc @@ -706,6 +708,18 @@ return threadNames_[threadId]; } + void AddLoggingListener(ILoggingListener* listener) + { + boost::mutex::scoped_lock lock(loggingListenersMutex_); + loggingListeners_.push_back(listener); + } + + void ClearLoggingListeners() + { + boost::mutex::scoped_lock lock(loggingListenersMutex_); + loggingListeners_.clear(); + } + static void GetLinePrefix(std::string& prefix, LogLevel level, const char* pluginName, // when logging in the core but coming from a plugin, pluginName_ is NULL but this argument is != NULL @@ -1048,8 +1062,15 @@ } else if (stream_ != &nullStream_) { - *stream_ << "\n"; + *stream_ << messageStream_.str() << "\n"; stream_->flush(); + + boost::mutex::scoped_lock lock(loggingListenersMutex_); + for (std::list<Orthanc::Logging::ILoggingListener*>::iterator it = loggingListeners_.begin(); it != loggingListeners_.end(); ++it) + { + (*it)->HandleLog(level_, category_, pluginName_, file_, line_, messageStream_.str()); + } + } }
--- a/OrthancFramework/Sources/Logging.h Tue Dec 09 14:51:25 2025 +0100 +++ b/OrthancFramework/Sources/Logging.h Wed Dec 10 12:01:24 2025 +0100 @@ -74,7 +74,20 @@ LogCategory_JOBS = (1 << 5), LogCategory_LUA = (1 << 6) }; - + + class ILoggingListener + { + public: + virtual ~ILoggingListener() {} + + virtual void HandleLog(LogLevel level, + LogCategory category, + const std::string& pluginName, + const char* file, + uint32_t line, + const std::string& message) = 0; + }; + ORTHANC_PUBLIC const char* EnumerationToString(LogLevel level); ORTHANC_PUBLIC LogLevel StringToLogLevel(const char* level); @@ -97,6 +110,10 @@ ORTHANC_PUBLIC bool HasCurrentThreadName(); + ORTHANC_PUBLIC void AddLoggingListener(ILoggingListener* listener); + + ORTHANC_PUBLIC void ClearLoggingListeners(); + ORTHANC_PUBLIC void EnableThreadNames(bool enabled); ORTHANC_PUBLIC void EnableInfoLevel(bool enabled); @@ -270,6 +287,7 @@ LogCategory category_; const char* file_; uint32_t line_; + std::stringstream messageStream_; public: InternalLogger(LogLevel level, @@ -283,7 +301,7 @@ template <typename T> std::ostream& operator<< (const T& message) { - return (*stream_) << boost::lexical_cast<std::string>(message); + return messageStream_ << boost::lexical_cast<std::string>(message); } };
--- a/OrthancServer/Sources/main.cpp Tue Dec 09 14:51:25 2025 +0100 +++ b/OrthancServer/Sources/main.cpp Wed Dec 10 12:01:24 2025 +0100 @@ -1042,6 +1042,37 @@ return restart; } +// This class makes the bridge between the logging and the metrics +// to count the number of logged errors and warnings +class MetricsLoggingListener : public Orthanc::Logging::ILoggingListener +{ + MetricsRegistry& metrics_; +public: + MetricsLoggingListener(MetricsRegistry& metrics) + : metrics_(metrics) + { + } + + virtual ~MetricsLoggingListener() {}; + + virtual void HandleLog(Orthanc::Logging::LogLevel level, + Orthanc::Logging::LogCategory category, + const std::string& pluginName, + const char* file, + uint32_t line, + const std::string& message) ORTHANC_OVERRIDE + { + if (level == Orthanc::Logging::LogLevel_ERROR) + { + metrics_.IncrementIntegerValue("orthanc_logged_errors_count", 1); + } + else if (level == Orthanc::Logging::LogLevel_WARNING) + { + metrics_.IncrementIntegerValue("orthanc_logged_warnings_count", 1); + } + } + +}; static bool StartHttpServer(ServerContext& context, @@ -1282,8 +1313,13 @@ httpServer.Start(); + MetricsLoggingListener loggingMetrics(context.GetMetricsRegistry()); + Logging::AddLoggingListener(&loggingMetrics); + bool restart = WaitForExit(context, restApi); + Logging::ClearLoggingListeners(); + httpServer.Stop(); LOG(WARNING) << " HTTP server has stopped";
--- a/TODO Tue Dec 09 14:51:25 2025 +0100 +++ b/TODO Wed Dec 10 12:01:24 2025 +0100 @@ -25,6 +25,7 @@ * Toolbox::ComputeMD5() fails on files larger than 4GB * Logging: add more specific information to contextualize the logs. For a DICOM Transfer, that would be nice to include the modality in the context + a study identifier or a job id. + Note that the thread id greatly helps already wrt this topic. * (1) Accept extra DICOM tags dictionaries in the DCMTK format '.dic' (easier to use than declare them in the Orthanc configuration file). Even the standard dictionaries could be overridden by these custom dictionaries.
