Actually added the files for msgPrintControl
This commit is contained in:
@ -24,16 +24,6 @@ formatting:
|
|||||||
tags:
|
tags:
|
||||||
- sinq
|
- 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:
|
build_module:
|
||||||
stage: build
|
stage: build
|
||||||
script:
|
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