Added _minRepetitions to msgPrintControl
Test And Build / Lint (push) Successful in 6s
Test And Build / Build (push) Successful in 7s

This is an API breaking change, because the previous maxRepetitions_
member (size_t) is replaced with the msgPrintControlOptions struct.
However, since this value is only used once in the entire sinqMotor
ecosystem, I deemed this an acceptable tradeoff and did not bump the
major version.
This commit is contained in:
mathis_s committed 2026-09-17 15:59:44 +02:00
1 parent 7cad532a29
commit b173b9554b
2 files changed
+93 -66

No files matched your search

+51 -58
View File
@@ -5,9 +5,9 @@
msgPrintControlKey::msgPrintControlKey(char *controller, int axisNo,
const char *functionName, int line,
size_t maxRepetitions)
msgPrintControlOptions options)
: controller_(controller), axisNo_(axisNo), functionName_(functionName),
line_(line), maxRepetitions_(maxRepetitions) {}
line_(line), options_(options) {}
void msgPrintControlKey::format(char *buffer, size_t bufferSize) {
snprintf(buffer, bufferSize, "controller %s, axis %d, function %s, line %d",
@@ -22,76 +22,69 @@ msgPrintControl::~msgPrintControl() = default;
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 < key.maxRepetitions_) {
// Number of allowed repetitions not exceeded -> Printing the
// message is ok.
map_[key] = repetitions + 1;
return true;
} else if (repetitions == key.maxRepetitions_) {
// Reached number of allowed repetitions -> Printing the message
// is ok, but further trys are rejected.
if (!wantToPrint) {
auto iter = map_.find(key);
if (iter != map_.end() && iter->second != 0) {
if (pasynUser != nullptr) {
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;
asynPrint(
pasynUser, ASYN_TRACE_ERROR,
"Controller \"%s\", axis %d => %s, line %d\n"
"Error associated with key \"%s\" has been resolved.\n",
key.controller_.c_str(), key.axisNo_,
key.functionName_.c_str(), key.line_, formattedKey);
}
} else {
// Message is not yet in map -> create an entry so it is watched in
// the future.
map_[key] = 1;
return true;
iter->second = 0;
}
} 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) {
if (pasynUser != nullptr) {
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_.c_str(), key.line_, formattedKey);
}
map_[key] = 0;
}
}
return false;
}
auto iter = map_.find(key);
if (iter == map_.end()) {
// First occurrence.
map_[key] = 1;
return key.options_.minRepetitions == 0;
}
size_t &repetitions = iter->second;
++repetitions;
// Print one final message when suppression starts.
if (repetitions == key.options_.maxRepetitions + 1) {
char formattedKey[100] = {0};
key.format(formattedKey, sizeof(formattedKey));
snprintf(suffix_, sizeof(suffix_),
" Further repetition of this error message (key "
"\"%s\") is suppressed.",
formattedKey);
return true;
}
// Suppress everything after the notification.
if (repetitions > key.options_.maxRepetitions) {
return false;
}
// Suppress occurrences before minRepetitions.
return repetitions > key.options_.minRepetitions;
}
bool msgPrintControl::shouldBePrinted(char *portName, int axisNo,
const char *functionName, int line,
bool wantToPrint, asynUser *pasynUser,
size_t maxRepetitions) {
msgPrintControlKey key = msgPrintControlKey(portName, axisNo, functionName,
line, maxRepetitions);
msgPrintControlOptions options) {
msgPrintControlKey key =
msgPrintControlKey(portName, axisNo, functionName, line, options);
return shouldBePrinted(key, wantToPrint, pasynUser);
}
+42 -8
View File
@@ -3,8 +3,6 @@
#ifndef msgPrintControl_H
#define msgPrintControl_H
#define DefaultMaxRepetitions 4
// The EPICS libaries do not follow -Weffc++
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Weffc++"
@@ -18,6 +16,41 @@
#include <string>
#include <unordered_map>
/**
* @brief Configuration options controlling repetition of a message.
*
* These options determine how many consecutive occurrences of a message
* are suppressed or printed by msgPrintControl.
*
* A message is identified by its msgPrintControlKey. The repetition count
* is reset when `wantToPrint` is false.
*/
struct msgPrintControlOptions {
/**
* @brief Maximum number of consecutive occurrences that are printed.
*
* Once this number of consecutive occurrences has been reached,
* subsequent occurrences are suppressed until the repetition count
* is reset.
*
* The default value is 4.
*/
size_t maxRepetitions = 4;
/**
* @brief Minimum number of consecutive repetitions before printing.
*
* This many consecutive occurrences are suppressed before the message
* is printed. For example, a value of 2 suppresses the first two
* occurrences and prints the third and subsequent occurrences.
*
* A value of 0 disables the minimum-repetition requirement and
* preserves the original behaviour, where the first occurrence is
* printed.
*/
size_t minRepetitions = 0;
};
/**
* @brief Class to identify a message print location. See the docstring of
* `msgPrintControl` on how to use this key.
@@ -26,7 +59,7 @@
class HIDDEN msgPrintControlKey {
public:
msgPrintControlKey(char *controller_, int axisNo, const char *fileName,
int line, size_t maxRepetitions = DefaultMaxRepetitions);
int line, msgPrintControlOptions options = {});
bool operator==(const msgPrintControlKey &other) const {
return axisNo_ == other.axisNo_ && line_ == other.line_ &&
@@ -45,11 +78,12 @@ class HIDDEN msgPrintControlKey {
int line_;
/**
* @brief Maximum number of times a message is printed before it is
* suppressed. This number is not used as part of the hash.
* @brief Repetition-control options for this message.
*
* These options are not part of the key identity and are therefore not
* considered by operator==() or std::hash<msgPrintControlKey>.
*/
size_t maxRepetitions_;
msgPrintControlOptions options_;
};
/**
@@ -106,7 +140,7 @@ class HIDDEN msgPrintControl {
/**
* @brief Checks if the error message associated with "key" has been printed
* more than `this->maxRepetitions_` times in a row. If yes, returns false,
* more than `key->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
@@ -145,7 +179,7 @@ class HIDDEN msgPrintControl {
*/
bool shouldBePrinted(char *controller, int axisNo, const char *functionName,
int line, bool wantToPrint, asynUser *pasynUser,
size_t maxRepetitions = DefaultMaxRepetitions);
msgPrintControlOptions options = {});
/**
* @brief Reset the error message count incremented in `shouldBePrinted` for