Newer
Older
#ifndef CHIMERATK_STATUS_MONITOR_H
#define CHIMERATK_STATUS_MONITOR_H
/*!
* \author Nadeem Shehzad (DESY)
* \date 15.05.2019
* \page statusmonitordoc Status Monitor
*
* To monitor a status of a varaible in an appplicaiton this group of
* modules provides different possiblites.
* It includes
* - MaxMonitor to monitor a value depending upon two MAX thresholds for warning and error.
* - MinMonitor to monitor a value depending upon two MIN thresholds for warning and error.
* - RangeMonitor to monitor a value depending upon two ranges of thresholds for warning and error.
* - ExactMonitor to monitor a value which should be exactly same as required value.
* - StateMonitor to monitor On/Off state.
* Depending upon the value and condition on of the four states are reported.
* - OFF, OK, WARNING, ERROR.
* Checkout the status monitor example to see in detail how it works.
* \include demoStatusMonitor.cc
/**
For more info see \ref statusmonitordoc
\example demoStatusMonitor.cc
*/
/** Generic modules for status monitoring.
* Each module monitors an input variable and depending upon the
* conditions reports four different states.
*/
namespace ChimeraTK {
/** There are four states that can be reported*/
enum States { OFF, OK, WARNING, ERROR };
/** Common base for StatusMonitors
*
* This holds common process variables that are not dependant on the
* type of the variable to be monitored. A non-template base class
* facilitates checking for the type in the StatusAggregator, which
* needs to identify any StatusMonitor.
*/
struct StatusMonitor : public ApplicationModule {
Martin Killenberg
committed
StatusMonitor(EntityOwner* owner, const std::string& name, const std::string& description, const std::string& input,
const std::string& output, HierarchyModifier modifier, const std::unordered_set<std::string>& outputTags = {},
const std::unordered_set<std::string>& parameterTags = {}, const std::unordered_set<std::string>& tags = {})
: ApplicationModule(owner, name, description, modifier, tags), _parameterTags(parameterTags), _input(input),
status(this, output, "", "", outputTags) {}
StatusMonitor(StatusMonitor&&) = default;
~StatusMonitor() override {}
void prepare() override {}
/**Tags for parameters. This makes it easier to connect them to e.g, to control system*/
std::unordered_set<std::string> _parameterTags;
/**One of four possible states to be reported*/
ScalarOutput<uint16_t> status;
/** Disable the monitor. The status will always be OFF. You don't have to connect this input.
* When there is no feeder, ApplicationCore will connect it to a constant feeder with value 0, hence the monitor is always enabled.
*/
ScalarPushInput<int> disable{this, "disable", "", "Disable the status monitor"};
};
/** Common template base class for StatusMonitors
*
* This provides a ScalarPushInput for the variable to be monitored, which
* can be specified by the input parameter of the constructor.
*/
template<typename T>
struct StatusMonitorImpl : public StatusMonitor {
/** Number of convience constructors for ease of use.
* The input and output variable names can be given by user which
* should be mapped with the variables of module to be watched.
*/
StatusMonitorImpl(EntityOwner* owner, const std::string& name, const std::string& description,
const std::string& input, const std::string& output, HierarchyModifier modifier,
const std::unordered_set<std::string>& outputTags = {},
const std::unordered_set<std::string>& parameterTags = {}, const std::unordered_set<std::string>& tags = {})
: StatusMonitor(owner, name, description, input, output, modifier, outputTags, parameterTags, tags),
StatusMonitorImpl() { throw logic_error("Default constructor unusable. Just exists to work around gcc bug."); }
StatusMonitorImpl(StatusMonitorImpl&&) = default;
~StatusMonitorImpl() override {}
void prepare() override {}
/**Input value that should be monitored. It is moved one level up, so it's parallel to this monitor object.*/
struct OneUp : public VariableGroup {
OneUp(EntityOwner* owner, const std::string& watchName)
: VariableGroup(owner, "hidden", "", HierarchyModifier::oneUpAndHide), watch(this, watchName, "", "") {}
ScalarPushInput<T> watch;
} oneUp;
};
/** Module for status monitoring depending on a maximum threshold value*/
template<typename T>
struct MaxMonitor : public StatusMonitorImpl<T> {
using StatusMonitorImpl<T>::StatusMonitorImpl;
Martin Killenberg
committed
/** WARNING state to be reported if threshold is reached or exceeded*/
ScalarPushInput<T> warning{this, "upperWarningThreshold", "", "", StatusMonitor::_parameterTags};
Martin Killenberg
committed
/** ERROR state to be reported if threshold is reached or exceeded*/
ScalarPushInput<T> error{this, "upperErrorThreshold", "", "", StatusMonitor::_parameterTags};
/**This is where state evaluation is done*/
void mainLoop() {
/** If there is a change either in value monitored or in thershold values, the status is re-evaluated*/
ReadAnyGroup group{StatusMonitorImpl<T>::oneUp.watch, StatusMonitorImpl<T>::disable, warning, error};
while(true) {
// evaluate and publish first, then read and wait. This takes care of the publishing the initial variables
if(StatusMonitorImpl<T>::disable != 0) {
StatusMonitorImpl<T>::status = OFF;
else if(StatusMonitorImpl<T>::oneUp.watch >= error) {
StatusMonitorImpl<T>::status = ERROR;
}
else if(StatusMonitorImpl<T>::oneUp.watch >= warning) {
StatusMonitorImpl<T>::status = WARNING;
}
else {
}
}
}
};
/** Module for status monitoring depending on a minimum threshold value*/
template<typename T>
struct MinMonitor : public StatusMonitorImpl<T> {
using StatusMonitorImpl<T>::StatusMonitorImpl;
/** WARNING state to be reported if threshold is crossed*/
ScalarPushInput<T> warning{this, "lowerWarningThreshold", "", "", StatusMonitor::_parameterTags};
/** ERROR state to be reported if threshold is crossed*/
ScalarPushInput<T> error{this, "lowerErrorThreshold", "", "", StatusMonitor::_parameterTags};
/**This is where state evaluation is done*/
void mainLoop() {
/** If there is a change either in value monitored or in thershold values, the status is re-evaluated*/
ReadAnyGroup group{StatusMonitorImpl<T>::oneUp.watch, StatusMonitorImpl<T>::disable, warning, error};
while(true) {
if(StatusMonitorImpl<T>::disable != 0) {
StatusMonitorImpl<T>::status = OFF;
else if(StatusMonitorImpl<T>::oneUp.watch <= error) {
StatusMonitorImpl<T>::status = ERROR;
}
else if(StatusMonitorImpl<T>::oneUp.watch <= warning) {
StatusMonitorImpl<T>::status = WARNING;
}
else {
}
}
}
};
/** Module for status monitoring depending on range of threshold values.
* As long as a monitored value is in the range defined by user it goes
* to error or warning state. If the monitored value exceeds the upper limmit
Martin Killenberg
committed
* or goes under the lowerthreshold the state reported will be always OK.
* IMPORTANT: This module does not check for ill logic, so make sure to
* set the ranges correctly to issue warning or error.
*/
template<typename T>
struct RangeMonitor : public StatusMonitorImpl<T> {
using StatusMonitorImpl<T>::StatusMonitorImpl;
/** WARNING state to be reported if value is in between the upper and
Martin Killenberg
committed
* lower threshold including the start and end of thresholds.
ScalarPushInput<T> warningUpperThreshold{this, "upperWarningThreshold", "", "", StatusMonitor::_parameterTags};
ScalarPushInput<T> warningLowerThreshold{this, "lowerWarningThreshold", "", "", StatusMonitor::_parameterTags};
/** ERROR state to be reported if value is in between the upper and
Martin Killenberg
committed
* lower threshold including the start and end of thresholds.
ScalarPushInput<T> errorUpperThreshold{this, "upperErrorThreshold", "", "", StatusMonitor::_parameterTags};
ScalarPushInput<T> errorLowerThreshold{this, "lowerErrorThreshold", "", "", StatusMonitor::_parameterTags};
/**This is where state evaluation is done*/
void mainLoop() {
/** If there is a change either in value monitored or in thershold values, the status is re-evaluated*/
ReadAnyGroup group{StatusMonitorImpl<T>::oneUp.watch, StatusMonitorImpl<T>::disable, warningUpperThreshold,
warningLowerThreshold, errorUpperThreshold, errorLowerThreshold};
while(true) {
if(StatusMonitorImpl<T>::disable != 0) {
StatusMonitorImpl<T>::status = OFF;
// Check for error limits first. Like this they supersede the warning,
// even if they are stricter then the warning limits (mis-configuration)
else if(StatusMonitorImpl<T>::oneUp.watch <= errorLowerThreshold ||
StatusMonitorImpl<T>::oneUp.watch >= errorUpperThreshold) {
StatusMonitorImpl<T>::status = ERROR;
}
else if(StatusMonitorImpl<T>::oneUp.watch <= warningLowerThreshold ||
StatusMonitorImpl<T>::oneUp.watch >= warningUpperThreshold) {
StatusMonitorImpl<T>::status = WARNING;
}
else {
}
}
}
};
/** Module for status monitoring of an exact value.
* If value monitored is not exactly the same. an error state will be
* reported.*/
template<typename T>
struct ExactMonitor : public StatusMonitorImpl<T> {
using StatusMonitorImpl<T>::StatusMonitorImpl;
/**ERROR state if value is not equal to requiredValue*/
ScalarPushInput<T> requiredValue{this, "requiredValue", "", "", StatusMonitor::_parameterTags};
/**This is where state evaluation is done*/
void mainLoop() {
/** If there is a change either in value monitored or in requiredValue, the status is re-evaluated*/
ReadAnyGroup group{StatusMonitorImpl<T>::oneUp.watch, StatusMonitorImpl<T>::disable, requiredValue};
while(true) {
if(StatusMonitorImpl<T>::disable != 0) {
StatusMonitorImpl<T>::status = OFF;
else if(StatusMonitorImpl<T>::oneUp.watch != requiredValue) {
StatusMonitorImpl<T>::status = ERROR;
}
else {
}
}
}
};
/** Module for On/off status monitoring.
* If value monitored is different then desired state (on/off) an error
* will be reported, otherwise OFF(0) or OK(1) depending on state.
*/
template<typename T>
struct StateMonitor : public StatusMonitorImpl<T> {
using StatusMonitorImpl<T>::StatusMonitorImpl;
Martin Killenberg
committed
/// The state that we are supposed to have
ScalarPushInput<T> nominalState{this, "nominalState", "", "", StatusMonitor::_parameterTags};
/**This is where state evaluation is done*/
void mainLoop() {
/** If there is a change either in value monitored or in state, the status is re-evaluated*/
ReadAnyGroup group{StatusMonitorImpl<T>::oneUp.watch, StatusMonitorImpl<T>::disable, nominalState};
while(true) {
if(StatusMonitorImpl<T>::disable != 0) {
StatusMonitorImpl<T>::status = OFF;
else if(StatusMonitorImpl<T>::oneUp.watch != nominalState) {
StatusMonitorImpl<T>::status = ERROR;
}
Martin Killenberg
committed
else if(nominalState == OK || nominalState == OFF) {
StatusMonitorImpl<T>::status = nominalState;
}
}
}
};
} // namespace ChimeraTK
#endif // CHIMERATK_STATUS_MONITOR_H