13#ifndef RTCTK_COMPONENTFRAMEWORK_RTCCOMPONENTMAIN_HPP
14#define RTCTK_COMPONENTFRAMEWORK_RTCCOMPONENTMAIN_HPP
35#include <fmt/format.h>
37#include <boost/core/demangle.hpp>
39#include <boost/stacktrace.hpp>
73template <
class BL,
class BLF>
79 LOG4CPLUS_INFO(logger,
"RtcComponent '" << component_name <<
"' started.");
80 using boost::core::demangle;
81 LOG4CPLUS_DEBUG(logger,
"BusinessLogic '" << demangle(
typeid(BL).name()) <<
"'");
89 std::make_unique<ServiceDiscovery>(svc_disc_endpoint, component_name));
98 auto oldb_endpoint = svc_disc.GetOldbEndpoint();
103 auto telegraf_endpoint = svc_disc.GetTelegrafEndpoint();
104 auto telegraf_adapter =
105 std::make_shared<TelegrafAdapter>(telegraf_endpoint, component_name);
109 auto component_metrics = std::make_shared<ComponentMetrics>(
113 DataPointPath(fmt::format(
"/{}/dynamic/metrics", component_name)),
115 telegraf_adapter.get());
119 auto event_service = std::make_shared<MalDdsEventService>();
123 auto alert_service = std::make_shared<AlertService>();
124 alert_service->AddObserver(std::make_unique<AlertLogger>());
125 alert_service->AddObserver(
126 std::make_unique<AlertOldbPublisher>(component_name, *oldb_adapter));
127 alert_service->AddObserver(
128 std::make_unique<AlertEventPublisher>(component_name, *event_service));
129 alert_service->AddObserver(
130 std::make_unique<AlertTelegrafPublisher>(component_name, *telegraf_adapter));
148 LOG4CPLUS_DEBUG(logger,
"Entering State: " << state);
154 if (not oldb.DataPointExists(dp_name)) {
155 oldb.CreateDataPoint<std::string>(dp_name);
157 oldb.SetDataPoint(dp_name, state);
165 LOG4CPLUS_ERROR(logger,
171 static_assert(std::is_base_of_v<typename BL::ComponentType::BizLogicIf, BL>,
172 "BusinessLogic must implement BusinessLogicInterface");
175 std::is_invocable_v<BLF, const std::string&, ServiceContainer&>,
176 "Factory must be invocable with 'const std::string&' and 'ServiceContainer&'");
179 std::is_same_v<std::invoke_result_t<BLF, const std::string&, ServiceContainer&>,
180 std::unique_ptr<BL>>,
181 "Factory must return type 'std::unique_ptr<BusinessLogic>'");
184 std::unique_ptr<BL> biz_logic;
186 biz_logic = invoke(factory, component_name, services);
189 "BusinessLogic factory did not return a valid object");
191 }
catch (
const std::exception& ex) {
192 CII_THROW_WITH_NESTED(
RtctkException, ex,
"BusinessLogic factory failed");
195 typename BL::ComponentType::InputStage input_stage(replier, engine);
197 typename BL::ComponentType::OutputStage output_stage(engine, *biz_logic);
199 typename BL::ComponentType::ModelBuilder model_builder(engine);
202 model_builder.ExportModel(emf->path().to_string());
205 model_builder.RegisterModel();
207 component_metrics->StartMonitoring();
211 LOG4CPLUS_INFO(logger,
"RtcComponent '" << component_name <<
"' terminated.");
213 }
catch (
const std::exception& ex) {
214 CII_THROW_WITH_NESTED(
RtctkException, ex,
"RunAsRtcComponent() failed");
232 std::is_constructible_v<BL, const std::string&, ServiceContainer&>,
233 "BusinessLogic must be constructible with 'const std::string&' and 'ServiceContainer&'");
249int Main(
int argc,
char* argv[]) {
251 Args args{argc, argv};
255 }
catch (
const CLI::ParseError& e) {
256 return args.PrintHelpOrErrMsg(e);
257 }
catch (
const std::exception& e) {
258 fmt::print(stderr,
"RtcComponentMain failed during argument parsing: {}\n", e.what());
266 auto name = args.GetComponentName();
267 auto log_props_file = args.GetLogPropsFile();
268 auto debug_mode = args.GetDebugMode();
270 if (log_props_file.has_value()) {
273 auto level = debug_mode ? log4cplus::DEBUG_LOG_LEVEL : log4cplus::INFO_LOG_LEVEL;
276 }
catch (
const std::exception& e) {
277 fmt::print(stderr,
"Failed to initialise log system: {}\n", e.what());
287 }
catch (
const std::exception& e) {
300int main(
int argc,
char* argv[]) {
301 std::set_terminate([]() {
304 std::exception_ptr eptr{std::current_exception()};
307 "Unhandled Exception caught: "
309 << boost::to_string(boost::stacktrace::stacktrace()));
312 "Exiting without exception.\nBacktrace:\n"
313 << boost::to_string(boost::stacktrace::stacktrace()));
323 constexpr std::string_view msg =
324 "Caught exception leaked from rtctk::componentFramework::Main\n";
325 std::cerr.write(msg.data(), msg.size());
Alert Service interface.
Definition alertServiceIf.hpp:138
Class used to parse default command line arguments.
Definition rtcComponentArgs.hpp:33
std::optional< elt::mal::Uri > GetModelExportFile() const
Get name of optionally provided state machine model export file.
Definition rtcComponentArgs.cpp:40
std::string GetComponentName() const
Get component name or identifier.
Definition rtcComponentArgs.cpp:20
elt::mal::Uri GetServiceDiscEndpoint() const
Get service discovery endpoint.
Definition rtcComponentArgs.cpp:24
Class that handles reception of commands using MAL.
Definition commandReplier.hpp:30
Component metrics interface.
Definition componentMetricsIf.hpp:164
This class provides a wrapper for a data point path.
Definition dataPointPath.hpp:77
Interface class for providing pub/sub facilities for JSON events.
Definition eventServiceIf.hpp:29
RAII class to clean-up logging without leaking memory.
Definition logger.hpp:28
Adapter object intended to be used in contexts without direct access to the output-stream object.
Definition exceptions.hpp:161
Base interface for all OLDB adapters.
Definition oldbIf.hpp:25
static std::unique_ptr< OldbIf > CreateAdapter(const elt::mal::Uri &uri)
Factory method used to create the appropriate OLDB adapter depending on the URI scheme.
Definition oldbIf.cpp:18
The RtctkException class is the base class for all Rtctk exceptions.
Definition exceptions.hpp:213
Base interface for all Runtime Configuration Repository adapters.
Definition runtimeRepoIf.hpp:27
static std::unique_ptr< RuntimeRepoIf > CreateAdapter(const elt::mal::Uri &uri)
Factory method used to create the appropriate Runtime Configuration Repository adapter depending on t...
Definition runtimeRepoIf.cpp:19
Container class that holds services of any type.
Definition serviceContainer.hpp:39
void Add(Service &&service, const std::string &name="")
Insert new service into the container.
Definition serviceContainer.hpp:62
Service & Get(const std::string &name="")
Get a handle to a service.
Definition serviceContainer.hpp:100
Class that implements a very basic service discovery mechanism.
Definition serviceDiscovery.hpp:33
ServiceEndpoint GetRuntimeRepoEndpoint()
Get the Runtime Repository Endpoint from the ServiceDiscovery.
Definition serviceDiscovery.cpp:59
static const std::string COMPONENT_TYPE
the string for component type (default)
Definition serviceRegistryIf.hpp:60
Definition stateMachineEngine.hpp:35
void RegisterStateChangeHandler(StateMethod on_statechange)
Register state changed handler.
Definition stateMachineEngine.cpp:142
void Work()
Runs the event loop of the state machine.
Definition stateMachineEngine.cpp:155
Class used to publish state-changed-topic using MAL.
Definition statePublisher.hpp:36
void PublishState(const std::string &state)
Definition statePublisher.cpp:41
Implementation of the Telegraf Adapter.
Definition telegrafAdapter.hpp:93
std::map< std::string, std::string > BaseTags()
Constructs and returns a map of base tags for InfluxDB.
Definition telegrafAdapter.cpp:78
void SendPoints(const std::vector< InfluxPoint > &points)
Sends vector of points to Telegraf using UDP and Influx line protocol.
Definition telegrafAdapter.cpp:86
Receive commands via MAL.
Declares ComponentMetrics.
log4cplus::Logger & GetLogger(const std::string &name="app")
Get handle to a specific logger.
Definition logger.cpp:192
Provides macros and utilities for exception handling.
Logging Support Library based on log4cplus.
Implementation of the event service.
Definition commandReplier.cpp:22
std::vector< InfluxPoint > ParseStateToInfluxPoints(const std::string &component_name, const std::string &states_str, const std::map< std::string, std::string > &base_tags)
Definition telegrafAdapter.cpp:213
void RunAsRtcComponent(const Args &args, BLF factory)
RTC Component runner function, needed to run custom BusinessLogic as RTC Component.
Definition rtcComponentMain.hpp:74
auto WrapWithNested(E &&exception) noexcept(std::is_nothrow_constructible_v< detail::UnspecifiedNested< typename std::decay_t< E > >, E && >)
Constructs an unspecified exception that derives from both the provided object and std::nested_except...
Definition exceptions.hpp:97
log4cplus::Logger & GetLogger(const std::string &name="app")
Get handle to a specific logger.
Definition logger.cpp:192
int Main(int argc, char *argv[])
Main function implementation.
Definition rtcComponentMain.hpp:249
void LogConfigure(const std::string &app_name, const std::string &props_file_name)
Performs custom logging configuration for any application.
Definition logger.cpp:70
Header file for OldbIf, which defines the API for OldbAdapters.
Provides argument parsing functionality of an RTC Component.
void RtcComponentMain(const rtctk::componentFramework::Args &args)
Main entry point for user code, this method must be implemented by component developers.
Definition main.cpp:27
int main(int argc, char *argv[])
Main function, this is private to the RTC Tk and shall NOT be used by component developers.
Definition rtcComponentMain.hpp:300
Header file for RuntimeRepoIf, which defines the API for RuntimeRepoAdapters.
A container that can hold any type of service.
Class that implements a very basic service discover mechanism.
Class that implements the service registry interface.
Wrapper around the SCXML State Machine Engine.
Publishes the stdif state topic via MAL.
Header file needed to instantiate an TelegrafAdapter.