RTC Toolkit 5.0.0
Loading...
Searching...
No Matches
rtcComponentMain.hpp
Go to the documentation of this file.
1
13#ifndef RTCTK_COMPONENTFRAMEWORK_RTCCOMPONENTMAIN_HPP
14#define RTCTK_COMPONENTFRAMEWORK_RTCCOMPONENTMAIN_HPP
15
16#include <exception>
31
32#include <mal/Cii.hpp>
33
34#include <fmt/format.h>
35
36#include <boost/core/demangle.hpp>
37
38#include <boost/stacktrace.hpp>
39#include <iostream>
40#include <memory>
41#include <string>
42
53
55
72template <class BL, class BLF>
74 try {
75 auto& logger = GetLogger("rtctk");
76
77 auto component_name = args.GetComponentName();
78 LOG4CPLUS_INFO(logger, "RtcComponent '" << component_name << "' started.");
79 using boost::core::demangle;
80 LOG4CPLUS_DEBUG(logger, "BusinessLogic '" << demangle(typeid(BL).name()) << "'");
81
82 {
83 ServiceContainer services;
84
85 // Service Discovery
86 auto svc_disc_endpoint = args.GetServiceDiscEndpoint();
87 services.Add<ServiceDiscovery>(
88 std::make_unique<ServiceDiscovery>(svc_disc_endpoint, component_name));
90
91 // Runtime repository
94 services.Add<RuntimeRepoIf>(rtr_adapter);
95
96 // OLDB
97 auto oldb_endpoint = svc_disc.GetOldbEndpoint();
98 auto oldb_adapter = std::shared_ptr(OldbIf::CreateAdapter(oldb_endpoint));
99 services.Add<OldbIf>(oldb_adapter);
100
101 // Telemetry service
102 auto component_metrics = std::make_shared<ComponentMetrics>(
104 DataPointPath(fmt::format("/{}/metrics", component_name)),
106 DataPointPath(fmt::format("/{}/dynamic/metrics", component_name)),
107 GetLogger("rtctk.metrics"));
109
110 // Event Service
111 auto event_service = std::make_shared<MalDdsEventService>();
113
114 // Alert service and standard observers
115 auto alert_service = std::make_shared<AlertService>();
116 alert_service->AddObserver(std::make_unique<AlertLogger>());
117 alert_service->AddObserver(
118 std::make_unique<AlertOldbPublisher>(component_name, *oldb_adapter));
119 alert_service->AddObserver(
120 std::make_unique<AlertEventPublisher>(component_name, *event_service));
122 // for RR endpoint we do not want to be checked if the process is there or not (as we
123 // are just starting it up)
124 auto rr_endpoint =
125 svc_disc.GetReqRepEndpoint("", ServiceRegistryIf::COMPONENT_TYPE, false);
127
128 // ... and sam for PubSub endpoint we do not want to be checked if the process is there
129 // or not (as we are just starting it up)
130 auto ps_endpoint =
131 svc_disc.GetPubSubEndpoint("", ServiceRegistryIf::COMPONENT_TYPE, false);
133
135
136 engine.RegisterStateChangeHandler([&](const std::string& state) {
137 try {
138 LOG4CPLUS_DEBUG(logger, "Entering State: " << state);
139 publisher.PublishState(state);
140 OldbIf& oldb = services.Get<OldbIf>();
142 if (not oldb.DataPointExists(dp_name)) {
143 oldb.CreateDataPoint<std::string>(dp_name);
144 }
145 oldb.SetDataPoint(dp_name, state);
146 } catch (...) {
147 LOG4CPLUS_ERROR(logger,
149 RtctkException("StateChangeHandler failed"))));
150 }
151 });
152
153 static_assert(std::is_base_of_v<typename BL::ComponentType::BizLogicIf, BL>,
154 "BusinessLogic must implement BusinessLogicInterface");
155
156 static_assert(
157 std::is_invocable_v<BLF, const std::string&, ServiceContainer&>,
158 "Factory must be invocable with 'const std::string&' and 'ServiceContainer&'");
159
160 static_assert(
161 std::is_same_v<std::invoke_result_t<BLF, const std::string&, ServiceContainer&>,
162 std::unique_ptr<BL>>,
163 "Factory must return type 'std::unique_ptr<BusinessLogic>'");
164
165 // Invoking user factory here -> catch and rethrow RtctkException
166 std::unique_ptr<BL> biz_logic;
167 try {
169 if (!biz_logic) {
171 "BusinessLogic factory did not return a valid object");
172 }
173 } catch (const std::exception& ex) {
174 CII_THROW_WITH_NESTED(RtctkException, ex, "BusinessLogic factory failed");
175 }
176
177 typename BL::ComponentType::InputStage input_stage(replier, engine);
178
179 typename BL::ComponentType::OutputStage output_stage(engine, *biz_logic);
180
181 typename BL::ComponentType::ModelBuilder model_builder(engine);
182
183 if (auto emf = args.GetModelExportFile(); emf) {
184 model_builder.ExportModel(emf->path().to_string());
185 }
186
187 model_builder.RegisterModel();
188 input_stage.Start();
189 component_metrics->StartMonitoring();
190 engine.Work();
191 }
192
193 LOG4CPLUS_INFO(logger, "RtcComponent '" << component_name << "' terminated.");
194
195 } catch (const std::exception& ex) {
196 CII_THROW_WITH_NESTED(RtctkException, ex, "RunAsRtcComponent() failed");
197 }
198}
199
211template <class BL>
213 static_assert(
214 std::is_constructible_v<BL, const std::string&, ServiceContainer&>,
215 "BusinessLogic must be constructible with 'const std::string&' and 'ServiceContainer&'");
216
217 RunAsRtcComponent<BL>(args, std::make_unique<BL, const std::string&, ServiceContainer&>);
218}
219
220} // namespace rtctk::componentFramework
221
222#ifndef RTCTK_NOMAIN
224
231int Main(int argc, char* argv[]) {
233 Args args{argc, argv};
234
235 try {
236 args.Parse();
237 } catch (const CLI::ParseError& e) {
238 return args.PrintHelpOrErrMsg(e);
239 } catch (const std::exception& e) {
240 fmt::print(stderr, "RtcComponentMain failed during argument parsing: {}\n", e.what());
241 return EXIT_FAILURE;
242 } catch (...) {
243 fmt::print(stderr, "{}", NestedExceptionPrinter(std::current_exception()).Str());
244 return EXIT_FAILURE;
245 }
246
247 try {
248 auto name = args.GetComponentName();
249 auto log_props_file = args.GetLogPropsFile();
250 auto debug_mode = args.GetDebugMode();
251
252 if (log_props_file.has_value()) {
254 } else {
255 auto level = debug_mode ? log4cplus::DEBUG_LOG_LEVEL : log4cplus::INFO_LOG_LEVEL;
256 LogConfigure(name, level);
257 }
258 } catch (const std::exception& e) {
259 fmt::print(stderr, "Failed to initialize log system: {}\n", e.what());
260 return EXIT_FAILURE;
261 }
262
263 try {
264 // Call user implementation of RtcComponentMain
266
267 return EXIT_SUCCESS;
268
269 } catch (const std::exception& e) {
271 } catch (...) {
272 LOG4CPLUS_FATAL(GetLogger("rtctk"), NestedExceptionPrinter(std::current_exception()));
273 }
274 return EXIT_FAILURE;
275}
276
277} // namespace rtctk::componentFramework
278
282int main(int argc, char* argv[]) {
283 std::set_terminate([]() {
284 using namespace rtctk::componentFramework;
285
286 std::exception_ptr eptr{std::current_exception()};
287 if (eptr) {
288 LOG4CPLUS_FATAL(GetLogger("rtctk"),
289 "Unhandled Exception caught: "
290 << NestedExceptionPrinter(eptr) << "\n\nBacktrace:\n"
291 << boost::to_string(boost::stacktrace::stacktrace()));
292 } else {
293 LOG4CPLUS_FATAL(GetLogger("rtctk"),
294 "Exiting without exception.\nBacktrace:\n"
295 << boost::to_string(boost::stacktrace::stacktrace()));
296 }
297 std::abort();
298 }); // std::set_terminate
299
300 try {
301 return rtctk::componentFramework::Main(argc, argv);
302 } catch (...) {
303 // Note: Use minimal formatting to avoid further exception leaks.
304 // This handler is only here to avoid std::terminate due to exception-leaks.
305 constexpr std::string_view msg =
306 "Caught exception leaked from rtctk::componentFramework::Main\n";
307 std::cerr.write(msg.data(), msg.size());
308 }
309}
310#endif // RTCTK_NOMAIN
311
312#endif // RTCTK_COMPONENTFRAMEWORK_RTCCOMPONENTMAIN_HPP
Declares AlertService.
Alert Service interface.
Definition alertServiceIf.hpp:128
Class used to parse default command line arguments.
Definition rtcComponentArgs.hpp:33
void Parse()
do the actual parsing of CLI
Definition rtcComponentArgs.cpp:48
Class that handles reception of commands using MAL.
Definition commandReplier.hpp:30
Component metrics interface.
Definition componentMetricsIf.hpp:85
This class provides a wrapper for a data point path.
Definition dataPointPath.hpp:74
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:159
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:211
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:144
Class used to publish state-changed-topic using MAL.
Definition statePublisher.hpp:36
Receive commands via MAL.
Declares ComponentMetrics.
Provides macros and utilities for exception handling.
Logging Support Library based on log4cplus.
Implementation of the event service.
Definition commandReplier.cpp:22
void RunAsRtcComponent(const Args &args, BLF factory)
RTC Component runner function, needed to run custom BusinessLogic as RTC Component.
Definition rtcComponentMain.hpp:73
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:95
log4cplus::Logger & GetLogger(const std::string &name="app")
Get handle to a specific logger.
Definition logger.cpp:193
int Main(int argc, char *argv[])
Main function implementation.
Definition rtcComponentMain.hpp:231
elt::mal::future< std::string > InjectReqRepEvent(StateMachineEngine &engine)
Definition malEventInjector.hpp:23
void LogConfigure(const std::string &app_name, const std::string &props_file_name)
Performs custom logging configuration for any application.
Definition logger.cpp:71
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:43
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:282
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.