Mercurial > hg > orthanc
changeset 7162:e72e3adae0cc
warnings can now be disabled directly in the Logging classes making it available to the OrthancFramework as well + added W101_TruncatingDicomTagTo256Values
| author | Alain Mazy <am@orthanc.team> |
|---|---|
| date | Tue, 29 Sep 2026 16:25:10 +0200 |
| parents | f696c8086d5e |
| children | 5e8003d46cf5 |
| files | NEWS OrthancFramework/Sources/DicomParsing/FromDcmtkBridge.cpp OrthancFramework/Sources/Logging.cpp OrthancFramework/Sources/Logging.h OrthancServer/Plugins/Engine/PluginsManager.cpp OrthancServer/Resources/AdvancedConfiguration.json OrthancServer/Sources/OrthancConfiguration.cpp OrthancServer/Sources/OrthancConfiguration.h OrthancServer/Sources/ResourceFinder.cpp OrthancServer/Sources/ResourceFinder.h OrthancServer/Sources/ServerContext.cpp OrthancServer/Sources/ServerEnumerations.h OrthancServer/Sources/main.cpp |
| diffstat | 13 files changed, 105 insertions(+), 137 deletions(-) [+] |
line wrap: on
line diff
--- a/NEWS Mon Sep 28 16:20:59 2026 +0200 +++ b/NEWS Tue Sep 29 16:25:10 2026 +0200 @@ -30,6 +30,8 @@ * Added more tolerance to invalid OW value representations * Fixed handling of "DicomModalities.LocalAet" handling in /modalities/../find-worklists (https://discourse.orthanc-server.org/t/find-worklist-with-localaet-from-modality-configuration/6482) +* Added new warnings that can be disabled in the configuration: + - W101_TruncatingDicomTagTo256Values * Fix use of the static runtime under Visual Studio (/MT), which broke in 1.12.10 * New CMake options: - "THIRD_PARTY_DOWNLOADS_ROOT_URL" to specify another webserver to downloads the third-parties from.
--- a/OrthancFramework/Sources/DicomParsing/FromDcmtkBridge.cpp Mon Sep 28 16:20:59 2026 +0200 +++ b/OrthancFramework/Sources/DicomParsing/FromDcmtkBridge.cpp Tue Sep 29 16:25:10 2026 +0200 @@ -677,7 +677,7 @@ **/ DicomTag t(tag.getGroup(), tag.getElement()); - LOG(WARNING) << "Truncating the DICOM tag " << t.Format() << " containing " + LOG_WARNING("W101") << "Truncating the DICOM tag " << t.Format() << " containing " << size << " values to " << maxBinaryArrayLength << " values"; size = maxBinaryArrayLength; }
--- a/OrthancFramework/Sources/Logging.cpp Mon Sep 28 16:20:59 2026 +0200 +++ b/OrthancFramework/Sources/Logging.cpp Tue Sep 29 16:25:10 2026 +0200 @@ -30,6 +30,9 @@ #include <cassert> #include <stdint.h> #include <string.h> +#include <boost/thread/shared_mutex.hpp> +#include <boost/thread/lock_types.hpp> // For boost::unique_lock<> and boost::shared_lock<> + #if defined(__linux__) && !defined(NDEBUG) # include <pthread.h> @@ -52,6 +55,8 @@ static uint32_t traceCategoriesMask_ = 0; static std::string logTargetFolder_; // keep a track of the log folder in case of reset of the context static std::string logTargetFile_; // keep a track of the log file in case of reset of the context + static boost::shared_mutex messageIdsMutex_; + static std::set<std::string> disabledMessageIds_; const char* EnumerationToString(LogLevel level) { @@ -141,6 +146,28 @@ return (traceCategoriesMask_ != 0); } + void SetMessageIdEnabled(const std::string& messageId, + bool enabled) + { + boost::unique_lock<boost::shared_mutex> lock(messageIdsMutex_); + + if (enabled) + { + disabledMessageIds_.erase(messageId); + } + else + { + disabledMessageIds_.insert(messageId); + } + } + + bool IsMessageIdEnabled(const std::string& messageId) + { + boost::shared_lock<boost::shared_mutex> lock(messageIdsMutex_); + + return disabledMessageIds_.find(messageId) == disabledMessageIds_.end(); + } + void SetCategoryEnabled(LogLevel level, LogCategory category, @@ -953,7 +980,6 @@ static std::list<Orthanc::Logging::ILoggingListener*> loggingListeners_; static boost::shared_mutex loggingListenersMutex_; - namespace Orthanc { namespace Logging @@ -1413,13 +1439,15 @@ LogCategory category, const char* pluginName, const char* file, - int line) : + int line, + const char* messageId) : pimpl_(new PImpl), level_(level), stream_(&nullStream_), // By default, logging to "/dev/null" is simulated category_(category), file_(file), - line_(line) + line_(line), + messageId_(messageId) { if (pluginContext_ != NULL) { @@ -1447,9 +1475,9 @@ { // We are logging in a standalone application, not inside an Orthanc plugin - if (!IsCategoryEnabled(level_, category)) + if (!IsCategoryEnabled(level_, category) || (messageId_ != NULL && !IsMessageIdEnabled(messageId_))) { - // This logging level is disabled, directly exit as the + // This logging level or specific message is disabled, directly exit as the // stream is set to "/dev/null" return; } @@ -1502,6 +1530,11 @@ try { (*stream_) << prefix; + + if (messageId_ != NULL) + { + (*stream_) << messageId_ << ": "; + } } catch (...) { @@ -1573,7 +1606,7 @@ { try { - (*it)->HandleLog(level_, category_, pluginName_, file_, line_, messageStream_.str()); + (*it)->HandleLog(level_, category_, pluginName_, file_, line_, messageStream_.str(), messageId_); } catch (...) // NOLINT(bugprone-empty-catch) {
--- a/OrthancFramework/Sources/Logging.h Mon Sep 28 16:20:59 2026 +0200 +++ b/OrthancFramework/Sources/Logging.h Tue Sep 29 16:25:10 2026 +0200 @@ -113,7 +113,8 @@ const std::string& pluginName, const char* file, uint32_t line, - const std::string& message) = 0; + const std::string& message, + const char* messageId) = 0; }; @@ -173,6 +174,11 @@ ORTHANC_PUBLIC bool LookupCategory(LogCategory& target, const std::string& category); + ORTHANC_PUBLIC void SetMessageIdEnabled(const std::string& messageId, + bool enabled); + + ORTHANC_PUBLIC bool IsMessageIdEnabled(const std::string& messageId); + ORTHANC_PUBLIC unsigned int GetCategoriesCount(); ORTHANC_PUBLIC const char* GetCategoryName(unsigned int i); @@ -247,9 +253,10 @@ #if ORTHANC_ENABLE_LOGGING != 1 # define LOG(level) ::Orthanc::Logging::NullStream() +# define LOG_WARNING(warningId) ::Orthanc::Logging::NullStream() # define VLOG(unused) ::Orthanc::Logging::NullStream() # define CLOG(level, category) ::Orthanc::Logging::NullStream() -# define LOG_FROM_PLUGIN(level, category, pluginName, file, line) ::Orthanc::Logging::NullStream() +# define LOG_FROM_PLUGIN(level, category, pluginName, file, line, messageId) ::Orthanc::Logging::NullStream() #else /* ORTHANC_ENABLE_LOGGING == 1 */ #if !defined(__ORTHANC_FILE__) @@ -264,20 +271,25 @@ # define LOG(level) ::Orthanc::Logging::InternalLogger \ (::Orthanc::Logging::LogLevel_ ## level, \ ::Orthanc::Logging::LogCategory_GENERIC, NULL /* no plugin */, \ - __ORTHANC_FILE__, __LINE__) + __ORTHANC_FILE__, __LINE__, NULL) + +# define LOG_WARNING(warningId) ::Orthanc::Logging::InternalLogger \ + (::Orthanc::Logging::LogLevel_WARNING, \ + ::Orthanc::Logging::LogCategory_GENERIC, NULL /* no plugin */, \ + __ORTHANC_FILE__, __LINE__, warningId) # define VLOG(unused) ::Orthanc::Logging::InternalLogger \ (::Orthanc::Logging::LogLevel_TRACE, \ ::Orthanc::Logging::LogCategory_GENERIC, NULL /* no plugin */, \ - __ORTHANC_FILE__, __LINE__) + __ORTHANC_FILE__, __LINE__, NULL) # define CLOG(level, category) ::Orthanc::Logging::InternalLogger \ (::Orthanc::Logging::LogLevel_ ## level, \ ::Orthanc::Logging::LogCategory_ ## category, NULL /* no plugin */, \ - __ORTHANC_FILE__, __LINE__) + __ORTHANC_FILE__, __LINE__, NULL) -# define LOG_FROM_PLUGIN(level, category, pluginName, file, line) \ - ::Orthanc::Logging::InternalLogger(level, category, pluginName, file, line) +# define LOG_FROM_PLUGIN(level, category, pluginName, file, line, messageId) \ + ::Orthanc::Logging::InternalLogger(level, category, pluginName, file, line, messageId) #endif @@ -305,7 +317,8 @@ LogCategory category, const char* pluginName /* ignored */, const char* file /* ignored */, - int line /* ignored */) : + int line /* ignored */, + const char* messageId /* ignored */) : level_(level), category_(category) { @@ -346,13 +359,15 @@ const char* file_; uint32_t line_; std::stringstream messageStream_; + const char* messageId_; public: InternalLogger(LogLevel level, LogCategory category, const char* pluginName, const char* file, - int line); + int line, + const char* messageId); ~InternalLogger();
--- a/OrthancServer/Plugins/Engine/PluginsManager.cpp Mon Sep 28 16:20:59 2026 +0200 +++ b/OrthancServer/Plugins/Engine/PluginsManager.cpp Tue Sep 29 16:25:10 2026 +0200 @@ -171,7 +171,7 @@ Orthanc::Logging::LogLevel level = static_cast<Orthanc::Logging::LogLevel>(m.level); Orthanc::Logging::LogCategory category = static_cast<Orthanc::Logging::LogCategory>(m.category); - LOG_FROM_PLUGIN(level, category, m.plugin, m.file, m.line) << m.message; + LOG_FROM_PLUGIN(level, category, m.plugin, m.file, m.line, NULL) << m.message; return OrthancPluginErrorCode_Success; }
--- a/OrthancServer/Resources/AdvancedConfiguration.json Mon Sep 28 16:20:59 2026 +0200 +++ b/OrthancServer/Resources/AdvancedConfiguration.json Tue Sep 29 16:25:10 2026 +0200 @@ -15,6 +15,8 @@ // "true" enables a warning. All warnings are enabled by default // see https://orthanc.uclouvain.be/book/faq/main-dicom-tags.html#warnings // (new in Orthanc 1.11.0) + // Note, from Orthanc 1.13.1, only the WXXX prefix is relevant. The text + // following the underscore is ignored. "Warnings" : { // A "RequestedTags" has been read from storage which is slower than // reading it from DB. @@ -55,7 +57,11 @@ // Display a warning when a user requests a tag that can not be read from disk // because "StorageAccessOnFind" is set to "Never". // (new in Orthanc 1.12.5) - "W007_MissingRequestedTagsNotReadFromDisk" : true + "W007_MissingRequestedTagsNotReadFromDisk" : true, + + // Display a warning when Orthanc is truncating DICOMTag whose multiplicity is + // higher than 256 values when converting the tags to JSON. + "W101_TruncatingDicomTagTo256Values" : true }, // Path to the directory where Orthanc stores its large temporary
--- a/OrthancServer/Sources/OrthancConfiguration.cpp Mon Sep 28 16:20:59 2026 +0200 +++ b/OrthancServer/Sources/OrthancConfiguration.cpp Tue Sep 29 16:25:10 2026 +0200 @@ -1367,54 +1367,23 @@ for (size_t i = 0; i < members.size(); i++) { - const std::string& name = members[i]; + const std::string& name = members[i]; // name is something like W001_TagsBeingReadFromStorage or W123 bool enabled = warnings[name].asBool(); - Warnings warning = Warnings_None; - if (name == "W001_TagsBeingReadFromStorage") - { - warning = Warnings_001_TagsBeingReadFromStorage; - } - else if (name == "W002_InconsistentDicomTagsInDb") - { - warning = Warnings_002_InconsistentDicomTagsInDb; - } - else if (name == "W003_DecoderFailure") - { - warning = Warnings_003_DecoderFailure; - } - else if (name == "W004_NoMainDicomTagsSignature") + std::vector<std::string> splitName; + Toolbox::SplitString(splitName, name, '_'); + + if (splitName.size() >= 1) { - warning = Warnings_004_NoMainDicomTagsSignature; - } - else if (name == "W005_RequestingTagFromLowerResourceLevel") - { - warning = Warnings_005_RequestingTagFromLowerResourceLevel; - } - else if (name == "W006_RequestingTagFromMetaHeader") - { - warning = Warnings_006_RequestingTagFromMetaHeader; - } - else if (name == "W007_MissingRequestedTagsNotReadFromDisk") - { - warning = Warnings_007_MissingRequestedTagsNotReadFromDisk; - } - else - { - throw OrthancException(ErrorCode_BadFileFormat, name + " is not recognized as a valid warning name"); + Logging::SetMessageIdEnabled(splitName[0], enabled); + if (!enabled) + { + LOG(WARNING) << "Disabling warning '" << splitName[0] << "'"; + } } - if (!enabled) - { - disabledWarnings_.insert(warning); - } } } - else - { - disabledWarnings_.clear(); - } - }
--- a/OrthancServer/Sources/OrthancConfiguration.h Mon Sep 28 16:20:59 2026 +0200 +++ b/OrthancServer/Sources/OrthancConfiguration.h Tue Sep 29 16:25:10 2026 +0200 @@ -96,7 +96,6 @@ Peers peers_; JobsEngineThreadsCount jobsEngineThreadsCount_; ServerIndex* serverIndex_; - std::set<Warnings> disabledWarnings_; OrthancConfiguration(); @@ -297,11 +296,6 @@ std::string GetDatabaseServerIdentifier() const; - bool IsWarningEnabled(Warnings warning) const - { - return disabledWarnings_.count(warning) == 0; - } - std::string GetOrthancAET() const; std::string GetMaximumStorageMode() const
--- a/OrthancServer/Sources/ResourceFinder.cpp Mon Sep 28 16:20:59 2026 +0200 +++ b/OrthancServer/Sources/ResourceFinder.cpp Tue Sep 29 16:25:10 2026 +0200 @@ -565,18 +565,8 @@ limitsCount_(0), responseContent_(responseContent), storageAccessMode_(storageAccessMode), - supportsChildExistQueries_(supportsChildExistQueries), - isWarning002Enabled_(false), - isWarning004Enabled_(false), - isWarning005Enabled_(false) + supportsChildExistQueries_(supportsChildExistQueries) { - { - OrthancConfiguration::ReaderLock lock; - isWarning002Enabled_ = lock.GetConfiguration().IsWarningEnabled(Warnings_002_InconsistentDicomTagsInDb); - isWarning004Enabled_ = lock.GetConfiguration().IsWarningEnabled(Warnings_004_NoMainDicomTagsSignature); - isWarning005Enabled_ = lock.GetConfiguration().IsWarningEnabled(Warnings_005_RequestingTagFromLowerResourceLevel); - } - request_.SetRetrieveMainDicomTags(responseContent_ & ResponseContentFlags_MainDicomTags); request_.SetRetrieveMetadata((responseContent_ & ResponseContentFlags_Metadata) || (responseContent_ & ResponseContentFlags_MetadataLegacy)); request_.SetRetrieveLabels(responseContent_ & ResponseContentFlags_Labels); @@ -740,11 +730,9 @@ { if (request_.GetLevel() == ResourceType_Patient) { - if (isWarning005Enabled_) - { - LOG(WARNING) << "W005: Requested tag " << tag.Format() - << " should only be read at the study, series, or instance level"; - } + LOG_WARNING("W005") << "Requested tag " << tag.Format() + << " should only be read at the study, series, or instance level"; + request_.SetRetrieveOneInstanceMetadataAndAttachments(true); // we might need to get it from one instance } else @@ -765,11 +753,9 @@ if (request_.GetLevel() == ResourceType_Patient || request_.GetLevel() == ResourceType_Study) { - if (isWarning005Enabled_) - { - LOG(WARNING) << "W005: Requested tag " << tag.Format() - << " should only be read at the series or instance level"; - } + LOG_WARNING("W005") << "Requested tag " << tag.Format() + << " should only be read at the series or instance level"; + request_.SetRetrieveOneInstanceMetadataAndAttachments(true); // we might need to get it from one instance } else @@ -791,11 +777,9 @@ request_.GetLevel() == ResourceType_Study || request_.GetLevel() == ResourceType_Series) { - if (isWarning005Enabled_) - { - LOG(WARNING) << "W005: Requested tag " << tag.Format() - << " should only be read at the instance level"; - } + LOG_WARNING("W005") << "Requested tag " << tag.Format() + << " should only be read at the instance level"; + request_.SetRetrieveOneInstanceMetadataAndAttachments(true); // we might need to get it from one instance } else @@ -941,13 +925,11 @@ const FindResponse::Resource& resource, const std::set<DicomTag>& missingTags) { - OrthancConfiguration::ReaderLock lock; - if (lock.GetConfiguration().IsWarningEnabled(Warnings_001_TagsBeingReadFromStorage)) { std::string missings; FromDcmtkBridge::FormatListOfTags(missings, missingTags); - LOG(WARNING) << "W001: Accessing DICOM tags from storage when accessing " + LOG_WARNING("W001") << "Accessing DICOM tags from storage when accessing " << Orthanc::GetResourceTypeText(resource.GetLevel(), false, false) << " " << resource.GetIdentifier() << ": " << missings; @@ -1065,19 +1047,6 @@ "Unable to use 'Since' when finding resources when querying against Dicom Tags that are not in the MainDicomTags or when using CaseSenstive queries."); } - bool isWarning002Enabled = false; - bool isWarning004Enabled = false; - bool isWarning006Enabled = false; - bool isWarning007Enabled = false; - - { - OrthancConfiguration::ReaderLock lock; - isWarning002Enabled = lock.GetConfiguration().IsWarningEnabled(Warnings_002_InconsistentDicomTagsInDb); - isWarning004Enabled = lock.GetConfiguration().IsWarningEnabled(Warnings_004_NoMainDicomTagsSignature); - isWarning006Enabled = lock.GetConfiguration().IsWarningEnabled(Warnings_006_RequestingTagFromMetaHeader); - isWarning007Enabled = lock.GetConfiguration().IsWarningEnabled(Warnings_007_MissingRequestedTagsNotReadFromDisk); - } - FindResponse response; context.GetIndex().ExecuteFind(response, request_); @@ -1144,11 +1113,10 @@ } } - if (isWarning006Enabled) { std::string joinedMetaTags; FromDcmtkBridge::FormatListOfTags(joinedMetaTags, metaTagsToRemove); - LOG(WARNING) << "W006: Unable to include tags from the Meta Header in \"RequestedTags\". Skipping them: " << joinedMetaTags; + LOG_WARNING("W006") << "Unable to include tags from the Meta Header in \"RequestedTags\". Skipping them: " << joinedMetaTags; } Toolbox::RemoveSets(remainingRequestedTags, metaTagsToRemove); @@ -1173,30 +1141,30 @@ { ReadMissingTagsFromStorageArea(outRequestedTags, context, request_, resource, remainingRequestedTags); } - else if (isWarning007Enabled) + else { std::string joinedTags; FromDcmtkBridge::FormatListOfTags(joinedTags, remainingRequestedTags); - LOG(WARNING) << "W007: Unable to include requested tags since \"StorageAccessOnFind\" does not allow accessing the storage to build answers: " << joinedTags; + LOG_WARNING("W007") << "Unable to include requested tags since \"StorageAccessOnFind\" does not allow accessing the storage to build answers: " << joinedTags; } } std::string mainDicomTagsSignature; - if (isWarning002Enabled && + if (Logging::IsMessageIdEnabled("W002") && resource.LookupMetadata(mainDicomTagsSignature, resource.GetLevel(), MetadataType_MainDicomTagsSignature) && mainDicomTagsSignature != DicomMap::GetMainDicomTagsSignature(resource.GetLevel())) { - LOG(WARNING) << "W002: " << Orthanc::GetResourceTypeText(resource.GetLevel(), false , false) + LOG_WARNING("W002") << Orthanc::GetResourceTypeText(resource.GetLevel(), false , false) << " has been stored with another version of Main Dicom Tags list, you should POST to /" << Orthanc::GetResourceTypeText(resource.GetLevel(), true, false) << "/" << resource.GetIdentifier() << "/reconstruct to update the list of tags saved in DB or run the Housekeeper plugin. Some MainDicomTags might be missing from this answer."; } - else if (isWarning004Enabled && + else if (Logging::IsMessageIdEnabled("W004") && request_.IsRetrieveMetadata() && !resource.LookupMetadata(mainDicomTagsSignature, resource.GetLevel(), MetadataType_MainDicomTagsSignature)) { - LOG(WARNING) << "W004: " << Orthanc::GetResourceTypeText(resource.GetLevel(), false , false) + LOG_WARNING("W004") << Orthanc::GetResourceTypeText(resource.GetLevel(), false , false) << " has been stored with an old Orthanc version and does not have a MainDicomTagsSignature, you should POST to /" << Orthanc::GetResourceTypeText(resource.GetLevel(), true, false) << "/" << resource.GetIdentifier()
--- a/OrthancServer/Sources/ResourceFinder.h Mon Sep 28 16:20:59 2026 +0200 +++ b/OrthancServer/Sources/ResourceFinder.h Tue Sep 29 16:25:10 2026 +0200 @@ -72,10 +72,6 @@ std::set<DicomTag> requestedTags_; std::set<DicomTag> requestedComputedTags_; - bool isWarning002Enabled_; - bool isWarning004Enabled_; - bool isWarning005Enabled_; - bool IsRequestedComputedTag(const DicomTag& tag) const { return requestedComputedTags_.find(tag) != requestedComputedTags_.end();
--- a/OrthancServer/Sources/ServerContext.cpp Mon Sep 28 16:20:59 2026 +0200 +++ b/OrthancServer/Sources/ServerContext.cpp Tue Sep 29 16:25:10 2026 +0200 @@ -2211,11 +2211,7 @@ if (decoded.get() == NULL) { - OrthancConfiguration::ReaderLock configLock; - if (configLock.GetConfiguration().IsWarningEnabled(Warnings_003_DecoderFailure)) - { - LOG(WARNING) << "W003: Unable to decode frame " << frameIndex << " from instance " << instancePublicId; - } + LOG_WARNING("W003") << "Unable to decode frame " << frameIndex << " from instance " << instancePublicId; throw OrthancException(ErrorCode_NotImplemented); }
--- a/OrthancServer/Sources/ServerEnumerations.h Mon Sep 28 16:20:59 2026 +0200 +++ b/OrthancServer/Sources/ServerEnumerations.h Tue Sep 29 16:25:10 2026 +0200 @@ -252,18 +252,6 @@ BuiltinDecoderTranscoderOrder_Disabled }; - enum Warnings - { - Warnings_None, - Warnings_001_TagsBeingReadFromStorage, - Warnings_002_InconsistentDicomTagsInDb, - Warnings_003_DecoderFailure, // new in Orthanc 1.12.5 - Warnings_004_NoMainDicomTagsSignature, // new in Orthanc 1.12.5 - Warnings_005_RequestingTagFromLowerResourceLevel, // new in Orthanc 1.12.5 - Warnings_006_RequestingTagFromMetaHeader, // new in Orthanc 1.12.5 - Warnings_007_MissingRequestedTagsNotReadFromDisk // new in Orthanc 1.12.5 - }; - enum QueueOrigin { QueueOrigin_Front,
--- a/OrthancServer/Sources/main.cpp Mon Sep 28 16:20:59 2026 +0200 +++ b/OrthancServer/Sources/main.cpp Tue Sep 29 16:25:10 2026 +0200 @@ -1112,7 +1112,8 @@ const std::string& pluginName, const char* file, uint32_t line, - const std::string& message) ORTHANC_OVERRIDE + const std::string& message, + const char* messageId) ORTHANC_OVERRIDE { if (level == Orthanc::Logging::LogLevel_ERROR) {
