Actually added the files for msgPrintControl
This commit is contained in:
@ -24,16 +24,6 @@ formatting:
|
||||
tags:
|
||||
- sinq
|
||||
|
||||
# clangtidy:
|
||||
# stage: lint
|
||||
# script:
|
||||
# - curl https://docker.psi.ch:5000/v2/_catalog
|
||||
# # - dnf update -y
|
||||
# # - dnf install -y clang-tools-extra
|
||||
# # - clang-tidy sinqEPICSApp/src/*.cpp sinqEPICSApp/src/*.c sinqEPICSApp/src/*.h -checks=cppcoreguidelines-*,cert-*
|
||||
# # tags:
|
||||
# # - sinq
|
||||
|
||||
build_module:
|
||||
stage: build
|
||||
script:
|
||||
|
100
src/msgPrintControl.cpp
Normal file
100
src/msgPrintControl.cpp
Normal file
@ -0,0 +1,100 @@
|
||||
#include "msgPrintControl.h"
|
||||
#include <unordered_map>
|
||||
|
||||
msgPrintControlKey::msgPrintControlKey(char *controller, int axisNo,
|
||||
const char *functionName, int line) {
|
||||
controller_ = controller;
|
||||
axisNo_ = axisNo;
|
||||
line_ = line;
|
||||
functionName_ = functionName;
|
||||
}
|
||||
|
||||
void msgPrintControlKey::format(char *buffer, size_t bufferSize) {
|
||||
snprintf(buffer, bufferSize, "controller %s, axis %d, function %s, line %d",
|
||||
controller_.c_str(), axisNo_, functionName_, line_);
|
||||
}
|
||||
|
||||
// =============================================================================
|
||||
|
||||
msgPrintControl::msgPrintControl(size_t maxRepetitions) {
|
||||
maxRepetitions_ = maxRepetitions;
|
||||
}
|
||||
|
||||
bool msgPrintControl::shouldBePrinted(msgPrintControlKey &key, bool wantToPrint,
|
||||
asynUser *pasynUser) {
|
||||
|
||||
// Reset the suffix
|
||||
suffix_[0] = 0;
|
||||
|
||||
if (wantToPrint) {
|
||||
/*
|
||||
We want to print the message associated with key -> Check if the number
|
||||
of allowed repetitions is exceeded. If true, inform the user that
|
||||
further output is suppressed.
|
||||
*/
|
||||
if (map_.find(key) != map_.end()) {
|
||||
size_t repetitions = map_[key];
|
||||
if (repetitions < maxRepetitions_) {
|
||||
// Number of allowed repetitions not exceeded -> Printing the
|
||||
// message is ok.
|
||||
map_[key] = repetitions + 1;
|
||||
return true;
|
||||
} else if (repetitions == maxRepetitions_) {
|
||||
// Reached number of allowed repetitions -> Printing the message
|
||||
// is ok, but further trys are rejected.
|
||||
char formattedKey[100] = {0};
|
||||
key.format(formattedKey, sizeof(formattedKey));
|
||||
snprintf(suffix_, sizeof(suffix_),
|
||||
" Further repetition of this error message (key "
|
||||
"\"%s\") is suppressed.",
|
||||
formattedKey);
|
||||
map_[key] = repetitions + 1;
|
||||
return true;
|
||||
} else {
|
||||
// Exceeded number of allowed repetitions -> Do not print the
|
||||
// message
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
// Message is not yet in map -> create an entry so it is watched in
|
||||
// the future.
|
||||
map_[key] = 1;
|
||||
return true;
|
||||
}
|
||||
|
||||
} else {
|
||||
/*
|
||||
We do not want to print the message associated with key -> If the key is
|
||||
part of the map, set the counter back to zero.
|
||||
*/
|
||||
if (map_.find(key) != map_.end()) {
|
||||
if (map_[key] != 0) {
|
||||
char formattedKey[100] = {0};
|
||||
key.format(formattedKey, sizeof(formattedKey));
|
||||
asynPrint(pasynUser, ASYN_TRACE_ERROR,
|
||||
"Controller \"%s\", axis %d => %s, line %d\nError "
|
||||
"associated with key \"%s\" has been resolved.\n",
|
||||
key.controller_.c_str(), key.axisNo_,
|
||||
key.functionName_, key.line_, formattedKey);
|
||||
map_[key] = 0;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool msgPrintControl::shouldBePrinted(char *portName, int axisNo,
|
||||
const char *functionName, int line,
|
||||
bool wantToPrint, asynUser *pasynUser) {
|
||||
msgPrintControlKey key =
|
||||
msgPrintControlKey(portName, axisNo, functionName, __LINE__);
|
||||
return shouldBePrinted(key, wantToPrint, pasynUser);
|
||||
}
|
||||
|
||||
void msgPrintControl::resetCount(msgPrintControlKey &key) {
|
||||
if (map_.find(key) != map_.end()) {
|
||||
map_[key] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
char *msgPrintControl::getSuffix() { return suffix_; }
|
133
src/msgPrintControl.h
Normal file
133
src/msgPrintControl.h
Normal file
@ -0,0 +1,133 @@
|
||||
#ifndef msgPrintControl_H
|
||||
#define msgPrintControl_H
|
||||
|
||||
#include <asynDriver.h>
|
||||
#include <string.h>
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
|
||||
/**
|
||||
* @brief Class to identify a message print location. See the docstring of
|
||||
* `msgPrintControl` on how to use this key.
|
||||
*
|
||||
*/
|
||||
class msgPrintControlKey {
|
||||
public:
|
||||
std::string controller_;
|
||||
// -1 is a non-axis specific message
|
||||
int axisNo_;
|
||||
const char *functionName_;
|
||||
int line_;
|
||||
|
||||
msgPrintControlKey(char *controller_, int axisNo, const char *fileName,
|
||||
int line);
|
||||
|
||||
bool operator==(const msgPrintControlKey &other) const {
|
||||
return axisNo_ == other.axisNo_ && line_ == other.line_ &&
|
||||
strcmp(functionName_, other.functionName_) == 0 &&
|
||||
controller_ == other.controller_;
|
||||
}
|
||||
|
||||
void format(char *buffer, size_t bufferSize);
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Implementation of the hash functionality for msgPrintControlKey
|
||||
*
|
||||
*/
|
||||
namespace std {
|
||||
template <> struct hash<msgPrintControlKey> {
|
||||
size_t operator()(const msgPrintControlKey &obj) const {
|
||||
// Combine the hashes of the members (x and y)
|
||||
size_t h1 = std::hash<std::string>{}(obj.controller_);
|
||||
size_t h2 = hash<int>{}(obj.axisNo_);
|
||||
size_t h3 = std::hash<const char *>{}(obj.functionName_);
|
||||
size_t h4 = hash<int>{}(obj.line_);
|
||||
// Combine the hashes (simple XOR and shifting technique)
|
||||
return h1 ^ (h2 << 1) ^ (h3 << 2) ^ (h4 << 3);
|
||||
}
|
||||
};
|
||||
} // namespace std
|
||||
|
||||
/**
|
||||
* @brief Class to control the number of repetitions of error messages
|
||||
*
|
||||
* This class is used to prevent excessive repetitions of identical error
|
||||
* messages. For example, if the communication between a controller and an
|
||||
* axis fails, a corresponding error message is created in each poll. This
|
||||
* could "flood" the IOC shell with noise. To prevent this, this class keeps
|
||||
* track of the number of subsequent error message repetition. Each message is
|
||||
* uniquely identified by "msgPrintControlKey". The function shouldBePrinted
|
||||
* can be used in order to see if a message should be printed or not:
|
||||
*
|
||||
* ```
|
||||
* const char* controller = "MCU" // Name of the controller
|
||||
* int axisNo = 0; // Number of the axis
|
||||
* bool wantToPrint = evaluateConditions(...); *
|
||||
* if (msgPrintControl.shouldBePrinted(controller, axisNo, __PRETTY_FUNCTION__,
|
||||
* __LINE__, wantToPrint)) { asynPrint(...)
|
||||
* }
|
||||
*
|
||||
* ```
|
||||
*/
|
||||
class msgPrintControl {
|
||||
public:
|
||||
msgPrintControl(size_t maxRepetitions);
|
||||
|
||||
/**
|
||||
* @brief Checks if the error message associated with "key" has been printed
|
||||
* more than "maxRepetitions_" times in a row. If yes, returns false,
|
||||
* otherwise true. Counter is reset if wantToPrint is false.
|
||||
*
|
||||
* If the conditions for printing a message are met, "wantToPrint" must be
|
||||
* set to true. The function then checks if "maxRepetitions_" has been
|
||||
* exceeded. If yes, the function returns no, indicating that the message
|
||||
* should not be printed. If no, the number of repetitions stored in the map
|
||||
* is incremented and the function returns true, indicating that the message
|
||||
* should be printed.
|
||||
*
|
||||
* If the conditions for printing a message are not met, "wantToPrint" must
|
||||
* be set to false. This resets the map entry.
|
||||
*
|
||||
* @param key Key associated with the message, used to
|
||||
* identify individual messages
|
||||
* @param wantToPrint If the message associated with key should be
|
||||
* printed, this value should be true, otherwise false.
|
||||
* @return bool If true, the message should be printed, if
|
||||
* false, it should not.
|
||||
*/
|
||||
bool shouldBePrinted(msgPrintControlKey &key, bool wantToPrint,
|
||||
asynUser *pasynUser);
|
||||
|
||||
/**
|
||||
* @brief Like `shouldBePrinted(msgPrintControlKey key, bool wantToPrint)`,
|
||||
* but constructs the key from the first four arguments.
|
||||
*
|
||||
* @param controller_
|
||||
* @param axisNo
|
||||
* @param fileName
|
||||
* @param line
|
||||
* @param wantToPrint
|
||||
* @return true
|
||||
* @return false
|
||||
*/
|
||||
bool shouldBePrinted(char *controller, int axisNo, const char *functionName,
|
||||
int line, bool wantToPrint, asynUser *pasynUser);
|
||||
|
||||
void resetCount(msgPrintControlKey &key);
|
||||
|
||||
/**
|
||||
* @brief Maximum number of times a message is printed before it is
|
||||
* suppressed.
|
||||
*
|
||||
*/
|
||||
size_t maxRepetitions_;
|
||||
|
||||
char *getSuffix();
|
||||
|
||||
private:
|
||||
std::unordered_map<msgPrintControlKey, size_t> map_;
|
||||
char suffix_[200] = {0};
|
||||
};
|
||||
|
||||
#endif
|
Reference in New Issue
Block a user