// ********************************************************************** // // Copyright (c) 2003-2017 ZeroC, Inc. All rights reserved. // // This copy of Ice is licensed to you under the terms described in the // ICE_LICENSE file included in this distribution. // // ********************************************************************** #ifndef ICEMX_METRICSOBSERVER_I_H #define ICEMX_METRICSOBSERVER_I_H #include #include #include #include #include #include #include #include #include namespace IceMX { /// \cond INTERNAL template class MetricsHelperT { public: virtual ~MetricsHelperT() { } virtual std::string operator()(const std::string&) const = 0; virtual void initMetrics(const ICE_INTERNAL_HANDLE&) const { // To be overriden in specialization to initialize state attributes } protected: template class AttributeResolverT { class Resolver { public: Resolver(const std::string& name) : _name(name) { } virtual ~Resolver() { } virtual std::string operator()(const Helper* h) const = 0; protected: std::string _name; }; public: AttributeResolverT() : _default(0) { } ~AttributeResolverT() { for(typename std::map::iterator p = _attributes.begin(); p != _attributes.end();++p) { delete p->second; } } std::string operator()(const Helper* helper, const std::string& attribute) const { typename std::map::const_iterator p = _attributes.find(attribute); if(p == _attributes.end()) { if(attribute == "none") { return ""; } if(_default) { return (helper->*_default)(attribute); } throw std::invalid_argument(attribute); } return (*p->second)(helper); } void setDefault(std::string (Helper::*memberFn)(const std::string&) const) { _default = memberFn; } template void add(const std::string& name, Y Helper::*member) { _attributes.insert(typename std::map::value_type(name, new HelperMemberResolver(name, member))); } template void add(const std::string& name, Y (Helper::*memberFn)() const) { _attributes.insert(typename std::map::value_type(name, new HelperMemberFunctionResolver(name, memberFn))); } template void add(const std::string& name, O (Helper::*getFn)() const, Y I::*member) { _attributes.insert(typename std::map::value_type(name, new MemberResolver(name, getFn, member))); } template void add(const std::string& name, O (Helper::*getFn)() const, Y (I::*memberFn)() const) { _attributes.insert(typename std::map::value_type(name, new MemberFunctionResolver(name, getFn, memberFn))); } private: template class HelperMemberResolver : public Resolver { public: HelperMemberResolver(const std::string& name, Y Helper::*member) : Resolver(name), _member(member) { } virtual std::string operator()(const Helper* r) const { return toString(r->*_member); } private: Y Helper::*_member; }; template class HelperMemberFunctionResolver : public Resolver { public: HelperMemberFunctionResolver(const std::string& name, Y (Helper::*memberFn)() const) : Resolver(name), _memberFn(memberFn) { } virtual std::string operator()(const Helper* r) const { return toString((r->*_memberFn)()); } private: Y (Helper::*_memberFn)() const; }; template class MemberResolver : public Resolver { public: MemberResolver(const std::string& name, O (Helper::*getFn)() const, Y I::*member) : Resolver(name), _getFn(getFn), _member(member) { } virtual std::string operator()(const Helper* r) const { O o = (r->*_getFn)(); I* v = dynamicCast(IceInternal::ReferenceWrapper::get(o)); if(v) { return toString(v->*_member); } else { throw std::invalid_argument(Resolver::_name); } } private: O (Helper::*_getFn)() const; Y I::*_member; }; template class MemberFunctionResolver : public Resolver { public: MemberFunctionResolver(const std::string& name, O (Helper::*getFn)() const, Y (I::*memberFn)() const) : Resolver(name), _getFn(getFn), _memberFn(memberFn) { } virtual std::string operator()(const Helper* r) const { O o = (r->*_getFn)(); I* v = dynamicCast(IceInternal::ReferenceWrapper::get(o)); if(v) { return toString((v->*_memberFn)()); } else { throw std::invalid_argument(Resolver::_name); } } private: O (Helper::*_getFn)() const; Y (I::*_memberFn)() const; }; template static I* dynamicCast(V* v) { return dynamic_cast(v); } template static I* dynamicCast(Ice::EndpointInfo* v) { for(Ice::EndpointInfo* info = v; info; info = info->underlying.get()) { I* i = dynamic_cast(info); if(i) { return i; } } return 0; } template static I* dynamicCast(Ice::ConnectionInfo* v) { for(Ice::ConnectionInfo* info = v; info; info = info->underlying.get()) { I* i = dynamic_cast(info); if(i) { return i; } } return 0; } template static std::string toString(const I& v) { std::ostringstream os; os << v; return os.str(); } static const std::string toString(const Ice::ObjectPrxPtr& p) { return p->ice_toString(); } static const std::string& toString(const std::string& s) { return s; } static std::string toString(const ::Ice::EndpointPtr& e) { return e->toString(); } static std::string toString(const ::Ice::ConnectionPtr& e) { return e->toString(); } static std::string toString(bool v) { return v ? "true" : "false"; } std::map _attributes; std::string (Helper::*_default)(const std::string&) const; }; }; class Updater #ifndef ICE_CPP11_MAPPING : public virtual IceUtil::Shared #endif { public: virtual void update() = 0; }; ICE_DEFINE_PTR(UpdaterPtr, Updater); template class UpdaterT : public Updater { public: #ifdef ICE_CPP11_MAPPING UpdaterT(const std::shared_ptr& updater, void (T::*fn)()) : #else UpdaterT(T* updater, void (T::*fn)()) : #endif _updater(updater), _fn(fn) { } virtual void update() { (_updater.get()->*_fn)(); } private: const ICE_HANDLE _updater; void (T::*_fn)(); }; #ifdef ICE_CPP11_MAPPING template UpdaterPtr newUpdater(const std::shared_ptr& updater, void (T::*fn)()) { if(updater) { return std::make_shared>(updater, fn); } else { return nullptr; } } #else template UpdaterPtr newUpdater(const IceInternal::Handle& updater, void (T::*fn)()) { if(updater) { return UpdaterPtr(new UpdaterT(updater.get(), fn)); } else { return 0; } } #endif template class ObserverT : public virtual ::Ice::Instrumentation::Observer { public: typedef T MetricsType; typedef typename IceInternal::MetricsMapT::EntryTPtr EntryPtrType; typedef std::vector EntrySeqType; ObserverT() : _previousDelay(0) { } virtual void attach() { if(!_watch.isStarted()) { _watch.start(); } } virtual void detach() { ::Ice::Long lifetime = _previousDelay + _watch.stop(); for(typename EntrySeqType::const_iterator p = _objects.begin(); p != _objects.end(); ++p) { (*p)->detach(lifetime); } } virtual void failed(const std::string& exceptionName) { for(typename EntrySeqType::const_iterator p = _objects.begin(); p != _objects.end(); ++p) { (*p)->failed(exceptionName); } } template void forEach(const Function& func) { for(typename EntrySeqType::const_iterator p = _objects.begin(); p != _objects.end(); ++p) { (*p)->execute(func); } } void init(const MetricsHelperT& /*helper*/, EntrySeqType& objects, ObserverT* previous = 0) { _objects.swap(objects); if(previous == 0) { return; } _previousDelay = previous->_previousDelay + previous->_watch.delay(); // // Detach entries from previous observer which are no longer // attached to this new observer. // for(typename EntrySeqType::const_iterator p = previous->_objects.begin(); p != previous->_objects.end(); ++p) { if(find(_objects.begin(), _objects.end(), *p) == _objects.end()) { (*p)->detach(_previousDelay); } } } EntryPtrType getEntry(IceInternal::MetricsMapT* map) { for(typename EntrySeqType::const_iterator p = _objects.begin(); p != _objects.end(); ++p) { if((*p)->getMap() == map) { return *p; } } return ICE_NULLPTR; } template ICE_INTERNAL_HANDLE getObserver(const std::string& mapName, const MetricsHelperT& helper) { std::vector::EntryTPtr> metricsObjects; for(typename EntrySeqType::const_iterator p = _objects.begin(); p != _objects.end(); ++p) { typename IceInternal::MetricsMapT::EntryTPtr e = (*p)->getMatching(mapName, helper); if(e) { metricsObjects.push_back(e); } } if(metricsObjects.empty()) { return ICE_NULLPTR; } ICE_INTERNAL_HANDLE obsv = ICE_MAKE_SHARED(ObserverImpl); obsv->init(helper, metricsObjects); return obsv; } private: EntrySeqType _objects; IceUtilInternal::StopWatch _watch; IceUtil::Int64 _previousDelay; }; template class ObserverFactoryT : public Updater, private IceUtil::Mutex { public: #ifdef ICE_CPP11_MAPPING using ObserverImplPtrType = ::std::shared_ptr; using MetricsType = typename ObserverImplType::MetricsType; using MetricsMapSeqType = std::vector<::std::shared_ptr>>; #else typedef IceUtil::Handle ObserverImplPtrType; typedef typename ObserverImplType::MetricsType MetricsType; typedef std::vector > > MetricsMapSeqType; #endif ObserverFactoryT(const IceInternal::MetricsAdminIPtr& metrics, const std::string& name) : _metrics(metrics), _name(name), _enabled(0) { _metrics->registerMap(name, this); } ~ObserverFactoryT() { if(_metrics) { _metrics->unregisterMap(_name); } } ObserverImplPtrType getObserver(const MetricsHelperT& helper) { IceUtil::Mutex::Lock sync(*this); if(!_metrics) { return ICE_NULLPTR; } typename ObserverImplType::EntrySeqType metricsObjects; for(typename MetricsMapSeqType::const_iterator p = _maps.begin(); p != _maps.end(); ++p) { typename ObserverImplType::EntryPtrType entry = (*p)->getMatching(helper); if(entry) { metricsObjects.push_back(entry); } } if(metricsObjects.empty()) { return ICE_NULLPTR; } ObserverImplPtrType obsv = ICE_MAKE_SHARED(ObserverImplType); obsv->init(helper, metricsObjects); return obsv; } template ObserverImplPtrType getObserver(const MetricsHelperT& helper, const ObserverPtrType& observer) { #ifdef ICE_CPP11_MAPPING ObserverImplPtrType old = std::dynamic_pointer_cast(observer); #else ObserverImplPtrType old = ObserverImplPtrType::dynamicCast(observer); #endif if(!observer || !old) { return getObserver(helper); } IceUtil::Mutex::Lock sync(*this); if(!_metrics) { return ICE_NULLPTR; } typename ObserverImplType::EntrySeqType metricsObjects; for(typename MetricsMapSeqType::const_iterator p = _maps.begin(); p != _maps.end(); ++p) { typename ObserverImplType::EntryPtrType entry = (*p)->getMatching(helper, old->getEntry(p->get())); if(entry) { metricsObjects.push_back(entry); } } if(metricsObjects.empty()) { old->detach(); return ICE_NULLPTR; } ObserverImplPtrType obsv = ICE_MAKE_SHARED(ObserverImplType); obsv->init(helper, metricsObjects, old.get()); return obsv; } template void registerSubMap(const std::string& subMap, MetricsMap MetricsType::* member) { assert(_metrics); _metrics->registerSubMap(_name, subMap, member); } bool isEnabled() const { return _enabled != 0; } virtual void update() { UpdaterPtr updater; { IceUtil::Mutex::Lock sync(*this); if(!_metrics) { return; } std::vector maps = _metrics->getMaps(_name); _maps.clear(); for(std::vector::const_iterator p = maps.begin(); p != maps.end(); ++p) { #ifdef ICE_CPP11_MAPPING _maps.push_back(::std::dynamic_pointer_cast>(*p)); #else _maps.push_back(IceUtil::Handle >::dynamicCast(*p)); #endif assert(_maps.back()); } _enabled.exchange(_maps.empty() ? 0 : 1); updater = _updater; } if(updater) { updater->update(); } } void setUpdater(const UpdaterPtr& updater) { IceUtil::Mutex::Lock sync(*this); _updater = updater; } void destroy() { IceUtil::Mutex::Lock sync(*this); _metrics = 0; _maps.clear(); } private: IceInternal::MetricsAdminIPtr _metrics; const std::string _name; MetricsMapSeqType _maps; // // TODO: Replace by std::atomic when it becomes widely // available. // IceUtilInternal::Atomic _enabled; UpdaterPtr _updater; }; typedef ObserverT ObserverI; /// \endcond } #endif