From b173b9554b0fe46e89d6c1a3e0cce2441384f2ea Mon Sep 17 00:00:00 2001 From: smathis Date: Thu, 17 Sep 2026 15:31:06 +0200 Subject: [PATCH] Added _minRepetitions to msgPrintControl 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. --- src/msgPrintControl.cpp | 109 +++++++++++++++++++--------------------- src/msgPrintControl.h | 50 +++++++++++++++--- 2 files changed, 93 insertions(+), 66 deletions(-) diff --git a/src/msgPrintControl.cpp b/src/msgPrintControl.cpp index 45ec4c5..80ff611 100644 --- a/src/msgPrintControl.cpp +++ b/src/msgPrintControl.cpp @@ -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); } diff --git a/src/msgPrintControl.h b/src/msgPrintControl.h index 2460b52..e0de81a 100644 --- a/src/msgPrintControl.h +++ b/src/msgPrintControl.h @@ -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 #include +/** + * @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. */ - 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