Skip to content

Commit

Permalink
Merge pull request #90 from sy-c/master
Browse files Browse the repository at this point in the history
v2.7.0
  • Loading branch information
sy-c authored Jul 25, 2024
2 parents cba4443 + 73a1f67 commit 0a80a64
Show file tree
Hide file tree
Showing 4 changed files with 139 additions and 0 deletions.
4 changes: 4 additions & 0 deletions doc/releaseNotes.md
Original file line number Diff line number Diff line change
Expand Up @@ -141,3 +141,7 @@ This file describes the main feature changes for each InfoLogger released versio

## v2.6.0 - 24/01/2024
- Updated SWIG version requirement to allow generation of Python3 bindings.

## v2.7.0 - 25/07/2024
- Added functions to keep a history of latest log messages: see historyReset() and historyGetSummary().
- Added function to register error codes descriptions to format message summaries in history.
28 changes: 28 additions & 0 deletions include/InfoLogger/InfoLogger.hxx
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
#include <type_traits>
#include <atomic>
#include <chrono>
#include <vector>

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


/// Functions to keep an history of messages

/// Reset history
/// This function enables storing next log messages injected in a buffer (eg for later error reporting). Existing history is cleared.
/// parameters:
/// messagesToKeep: number of messages stored in buffer
/// rotate: if set, newer messages overwrite stored messages stored in buffer (i.e. history keeps latest messages). By default, history keeps first messages.
/// filterSeverity: messages with lower severity are not stored in history.
/// filterLevel: messages with lower level are not stored in history.
void historyReset(unsigned int messagesToKeep = 0, bool rotate = false, InfoLogger::Severity filterSeverity = InfoLogger::Severity::Error, InfoLogger::Level filterLevel = InfoLogger::Level::Support);

/// Get a summary of messages stored in history buffer.
/// The buffer is not cleared (use historyReset to do so).
/// Each message is a simplified text.
/// parameters:
/// summary: a variable where to store a copy of the messages currently available in history buffer
/// returns: 0 on success
void historyGetSummary(std::vector<std::string> &summary);

/// Function to register a table converting error codes to a meaningful text.
/// Used for formatting message summary.
/// parameters:
/// errorCodes: a vector of key-value pairs. First is the error code, second is a text description
/// 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).
void registerErrorCodes(const std::vector<std::pair<int, std::string>> errorCodes, bool clear = 0);

///////////////////////
/// internals
///////////////////////
Expand Down
90 changes: 90 additions & 0 deletions src/InfoLogger.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@
#include <thread>
#include <memory>
#include <functional>
#include <queue>
#include <mutex>

#include "InfoLoggerMessageHelper.h"
#include "Common/LineBuffer.h"
Expand Down Expand Up @@ -167,6 +169,26 @@ int infoLoggerLogDebug(InfoLoggerHandle handle, const char* message, ...)
return err;
}


// function to convert severities to a priority number (high priority = small number)
int getIdFromSeverity(InfoLogger::Severity s) {
switch (s) {
case InfoLogger::Severity::Fatal :
return 1;
case InfoLogger::Severity::Error :
return 2;
case InfoLogger::Severity::Warning :
return 3;
case InfoLogger::Severity::Info :
return 4;
case InfoLogger::Severity::Debug :
return 5;
default:
return 6;
}
}


/////////////////////////////////////////////////////////

namespace AliceO2
Expand Down Expand Up @@ -420,7 +442,18 @@ class InfoLogger::Impl
bool filterDiscardFileEnabled = false; // when set, discarded messages go to file
bool filterDiscardFileIgnoreDebug = false; // when set, debug messages even when discarded and filterDiscardFileEnabled=true do not go to file
SimpleLog filterDiscardFile; // file object where to save discarded messages

// history
unsigned int historyMessagesToKeep = 0;
bool historyRotate = false;
int historyFilterSeverity = -1;
int historyFilterLevel = -1;
std::queue<std::string> historyMessages; // messages currently in history queue
std::mutex historyMutex; // lock to avoid concurrent calls on history functions

