Skip to content

Commit 372643e

Browse files
committed
added message history
1 parent cba4443 commit 372643e

File tree

4 files changed

+139
-0
lines changed

4 files changed

+139
-0
lines changed

doc/releaseNotes.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -141,3 +141,7 @@ This file describes the main feature changes for each InfoLogger released versio
141141

142142
## v2.6.0 - 24/01/2024
143143
- Updated SWIG version requirement to allow generation of Python3 bindings.
144+
145+
## next
146+
- Added functions to keep a history of latest log messages: see historyReset() and historyGetSummary().
147+
- Added function to register error codes descriptions to format message summaries in history.

include/InfoLogger/InfoLogger.hxx

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
#include <type_traits>
3030
#include <atomic>
3131
#include <chrono>
32+
#include <vector>
3233

3334
// here are some macros to help including source code info in infologger messages
3435
// to be used to quickly specify "infoLoggerMessageOption" argument in some logging functions
@@ -396,6 +397,33 @@ class InfoLogger
396397
/// Reset counters of messages
397398
void resetMessageCount();
398399

400+
401+
/// Functions to keep an history of messages
402+
403+
/// Reset history
404+
/// This function enables storing next log messages injected in a buffer (eg for later error reporting). Existing history is cleared.
405+
/// parameters:
406+
/// messagesToKeep: number of messages stored in buffer
407+
/// rotate: if set, newer messages overwrite stored messages stored in buffer (i.e. history keeps latest messages). By default, history keeps first messages.
408+
/// filterSeverity: messages with lower severity are not stored in history.
409+
/// filterLevel: messages with lower level are not stored in history.
410+
void historyReset(unsigned int messagesToKeep = 0, bool rotate = false, InfoLogger::Severity filterSeverity = InfoLogger::Severity::Error, InfoLogger::Level filterLevel = InfoLogger::Level::Support);
411+
412+
/// Get a summary of messages stored in history buffer.
413+
/// The buffer is not cleared (use historyReset to do so).
414+
/// Each message is a simplified text.
415+
/// parameters:
416+
/// summary: a variable where to store a copy of the messages currently available in history buffer
417+
/// returns: 0 on success
418+
void historyGetSummary(std::vector<std::string> &summary);
419+
420+
/// Function to register a table converting error codes to a meaningful text.
421+
/// Used for formatting message summary.
422+
/// parameters:
423+
/// errorCodes: a vector of key-value pairs. First is the error code, second is a text description
424+
/// clear: if set, existing table is cleared. Otherwise, it is appended (in this case, duplication of codes is not checked. First one found is used).
425+
void registerErrorCodes(const std::vector<std::pair<int, std::string>> errorCodes, bool clear = 0);
426+
399427
///////////////////////
400428
/// internals
401429
///////////////////////

src/InfoLogger.cxx

Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,8 @@
3434
#include <thread>
3535
#include <memory>
3636
#include <functional>
37+
#include <queue>
38+
#include <mutex>
3739

3840
#include "InfoLoggerMessageHelper.h"
3941
#include "Common/LineBuffer.h"
@@ -167,6 +169,26 @@ int infoLoggerLogDebug(InfoLoggerHandle handle, const char* message, ...)
167169
return err;
168170
}
169171

172+
173+
// function to convert severities to a priority number (high priority = small number)
174+
int getIdFromSeverity(InfoLogger::Severity s) {
175+
switch (s) {
176+
case InfoLogger::Severity::Fatal :
177+
return 1;
178+
case InfoLogger::Severity::Error :
179+
return 2;
180+
case InfoLogger::Severity::Warning :
181+
return 3;
182+
case InfoLogger::Severity::Info :
183+
return 4;
184+
case InfoLogger::Severity::Debug :
185+
return 5;
186+
default:
187+
return 6;
188+
}
189+
}
190+
191+
170192
/////////////////////////////////////////////////////////
171193

172194
namespace AliceO2
@@ -420,7 +442,18 @@ class InfoLogger::Impl
420442
bool filterDiscardFileEnabled = false; // when set, discarded messages go to file
421443
bool filterDiscardFileIgnoreDebug = false; // when set, debug messages even when discarded and filterDiscardFileEnabled=true do not go to file
422444
SimpleLog filterDiscardFile; // file object where to save discarded messages
445+
446+
// history
447+
unsigned int historyMessagesToKeep = 0;
448+
bool historyRotate = false;
449+
int historyFilterSeverity = -1;
450+
int historyFilterLevel = -1;
451+
std::queue<std::string> historyMessages; // messages currently in history queue
452+
std::mutex historyMutex; // lock to avoid concurrent calls on history functions
423453

