# HG changeset patch # User Sebastien Jodogne # Date 1548779649 -3600 # Node ID 574890d14c92cf4d933fd45eefa4401212742d2e # Parent 8ea7c4546c3a9712fd7727d24c2782e15aedc340 new metrics: orthanc_store_dicom_duration_ms, orthanc_storage_[create|read|remove]_duration_ms diff -r 8ea7c4546c3a -r 574890d14c92 Core/FileStorage/StorageAccessor.cpp --- a/Core/FileStorage/StorageAccessor.cpp Tue Jan 29 15:15:48 2019 +0100 +++ b/Core/FileStorage/StorageAccessor.cpp Tue Jan 29 17:34:09 2019 +0100 @@ -35,16 +35,39 @@ #include "StorageAccessor.h" #include "../Compression/ZlibCompressor.h" +#include "../MetricsRegistry.h" #include "../OrthancException.h" #include "../Toolbox.h" -#include "../Toolbox.h" #if ORTHANC_ENABLE_CIVETWEB == 1 || ORTHANC_ENABLE_MONGOOSE == 1 # include "../HttpServer/HttpStreamTranscoder.h" #endif + +static const std::string METRICS_CREATE = "orthanc_storage_create_duration_ms"; +static const std::string METRICS_READ = "orthanc_storage_read_duration_ms"; +static const std::string METRICS_REMOVE = "orthanc_storage_remove_duration_ms"; + + namespace Orthanc { + class StorageAccessor::MetricsTimer : public boost::noncopyable + { + private: + std::auto_ptr timer_; + + public: + MetricsTimer(StorageAccessor& that, + const std::string& name) + { + if (that.metrics_ != NULL) + { + timer_.reset(new MetricsRegistry::Timer(*that.metrics_, name)); + } + } + }; + + FileInfo StorageAccessor::Write(const void* data, size_t size, FileContentType type, @@ -64,6 +87,8 @@ { case CompressionType_None: { + MetricsTimer timer(*this, METRICS_CREATE); + area_.Create(uuid, data, size, type); return FileInfo(uuid, type, size, md5); } @@ -82,13 +107,17 @@ Toolbox::ComputeMD5(compressedMD5, compressed); } - if (compressed.size() > 0) { - area_.Create(uuid, &compressed[0], compressed.size(), type); - } - else - { - area_.Create(uuid, NULL, 0, type); + MetricsTimer timer(*this, METRICS_CREATE); + + if (compressed.size() > 0) + { + area_.Create(uuid, &compressed[0], compressed.size(), type); + } + else + { + area_.Create(uuid, NULL, 0, type); + } } return FileInfo(uuid, type, size, md5, @@ -108,6 +137,7 @@ { case CompressionType_None: { + MetricsTimer timer(*this, METRICS_READ); area_.Read(content, info.GetUuid(), info.GetContentType()); break; } @@ -117,7 +147,12 @@ ZlibCompressor zlib; std::string compressed; - area_.Read(compressed, info.GetUuid(), info.GetContentType()); + + { + MetricsTimer timer(*this, METRICS_READ); + area_.Read(compressed, info.GetUuid(), info.GetContentType()); + } + IBufferCompressor::Uncompress(content, zlib, compressed); break; } @@ -132,17 +167,19 @@ } - void StorageAccessor::Read(Json::Value& content, - const FileInfo& info) + void StorageAccessor::ReadRaw(std::string& content, + const FileInfo& info) { - std::string s; - Read(s, info); + MetricsTimer timer(*this, METRICS_READ); + area_.Read(content, info.GetUuid(), info.GetContentType()); + } - Json::Reader reader; - if (!reader.parse(s, content)) - { - throw OrthancException(ErrorCode_BadFileFormat); - } + + void StorageAccessor::Remove(const std::string& fileUuid, + FileContentType type) + { + MetricsTimer timer(*this, METRICS_REMOVE); + area_.Remove(fileUuid, type); } @@ -151,7 +188,11 @@ const FileInfo& info, const std::string& mime) { - area_.Read(sender.GetBuffer(), info.GetUuid(), info.GetContentType()); + { + MetricsTimer timer(*this, METRICS_READ); + area_.Read(sender.GetBuffer(), info.GetUuid(), info.GetContentType()); + } + sender.SetContentType(mime); const char* extension; diff -r 8ea7c4546c3a -r 574890d14c92 Core/FileStorage/StorageAccessor.h --- a/Core/FileStorage/StorageAccessor.h Tue Jan 29 15:15:48 2019 +0100 +++ b/Core/FileStorage/StorageAccessor.h Tue Jan 29 17:34:09 2019 +0100 @@ -61,14 +61,23 @@ #include #include #include -#include namespace Orthanc { + class MetricsRegistry; + + /** + * This class handles the compression/decompression of the raw files + * contained in the storage area, and monitors timing metrics (if + * enabled). + **/ class StorageAccessor : boost::noncopyable { private: - IStorageArea& area_; + class MetricsTimer; + + IStorageArea& area_; + MetricsRegistry* metrics_; #if ORTHANC_ENABLE_CIVETWEB == 1 || ORTHANC_ENABLE_MONGOOSE == 1 void SetupSender(BufferHttpSender& sender, @@ -77,7 +86,16 @@ #endif public: - StorageAccessor(IStorageArea& area) : area_(area) + StorageAccessor(IStorageArea& area) : + area_(area), + metrics_(NULL) + { + } + + StorageAccessor(IStorageArea& area, + MetricsRegistry& metrics) : + area_(area), + metrics_(&metrics) { } @@ -99,12 +117,15 @@ void Read(std::string& content, const FileInfo& info); - void Read(Json::Value& content, - const FileInfo& info); + void ReadRaw(std::string& content, + const FileInfo& info); + + void Remove(const std::string& fileUuid, + FileContentType type); void Remove(const FileInfo& info) { - area_.Remove(info.GetUuid(), info.GetContentType()); + Remove(info.GetUuid(), info.GetContentType()); } #if ORTHANC_ENABLE_CIVETWEB == 1 || ORTHANC_ENABLE_MONGOOSE == 1 diff -r 8ea7c4546c3a -r 574890d14c92 Core/MetricsRegistry.cpp --- a/Core/MetricsRegistry.cpp Tue Jan 29 15:15:48 2019 +0100 +++ b/Core/MetricsRegistry.cpp Tue Jan 29 17:34:09 2019 +0100 @@ -41,10 +41,9 @@ { static const boost::posix_time::ptime GetNow() { - return boost::posix_time::second_clock::universal_time(); + return boost::posix_time::microsec_clock::universal_time(); } - class MetricsRegistry::Item { private: diff -r 8ea7c4546c3a -r 574890d14c92 OrthancServer/OrthancRestApi/OrthancRestApi.cpp --- a/OrthancServer/OrthancRestApi/OrthancRestApi.cpp Tue Jan 29 15:15:48 2019 +0100 +++ b/OrthancServer/OrthancRestApi/OrthancRestApi.cpp Tue Jan 29 17:34:09 2019 +0100 @@ -35,6 +35,7 @@ #include "OrthancRestApi.h" #include "../../Core/Logging.h" +#include "../../Core/MetricsRegistry.h" #include "../../Core/SerializationToolbox.h" #include "../ServerContext.h" @@ -156,6 +157,24 @@ } + bool OrthancRestApi::Handle(HttpOutput& output, + RequestOrigin origin, + const char* remoteIp, + const char* username, + HttpMethod method, + const UriComponents& uri, + const Arguments& headers, + const GetArguments& getArguments, + const char* bodyData, + size_t bodySize) + { + MetricsRegistry::Timer timer(context_.GetMetricsRegistry(), "orthanc_rest_api_duration_ms"); + + return RestApi::Handle(output, origin, remoteIp, username, method, + uri, headers, getArguments, bodyData, bodySize); + } + + ServerContext& OrthancRestApi::GetContext(RestApiCall& call) { return GetApi(call).context_; diff -r 8ea7c4546c3a -r 574890d14c92 OrthancServer/OrthancRestApi/OrthancRestApi.h --- a/OrthancServer/OrthancRestApi/OrthancRestApi.h Tue Jan 29 15:15:48 2019 +0100 +++ b/OrthancServer/OrthancRestApi/OrthancRestApi.h Tue Jan 29 17:34:09 2019 +0100 @@ -75,6 +75,17 @@ public: OrthancRestApi(ServerContext& context); + virtual bool Handle(HttpOutput& output, + RequestOrigin origin, + const char* remoteIp, + const char* username, + HttpMethod method, + const UriComponents& uri, + const Arguments& headers, + const GetArguments& getArguments, + const char* bodyData, + size_t bodySize) ORTHANC_OVERRIDE; + const bool& LeaveBarrierFlag() const { return leaveBarrier_; diff -r 8ea7c4546c3a -r 574890d14c92 OrthancServer/ServerContext.cpp --- a/OrthancServer/ServerContext.cpp Tue Jan 29 15:15:48 2019 +0100 +++ b/OrthancServer/ServerContext.cpp Tue Jan 29 17:34:09 2019 +0100 @@ -322,7 +322,8 @@ void ServerContext::RemoveFile(const std::string& fileUuid, FileContentType type) { - area_.Remove(fileUuid, type); + StorageAccessor accessor(area_, GetMetricsRegistry()); + accessor.Remove(fileUuid, type); } @@ -331,7 +332,8 @@ { try { - StorageAccessor accessor(area_); + MetricsRegistry::Timer timer(GetMetricsRegistry(), "orthanc_store_dicom_duration_ms"); + StorageAccessor accessor(area_, GetMetricsRegistry()); resultPublicId = dicom.GetHasher().HashInstance(); @@ -472,7 +474,7 @@ throw OrthancException(ErrorCode_UnknownResource); } - StorageAccessor accessor(area_); + StorageAccessor accessor(area_, GetMetricsRegistry()); accessor.AnswerFile(output, attachment, GetFileContentMime(content)); } @@ -500,7 +502,7 @@ std::string content; - StorageAccessor accessor(area_); + StorageAccessor accessor(area_, GetMetricsRegistry()); accessor.Read(content, attachment); FileInfo modified = accessor.Write(content.empty() ? NULL : content.c_str(), @@ -616,15 +618,18 @@ " of instance " + instancePublicId); } + assert(attachment.GetContentType() == content); + if (uncompressIfNeeded) { ReadAttachment(result, attachment); } else { - // Do not interpret the content of the storage area, return the + // Do not uncompress the content of the storage area, return the // raw data - area_.Read(result, attachment.GetUuid(), content); + StorageAccessor accessor(area_, GetMetricsRegistry()); + accessor.ReadRaw(result, attachment); } } @@ -633,7 +638,7 @@ const FileInfo& attachment) { // This will decompress the attachment - StorageAccessor accessor(area_); + StorageAccessor accessor(area_, GetMetricsRegistry()); accessor.Read(result, attachment); } @@ -683,7 +688,7 @@ // TODO Should we use "gzip" instead? CompressionType compression = (compressionEnabled_ ? CompressionType_ZlibWithSize : CompressionType_None); - StorageAccessor accessor(area_); + StorageAccessor accessor(area_, GetMetricsRegistry()); FileInfo attachment = accessor.Write(data, size, attachmentType, compression, storeMD5_); StoreStatus status = index_.AddAttachment(attachment, resourceId);