// error code conversion table
std::vector<std::pair<int, std::string>> errorCodesTable; // first: error code, second: description

// message flood prevention
// constants
bool flood_protection = 1; // if set, flood protection mechanism enabled
Expand Down Expand Up @@ -787,6 +820,32 @@ int InfoLogger::Impl::pushMessage(const InfoLoggerMessageOption& options, const
msgHelper.MessageToText(&msg, buffer, sizeof(buffer), InfoLoggerMessageHelper::Format::Debug);
puts(buffer);
}

// keep history
std::unique_lock<std::mutex> lock(historyMutex);
if (historyMessagesToKeep > 0) {
if (historyRotate || (historyMessagesToKeep > historyMessages.size())) {
if ((getIdFromSeverity(options.severity) <= historyFilterSeverity) && (options.level <= historyFilterLevel)) {
std::string summary;
summary += "code "+ std::to_string(options.errorCode);
if (options.errorCode != undefinedMessageOption.errorCode) {
for(const auto &p: errorCodesTable) {
if (p.first == options.errorCode) {
summary += " : " + p.second;
break;
}
}
summary += " - ";
}
summary += messageBody;
historyMessages.push(std::move(summary));
if (historyRotate && (historyMessagesToKeep > historyMessages.size())) {
historyMessages.pop();
}
}
}
}

return 0;
}

Expand Down Expand Up @@ -1282,6 +1341,37 @@ void InfoLogger::resetMessageCount() {
mPimpl->resetMessageCount();
}

void InfoLogger::historyReset(unsigned int messagesToKeep, bool rotate, InfoLogger::Severity filterSeverity, InfoLogger::Level filterLevel) {
std::unique_lock<std::mutex> lock(mPimpl->historyMutex);
mPimpl->historyMessagesToKeep = messagesToKeep;
mPimpl->historyRotate = rotate;
mPimpl->historyFilterSeverity = getIdFromSeverity(filterSeverity);
mPimpl->historyFilterLevel = (int)filterLevel;
mPimpl->historyMessages = {}; // clear queue
}

void InfoLogger::historyGetSummary(std::vector<std::string> &summary) {
std::unique_lock<std::mutex> lock(mPimpl->historyMutex);
summary.clear();
summary.reserve(mPimpl->historyMessages.size());
while (!mPimpl->historyMessages.empty())
{
summary.push_back(std::move(mPimpl->historyMessages.front()));
mPimpl->historyMessages.pop();
}
}

void InfoLogger::registerErrorCodes(const std::vector<std::pair<int, std::string>> errorCodes, bool clear) {
std::unique_lock<std::mutex> lock(mPimpl->historyMutex);
if (clear) {
mPimpl->errorCodesTable.clear();
}
for(const auto &c: errorCodes) {
mPimpl->errorCodesTable.push_back({c.first, c.second});
}
}


// end of namespace
} // namespace InfoLogger
} // namespace AliceO2
Expand Down
17 changes: 17 additions & 0 deletions test/testInfoLogger.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,23 @@ int main()
{
InfoLogger theLog;

if (0) {
theLog.historyReset(2);
theLog.registerErrorCodes({{123, "error"}, {124, "fatal"}});
theLog.log(LogInfoSupport_(100), "test info");
theLog.log(LogErrorSupport_(123), "test error 123");
theLog.log(LogInfoDevel_(100), "test info");
theLog.log(LogFatalSupport_(124), "test fatal 124");
std::vector<std::string> m;
theLog.historyGetSummary(m);
printf("log summary:\n");
for(const auto&s: m) {
printf(" %s\n",s.c_str());
}
printf("\n");
return 0;
}

theLog.log("infoLogger message test");
printf("Message on stdout (initial stdout)\n");
theLog.setStandardRedirection(1);
Expand Down

0 comments on commit 0a80a64

Please sign in to comment.