diff --git a/CMakeLists.txt b/CMakeLists.txt index 975e8be..8ac8174 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -14,8 +14,9 @@ find_package(absl REQUIRED) find_package(Protobuf REQUIRED CONFIG) find_package(Boost COMPONENTS unit_test_framework REQUIRED) find_package(utilities) +find_package(confmodel) -set(OPMONLIB_DEPENDENCIES ${CETLIB} ${CETLIB_EXCEPT} ers::ers logging::logging nlohmann_json::nlohmann_json protobuf::libprotobuf absl::log_internal_check_op utilities::utilities ) +set(OPMONLIB_DEPENDENCIES ${CETLIB} ${CETLIB_EXCEPT} ers::ers logging::logging nlohmann_json::nlohmann_json protobuf::libprotobuf absl::log_internal_check_op utilities::utilities confmodel::confmodel ) ############################################################################## # Schemas diff --git a/include/opmonlib/MonitorableObject.hpp b/include/opmonlib/MonitorableObject.hpp index ff11a32..bc4ad5a 100644 --- a/include/opmonlib/MonitorableObject.hpp +++ b/include/opmonlib/MonitorableObject.hpp @@ -11,9 +11,12 @@ #include "opmonlib/Utils.hpp" #include "opmonlib/OpMonFacility.hpp" -#include #include +#include "confmodel/OpMonConf.hpp" + +#include + #include #include #include @@ -45,7 +48,8 @@ namespace dunedaq { namespace dunedaq::opmonlib { - using OpMonLevel = unsigned int; + using OpMonLevel = std::invoke_result::type; enum class SystemOpMonLevel : OpMonLevel { kDisabled = std::numeric_limits::min(), @@ -60,7 +64,7 @@ namespace dunedaq::opmonlib { }; template - auto to_level( T v ) { + constexpr auto to_level( T v ) { return static_cast::type>(v); } diff --git a/include/opmonlib/OpMonFacility.hpp b/include/opmonlib/OpMonFacility.hpp index b108177..8c3a165 100644 --- a/include/opmonlib/OpMonFacility.hpp +++ b/include/opmonlib/OpMonFacility.hpp @@ -18,6 +18,7 @@ #include #include #include +#include #ifndef EXTERN_C_FUNC_DECLARE_START // NOLINTNEXTLINE(build/define_used) @@ -32,12 +33,12 @@ */ // NOLINTNEXTLINE(build/define_used) -#define DEFINE_DUNE_OPMON_FACILITY(klass) \ - EXTERN_C_FUNC_DECLARE_START \ - std::shared_ptr make(std::string facility) \ - { \ - return std::shared_ptr(new klass(facility)); \ - } \ +#define DEFINE_DUNE_OPMON_FACILITY(klass) \ + EXTERN_C_FUNC_DECLARE_START \ + std::shared_ptr make(std::string facility, std::optional o ) \ + { \ + return std::shared_ptr(new klass(facility, o)); \ + } \ } namespace dunedaq { @@ -57,7 +58,7 @@ namespace dunedaq::opmonlib { class OpMonFacility { public: - explicit OpMonFacility(std::string uri) : m_uri(uri) {;} + explicit OpMonFacility(std::string uri ) : m_uri(uri) {;} virtual ~OpMonFacility() = default; OpMonFacility(const OpMonFacility&) = delete; ///< OpMonFacility is not copy-constructible @@ -79,7 +80,8 @@ class OpMonFacility std::string m_uri; }; -std::shared_ptr makeOpMonFacility(std::string const& facility) ; + using OptionalOrigin = std::optional; + std::shared_ptr makeOpMonFacility(std::string const& facility, OptionalOrigin = OptionalOrigin() ) ; } // namespace dunedaq::opmonlib diff --git a/include/opmonlib/OpMonManager.hpp b/include/opmonlib/OpMonManager.hpp index 7be68c3..7ebd589 100644 --- a/include/opmonlib/OpMonManager.hpp +++ b/include/opmonlib/OpMonManager.hpp @@ -13,7 +13,9 @@ #include #include "opmonlib/MonitorableObject.hpp" +#include "opmonlib/Utils.hpp" +#include "confmodel/OpMonConf.hpp" namespace dunedaq { ERS_DECLARE_ISSUE( opmonlib, @@ -31,6 +33,11 @@ namespace dunedaq { FailedMonitoringThread, "Monitoring thread failed to start", ERS_EMPTY ) + + ERS_DECLARE_ISSUE( opmonlib, + MissingConfiguration, + "Confiration is not set", + ERS_EMPTY ) } @@ -51,7 +58,7 @@ class OpMonManager : protected MonitorableObject explicit OpMonManager(std::string session, std::string name, std::string opmon_facility_uri = "stdout") : - OpMonManager( session, name, makeOpMonFacility(opmon_facility_uri) ){;} + OpMonManager( session, name, makeOpMonFacility(opmon_facility_uri, make_origin(session, name)) ){;} virtual ~OpMonManager() = default; @@ -61,10 +68,15 @@ class OpMonManager : protected MonitorableObject using MonitorableObject::set_opmon_level; // data collecting loop - void start_monitoring(std::chrono::seconds); + void start_monitoring(); // The stop command is not necessary. - // The stop is invoked during the destruction of the thread or at the start of a new one + // The stop is invoked during the destruction of the thread + // the method requires a valid configuration because the time period is taken from there + void set_opmon_conf( const confmodel::OpMonConf* c ) { + m_cfg.store(c); + set_opmon_level( m_cfg.load()->get_level() ); + } protected: using MonitorableObject::collect; @@ -76,11 +88,12 @@ class OpMonManager : protected MonitorableObject std::string name, facility_ptr_t ); - void run( std::stop_token, std::chrono::seconds ); // function used by the jthread + void run( std::stop_token ); // function used by the jthread private: std::jthread m_thread; + std::atomic m_cfg{nullptr}; }; diff --git a/include/opmonlib/Utils.hpp b/include/opmonlib/Utils.hpp index ed46582..642a5c7 100644 --- a/include/opmonlib/Utils.hpp +++ b/include/opmonlib/Utils.hpp @@ -66,6 +66,8 @@ namespace dunedaq::opmonlib { void set_value( const google::protobuf::Reflection & , google::protobuf::Message & , const google::protobuf::FieldDescriptor* , T ); + + opmon::OpMonId make_origin( const std::string & session, const std::string & app ) ; dunedaq::opmon::OpMonEntry to_entry(const google::protobuf::Message & m, const CustomOrigin & co); diff --git a/plugins/fileOpMonFacility.cpp b/plugins/fileOpMonFacility.cpp index 5846915..57042da 100644 --- a/plugins/fileOpMonFacility.cpp +++ b/plugins/fileOpMonFacility.cpp @@ -16,7 +16,7 @@ namespace dunedaq::opmonlib { - fileOpMonFacility::fileOpMonFacility(std::string uri) : + fileOpMonFacility::fileOpMonFacility(std::string uri, OptionalOrigin o) : JSonOpMonFacility(uri) { std::string hook = "://"; @@ -27,6 +27,19 @@ namespace dunedaq::opmonlib { } else { fname = uri.substr(sep + hook.size()); } + + if (o) { + auto slash_pos = fname.find_last_of('/'); + auto dot_pos = slash_pos == std::string::npos ? fname.find_first_of('.') : fname.find_first_of('.', slash_pos); + + auto origin = to_string( o.value() ); + if (dot_pos == std::string::npos) { + fname += '.' + origin + ".json"; + } else { + fname.insert(dot_pos, '.' + origin ); + } + + } m_ofs.open(fname, std::ios::out | std::ios::app); if (!m_ofs.is_open()) { diff --git a/plugins/fileOpMonFacility.hpp b/plugins/fileOpMonFacility.hpp index ea8fbe0..848afbd 100644 --- a/plugins/fileOpMonFacility.hpp +++ b/plugins/fileOpMonFacility.hpp @@ -50,7 +50,7 @@ class fileOpMonFacility : public JSonOpMonFacility { public: - explicit fileOpMonFacility(std::string uri); + explicit fileOpMonFacility(std::string uri, OptionalOrigin); ~fileOpMonFacility(); void publish(opmon::OpMonEntry && e) const override; diff --git a/plugins/stdoutOpMonFacility.cpp b/plugins/stdoutOpMonFacility.cpp index c99a8a4..19b1a28 100644 --- a/plugins/stdoutOpMonFacility.cpp +++ b/plugins/stdoutOpMonFacility.cpp @@ -20,7 +20,7 @@ namespace dunedaq::opmonlib { class stdoutOpMonFacility : public JSonOpMonFacility { public: - explicit stdoutOpMonFacility(std::string uri) + explicit stdoutOpMonFacility(std::string uri, OptionalOrigin ) : JSonOpMonFacility(uri) { ; } void publish(opmon::OpMonEntry && e) const override { diff --git a/plugins/stdoutOpmonService.cpp b/plugins/stdoutOpmonService.cpp deleted file mode 100644 index faa78d3..0000000 --- a/plugins/stdoutOpmonService.cpp +++ /dev/null @@ -1,52 +0,0 @@ -/** - * @file stdoutOpmonService.cpp - * - * This is part of the DUNE DAQ Application Framework, copyright 2020. - * Licensing/copyright details are in the COPYING file that you should have - * received with this code. - */ - -#include "opmonlib/OpmonService.hpp" - -#include - -#include -#include -#include - -namespace dunedaq::opmonlib { - -class stdoutOpmonService : public OpmonService -{ -public: - explicit stdoutOpmonService(std::string uri) - : OpmonService(uri) - { - auto sep = uri.find("://"); - m_style = "flat"; - if (sep != std::string::npos) { // assume filename - m_style = uri.substr(sep + 3); - } - } - - void publish(nlohmann::json j) - { - if (m_style == "flat") { - std::cout << std::setw(4) << j.flatten() << '\n'; // NOLINT(runtime/output_format) - } else if (m_style == "formatted") { - std::cout << j.dump(2) << std::endl; // NOLINT(runtime/output_format) - } else { - std::cout << j.dump() << std::endl; // NOLINT(runtime/output_format) - } - } - -protected: - typedef OpmonService inherited; - -private: - std::string m_style; -}; - -} // namespace dunedaq::opmonlib - -DEFINE_DUNE_OPMON_SERVICE(dunedaq::opmonlib::stdoutOpmonService) diff --git a/src/OpMonFacility.cpp b/src/OpMonFacility.cpp index f29e589..8c0ed2b 100644 --- a/src/OpMonFacility.cpp +++ b/src/OpMonFacility.cpp @@ -11,7 +11,7 @@ using namespace dunedaq::opmonlib; -std::shared_ptr dunedaq::opmonlib::makeOpMonFacility(std::string const& facility) { +std::shared_ptr dunedaq::opmonlib::makeOpMonFacility(std::string const& facility, OptionalOrigin o) { TLOG() << "FACILITY = " << facility; @@ -30,7 +30,7 @@ std::shared_ptr dunedaq::opmonlib::makeOpMonFacility(std::string std::shared_ptr os_ptr; try { - os_ptr = bpf.makePlugin>(plugin_name, facility); + os_ptr = bpf.makePlugin>(plugin_name, facility, o); } catch (const ers::Issue& iexpt) { throw OpMonFacilityCreationFailed(ERS_HERE, plugin_name, iexpt); } catch (const cet::exception& cexpt) { diff --git a/src/OpMonManager.cpp b/src/OpMonManager.cpp index f954e8f..0c7d622 100644 --- a/src/OpMonManager.cpp +++ b/src/OpMonManager.cpp @@ -22,13 +22,15 @@ OpMonManager::OpMonManager( std::string session, } -void OpMonManager::start_monitoring(std::chrono::seconds interval) { +void OpMonManager::start_monitoring() { - TLOG() << "Starting a new monitoring thread with interval " << interval.count() << " seconds, at level " << get_opmon_level(); + if ( ! m_cfg ) + throw MissingConfiguration(ERS_HERE); - auto running_function = std::bind( & OpMonManager::run, this, - std::placeholders::_1, std::placeholders::_2); - m_thread = std::jthread( running_function, interval ); + TLOG() << "Starting a new monitoring thread with interval " << m_cfg.load()->get_interval().count() << " seconds, at level " << get_opmon_level(); + + auto running_function = std::bind( & OpMonManager::run, this, std::placeholders::_1); + m_thread = std::jthread( running_function ); auto handle = m_thread.native_handle(); auto thread_name = "opmon"; auto rc = pthread_setname_np(handle, thread_name); @@ -37,8 +39,7 @@ void OpMonManager::start_monitoring(std::chrono::seconds interval) { } } -void OpMonManager::run(std::stop_token stoken, - std::chrono::seconds interval) { +void OpMonManager::run(std::stop_token stoken ) { auto sleep_interval = std::chrono::milliseconds(100); @@ -49,7 +50,7 @@ void OpMonManager::run(std::stop_token stoken, std::this_thread::sleep_for(sleep_interval); auto time_span = std::chrono::duration_cast( std::chrono::steady_clock::now() - last_collection_time); - if ( time_span >= interval ) { + if ( time_span >= m_cfg.load()->get_interval() ) { last_collection_time = std::chrono::steady_clock::now(); publish( collect() ); // there is no catch here because collect is supposed to catch all possible exceptions diff --git a/src/Utils.cpp b/src/Utils.cpp index 72a80e0..b5511e4 100644 --- a/src/Utils.cpp +++ b/src/Utils.cpp @@ -8,6 +8,15 @@ #include "opmonlib/Utils.hpp" + +dunedaq::opmon::OpMonId dunedaq::opmonlib::make_origin( const std::string & session, const std::string & app ) { + opmon::OpMonId origin; + origin.set_session( session ); + origin.set_application( app ); + return origin; +} + + dunedaq::opmon::OpMonEntry dunedaq::opmonlib::to_entry(const google::protobuf::Message & m, const CustomOrigin & co) { diff --git a/unittest/opmon_facility_test.cxx b/unittest/opmon_facility_test.cxx index 307cc3c..22a9ad9 100644 --- a/unittest/opmon_facility_test.cxx +++ b/unittest/opmon_facility_test.cxx @@ -74,7 +74,7 @@ BOOST_AUTO_TEST_CASE(File_facility) { BOOST_CHECK_THROW( auto service = makeOpMonFacility("file:///impossible_file.txt"), OpMonFacilityCreationFailed); - auto service = makeOpMonFacility("file://./test_file.txt"); + auto service = makeOpMonFacility("file://./test_file", make_origin("test", "app") ); auto pub_func = [&](int i){ dunedaq::opmon::OpMonId id;