Mercurial > hg > orthanc
view Core/MetricsRegistry.cpp @ 3341:8f44dadcdbc1
Fix issue #138 (POST to modalities/{name} accepts invalid characters)
author | Sebastien Jodogne <s.jodogne@gmail.com> |
---|---|
date | Fri, 05 Apr 2019 13:02:57 +0200 |
parents | 784bbb03fb54 |
children | 596cfabd72c5 |
line wrap: on
line source
/** * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium * Copyright (C) 2017-2019 Osimis S.A., Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation, either version 3 of the * License, or (at your option) any later version. * * In addition, as a special exception, the copyright holders of this * program give permission to link the code of its release with the * OpenSSL project's "OpenSSL" library (or with modified versions of it * that use the same license as the "OpenSSL" library), and distribute * the linked executables. You must obey the GNU General Public License * in all respects for all of the code used other than "OpenSSL". If you * modify file(s) with this exception, you may extend this exception to * your version of the file(s), but you are not obligated to do so. If * you do not wish to do so, delete this exception statement from your * version. If you delete this exception statement from all source files * in the program, then also delete it here. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. **/ #include "PrecompiledHeaders.h" #include "MetricsRegistry.h" #include "OrthancException.h" #include "ChunkedBuffer.h" namespace Orthanc { static const boost::posix_time::ptime GetNow() { return boost::posix_time::microsec_clock::universal_time(); } class MetricsRegistry::Item { private: MetricsType type_; boost::posix_time::ptime time_; bool hasValue_; float value_; void Touch(float value, const boost::posix_time::ptime& now) { hasValue_ = true; value_ = value; time_ = now; } void Touch(float value) { Touch(value, GetNow()); } void UpdateMax(float value, int duration) { if (hasValue_) { const boost::posix_time::ptime now = GetNow(); if (value > value_ || (now - time_).total_seconds() > duration) { Touch(value, now); } } else { Touch(value); } } void UpdateMin(float value, int duration) { if (hasValue_) { const boost::posix_time::ptime now = GetNow(); if (value < value_ || (now - time_).total_seconds() > duration) { Touch(value, now); } } else { Touch(value); } } public: Item(MetricsType type) : type_(type), hasValue_(false) { } MetricsType GetType() const { return type_; } void Update(float value) { switch (type_) { case MetricsType_Default: Touch(value); break; case MetricsType_MaxOver10Seconds: UpdateMax(value, 10); break; case MetricsType_MaxOver1Minute: UpdateMax(value, 60); break; case MetricsType_MinOver10Seconds: UpdateMin(value, 10); break; case MetricsType_MinOver1Minute: UpdateMin(value, 60); break; default: throw OrthancException(ErrorCode_NotImplemented); } } bool HasValue() const { return hasValue_; } const boost::posix_time::ptime& GetTime() const { if (hasValue_) { return time_; } else { throw OrthancException(ErrorCode_BadSequenceOfCalls); } } float GetValue() const { if (hasValue_) { return value_; } else { throw OrthancException(ErrorCode_BadSequenceOfCalls); } } }; MetricsRegistry::~MetricsRegistry() { for (Content::iterator it = content_.begin(); it != content_.end(); ++it) { assert(it->second != NULL); delete it->second; } } void MetricsRegistry::SetEnabled(bool enabled) { boost::mutex::scoped_lock lock(mutex_); enabled_ = enabled; } void MetricsRegistry::Register(const std::string& name, MetricsType type) { boost::mutex::scoped_lock lock(mutex_); Content::iterator found = content_.find(name); if (found == content_.end()) { content_[name] = new Item(type); } else { assert(found->second != NULL); // This metrics already exists: Only recreate it if there is a // mismatch in the type of metrics if (found->second->GetType() != type) { delete found->second; found->second = new Item(type); } } } void MetricsRegistry::SetValueInternal(const std::string& name, float value, MetricsType type) { boost::mutex::scoped_lock lock(mutex_); Content::iterator found = content_.find(name); if (found == content_.end()) { std::auto_ptr<Item> item(new Item(type)); item->Update(value); content_[name] = item.release(); } else { assert(found->second != NULL); found->second->Update(value); } } MetricsType MetricsRegistry::GetMetricsType(const std::string& name) { boost::mutex::scoped_lock lock(mutex_); Content::const_iterator found = content_.find(name); if (found == content_.end()) { throw OrthancException(ErrorCode_InexistentItem); } else { assert(found->second != NULL); return found->second->GetType(); } } void MetricsRegistry::ExportPrometheusText(std::string& s) { // https://www.boost.org/doc/libs/1_69_0/doc/html/date_time/examples.html#date_time.examples.seconds_since_epoch static const boost::posix_time::ptime EPOCH(boost::gregorian::date(1970, 1, 1)); boost::mutex::scoped_lock lock(mutex_); s.clear(); if (!enabled_) { return; } ChunkedBuffer buffer; for (Content::const_iterator it = content_.begin(); it != content_.end(); ++it) { assert(it->second != NULL); if (it->second->HasValue()) { boost::posix_time::time_duration diff = it->second->GetTime() - EPOCH; std::string line = (it->first + " " + boost::lexical_cast<std::string>(it->second->GetValue()) + " " + boost::lexical_cast<std::string>(diff.total_milliseconds()) + "\n"); buffer.AddChunk(line); } } buffer.Flatten(s); } void MetricsRegistry::SharedMetrics::Add(float delta) { boost::mutex::scoped_lock lock(mutex_); value_ += delta; registry_.SetValue(name_, value_); } void MetricsRegistry::Timer::Start() { if (registry_.IsEnabled()) { active_ = true; start_ = GetNow(); } else { active_ = false; } } MetricsRegistry::Timer::~Timer() { if (active_) { boost::posix_time::time_duration diff = GetNow() - start_; registry_.SetValue(name_, diff.total_milliseconds(), type_); } } }