454+
// error code conversion table
455+
std::vector<std::pair<int, std::string>> errorCodesTable; // first: error code, second: description
456+
424457
// message flood prevention
425458
// constants
426459
bool flood_protection = 1; // if set, flood protection mechanism enabled
@@ -787,6 +820,32 @@ int InfoLogger::Impl::pushMessage(const InfoLoggerMessageOption& options, const
787820
msgHelper.MessageToText(&msg, buffer, sizeof(buffer), InfoLoggerMessageHelper::Format::Debug);
788821
puts(buffer);
789822
}
823+
824+
// keep history
825+
std::unique_lock<std::mutex> lock(historyMutex);
826+
if (historyMessagesToKeep > 0) {
827+
if (historyRotate || (historyMessagesToKeep > historyMessages.size())) {
828+
if ((getIdFromSeverity(options.severity) <= historyFilterSeverity) && (options.level <= historyFilterLevel)) {
829+
std::string summary;
830+
summary += "code "+ std::to_string(options.errorCode);
831+
if (options.errorCode != undefinedMessageOption.errorCode) {
832+
for(const auto &p: errorCodesTable) {
833+
if (p.first == options.errorCode) {
834+
summary += " : " + p.second;
835+
break;
836+
}
837+
}
838+
summary += " - ";
839+
}
840+
summary += messageBody;
841+
historyMessages.push(std::move(summary));
842+
if (historyRotate && (historyMessagesToKeep > historyMessages.size())) {
843+
historyMessages.pop();
844+
}
845+
}
846+
}
847+
}
848+
790849
return 0;
791850
}
792851

@@ -1282,6 +1341,37 @@ void InfoLogger::resetMessageCount() {
12821341
mPimpl->resetMessageCount();
12831342
}
12841343

1344+
void InfoLogger::historyReset(unsigned int messagesToKeep, bool rotate, InfoLogger::Severity filterSeverity, InfoLogger::Level filterLevel) {
1345+
std::unique_lock<std::mutex> lock(mPimpl->historyMutex);
1346+
mPimpl->historyMessagesToKeep = messagesToKeep;
1347+
mPimpl->historyRotate = rotate;
1348+
mPimpl->historyFilterSeverity = getIdFromSeverity(filterSeverity);
1349+
mPimpl->historyFilterLevel = (int)filterLevel;
1350+
mPimpl->historyMessages = {}; // clear queue
1351+
}
1352+
1353+
void InfoLogger::historyGetSummary(std::vector<std::string> &summary) {
1354+
std::unique_lock<std::mutex> lock(mPimpl->historyMutex);
1355+
summary.clear();
1356+
summary.reserve(mPimpl->historyMessages.size());
1357+
while (!mPimpl->historyMessages.empty())
1358+
{
1359+
summary.push_back(std::move(mPimpl->historyMessages.front()));
1360+
mPimpl->historyMessages.pop();
1361+
}
1362+
}
1363+
1364+
void InfoLogger::registerErrorCodes(const std::vector<std::pair<int, std::string>> errorCodes, bool clear) {
1365+
std::unique_lock<std::mutex> lock(mPimpl->historyMutex);
1366+
if (clear) {
1367+
mPimpl->errorCodesTable.clear();
1368+
}
1369+
for(const auto &c: errorCodes) {
1370+
mPimpl->errorCodesTable.push_back({c.first, c.second});
1371+
}
1372+
}
1373+
1374+
12851375
// end of namespace
12861376
} // namespace InfoLogger
12871377
} // namespace AliceO2

test/testInfoLogger.cxx

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,23 @@ int main()
2525
{
2626
InfoLogger theLog;
2727

28+
if (0) {
29+
theLog.historyReset(2);
30+
theLog.registerErrorCodes({{123, "error"}, {124, "fatal"}});
31+
theLog.log(LogInfoSupport_(100), "test info");
32+
theLog.log(LogErrorSupport_(123), "test error 123");
33+
theLog.log(LogInfoDevel_(100), "test info");
34+
theLog.log(LogFatalSupport_(124), "test fatal 124");
35+
std::vector<std::string> m;
36+
theLog.historyGetSummary(m);
37+
printf("log summary:\n");
38+
for(const auto&s: m) {
39+
printf(" %s\n",s.c_str());
40+
}
41+
printf("\n");
42+
return 0;
43+
}
44+
2845
theLog.log("infoLogger message test");
2946
printf("Message on stdout (initial stdout)\n");
3047
theLog.setStandardRedirection(1);

0 commit comments

Comments
 (0)