Rate-limit duplicate error messages to avoid flooding console.

Fixes artf4809.

In both C++ and Java, error messages are being sent to both the console
(via stdout/stderr) and being reported via the HAL.  We don't want to
remove the stdout/stderr reporting at present because users debugging only
via netconsole (e.g. using riolog) won't see the HAL-reported errors.  Until
there's an alternative means to getting the HAL-reported errors to those
users, instead store the previous 5 error messages and don't duplicate them
more often than once per second.

Changes the error reporting from setErrorData() to sendError(), which
improves driver station error reporting.  The "location" in C++ is given as
the immediate caller (e.g. the WPILib function).  The "location" in Java is
given as the first user function in the call stack.  Note the full call stack
is provided in both instances.

Change-Id: I590dd63dcb66825301ebb260aff00cd8d7d501ed
This commit is contained in:
Peter Johnson
2016-02-04 22:29:11 -08:00
parent f17d27aacf
commit 3c3b2c75c0
12 changed files with 244 additions and 74 deletions

View File

@@ -32,6 +32,7 @@ static tGlobal *global = nullptr;
static tSysWatchdog *watchdog = nullptr;
static priority_mutex timeMutex;
static priority_mutex msgMutex;
static uint32_t timeEpoch = 0;
static uint32_t prevFPGATime = 0;
static void* rolloverNotifier = nullptr;
@@ -232,6 +233,54 @@ int HALSetErrorData(const char *errors, int errorsLength, int wait_ms)
return setErrorData(errors, errorsLength, wait_ms);
}
int HALSendError(int isError, int32_t errorCode, int isLVCode,
const char *details, const char *location, const char *callStack,
int printMsg)
{
// Avoid flooding console by keeping track of previous 5 error
// messages and only printing again if they're longer than 1 second old.
static constexpr int KEEP_MSGS = 5;
std::lock_guard<priority_mutex> lock(msgMutex);
static std::string prev_msg[KEEP_MSGS];
static uint64_t prev_msg_time[KEEP_MSGS] = { 0, 0, 0 };
int32_t status = 0;
uint64_t curTime = getFPGATime(&status);
int i;
for (i=0; i<KEEP_MSGS; ++i) {
if (prev_msg[i] == details) break;
}
int retval = 0;
if (i == KEEP_MSGS || (curTime - prev_msg_time[i]) >= 1000000) {
retval = FRC_NetworkCommunication_sendError(isError, errorCode, isLVCode, details, location, callStack);
if (printMsg) {
if (location && location[0] != '\0') {
fprintf(stderr, "%s at %s: ",
isError ? "Error" : "Warning",
location);
}
fprintf(stderr, "%s\n", details);
if (callStack && callStack[0] != '\0') {
fprintf(stderr, "%s\n", callStack);
}
}
if (i == KEEP_MSGS) {
// replace the oldest one
i = 0;
uint64_t first = prev_msg_time[0];
for (int j=1; j<KEEP_MSGS; ++j) {
if (prev_msg_time[j] < first) {
first = prev_msg_time[j];
i = j;
}
}
prev_msg[i] = details;
}
prev_msg_time[i] = curTime;
}
return retval;
}
bool HALGetSystemActive(int32_t *status)
{