15#include <fairmq/Device.h>
16#include <fairmq/runDevice.h>
18#include "InfoLogger/InfoLogger.hxx"
23#include <unordered_map>
30#include <sys/inotify.h>
33using namespace AliceO2;
35static constexpr size_t MAX_LINES_FILE = 30;
36static constexpr size_t MAX_BYTES_FILE = MAX_LINES_FILE * 512;
37static constexpr size_t MAX_LINES_TOTAL = 1000;
38static constexpr size_t MAX_BYTES_TOTAL = MAX_LINES_TOTAL * 256;
53 printf(
"Monitoring file %s\n",
filename.c_str());
64 EPNMonitor(std::string
path,
bool infoLogger,
int runNumber, std::string partition);
70 void check_add_file(
const std::string&
filename);
71 void sendLog(
const std::string&
file,
const std::string&
message,
72 const InfoLogger::InfoLogger::Severity
severity = InfoLogger::InfoLogger::Severity::Error,
int level = 3);
74 bool mInfoLoggerActive;
75 volatile bool mTerminate =
false;
77 std::unordered_map<std::string, fileMon> mFiles;
79 std::vector<std::regex> mFilters;
80 std::unordered_map<std::string, std::pair<InfoLogger::InfoLogger::Severity, int>> mMapLogTypes;
81 volatile unsigned int mRunNumber;
82 std::string mPartition;
83 unsigned int nLines = 0;
84 unsigned int nBytes = 0;
85 std::unique_ptr<InfoLogger::InfoLogger> mLogger;
86 std::unique_ptr<InfoLogger::InfoLoggerContext> mLoggerContext;
91 mFilters.emplace_back(
"^Info in <");
92 mFilters.emplace_back(
"^Print in <");
93 mFilters.emplace_back(
"^[0-9]{4}-[0-9]{2}-[0-9]{2} [0-9]{2}:[0-9]{2}:[0-9]{2}.[0-9]{6}");
94 mFilters.emplace_back(
"^Warning in <Fit");
95 mFilters.emplace_back(
"^Warning in <TGraph");
96 mFilters.emplace_back(
"^Warning in <TInterpreter");
97 mFilters.emplace_back(
"Dividing histograms with different labels");
98 mMapLogTypes.emplace(
"(core dumped)", std::pair<InfoLogger::InfoLogger::Severity, int>{InfoLogger::InfoLogger::Severity::Error, 1});
99 mMapLogTypes.emplace(
"Warning in <", std::pair<InfoLogger::InfoLogger::Severity, int>{InfoLogger::InfoLogger::Severity::Warning, 11});
100 mMapLogTypes.emplace(
"Error in <", std::pair<InfoLogger::InfoLogger::Severity, int>{InfoLogger::InfoLogger::Severity::Error, 2});
101 mMapLogTypes.emplace(
"Fatal in <", std::pair<InfoLogger::InfoLogger::Severity, int>{InfoLogger::InfoLogger::Severity::Fatal, 1});
102 mMapLogTypes.emplace(
"*** Break ***", std::pair<InfoLogger::InfoLogger::Severity, int>{InfoLogger::InfoLogger::Severity::Fatal, 1});
103 mInfoLoggerActive = infoLogger;
105 mRunNumber = runNumber;
106 mPartition = partition;
108 mLogger = std::make_unique<InfoLogger::InfoLogger>();
109 mLoggerContext = std::make_unique<InfoLogger::InfoLoggerContext>();
110 mLoggerContext->setField(InfoLogger::InfoLoggerContext::FieldName::Partition, partition !=
"" ? partition :
"unspecified");
111 mLoggerContext->setField(InfoLogger::InfoLoggerContext::FieldName::System, std::string(
"STDERR"));
113 mThread = std::thread(&EPNMonitor::thread,
this);
122void EPNMonitor::check_add_file(
const std::string&
filename)
125 static const std::regex match_stderr(
"_err\\.log$");
126 if (std::regex_search(
filename, match_stderr)) {
131void EPNMonitor::sendLog(
const std::string&
file,
const std::string&
message,
const InfoLogger::InfoLogger::Severity
severity,
int level)
133 if (mInfoLoggerActive) {
134 mLoggerContext->setField(InfoLogger::InfoLoggerContext::FieldName::Facility, (
"stderr/" +
file).substr(0, 31));
135 mLoggerContext->setField(InfoLogger::InfoLoggerContext::FieldName::Run, mRunNumber != 0 ?
std::to_string(mRunNumber) :
"unspecified");
136 static const InfoLogger::InfoLogger::InfoLoggerMessageOption opt = {
severity,
level, InfoLogger::InfoLogger::undefinedMessageOption.errorCode, InfoLogger::InfoLogger::undefinedMessageOption.sourceFile, InfoLogger::InfoLogger::undefinedMessageOption.sourceLine};
137 mLogger->log(opt, *mLoggerContext,
"stderr: %s",
file ==
"SYSLOG" ? (std::string(
"[GLOBAL SYSLOG]: ") +
message).c_str() :
message.c_str());
143void EPNMonitor::thread()
145 printf(
"EPN stderr Monitor active\n");
148 std::string syslogfile =
"/var/log/infologger_syslog";
150 file.open(syslogfile, std::ifstream::in);
152 mFiles.emplace(std::piecewise_construct, std::forward_as_tuple(syslogfile), std::forward_as_tuple(std::string(
"SYSLOG"), std::move(
file)));
158 static constexpr size_t BUFFER_SIZE = 64 * 1024;
159 std::vector<char> evt_buffer(BUFFER_SIZE);
160 std::vector<char> text_buffer(8192);
162 wd = inotify_add_watch(fd, mPath.c_str(), IN_CREATE);
166 pollfd pfd = {fd, POLLIN, 0};
168 for (
const auto&
entry :
std::filesystem::directory_iterator(mPath)) {
169 if (
entry.is_regular_file()) {
170 check_add_file(
entry.path().filename());
174 auto lastTime = std::chrono::system_clock::now();
175 while (!mTerminate) {
176 if (poll(&pfd, 1, 50) > 0) {
177 int l =
read(fd, evt_buffer.data(), BUFFER_SIZE);
179 throw std::runtime_error(std::string(
"Error waiting for inotify event ") +
std::to_string(l));
181 for (
int i = 0;
i < l;
i +=
sizeof(inotify_event)) {
182 inotify_event*
event = (inotify_event*)&evt_buffer[
i];
183 if (
event->len && (
event->mask & IN_CREATE) && !(
event->mask & IN_ISDIR)) {
184 check_add_file(
event->name);
189 auto curTime = std::chrono::system_clock::now();
190 if (std::chrono::duration_cast<std::chrono::milliseconds>(curTime - lastTime).
count() >= 1000) {
191 char*
ptr = text_buffer.data();
193 for (
auto fit = mFiles.begin();
fit != mFiles.end();
fit++) {
194 auto&
f =
fit->second;
201 std::getline(
file, line);
203 bool filterLine =
false;
204 for (
const auto&
filter : mFilters) {
205 if (std::regex_search(line,
filter)) {
214 auto severity{InfoLogger::InfoLogger::Severity::Error};
216 for (
const auto& logType : mMapLogTypes) {
217 if (
line.find(logType.first) != std::string::npos) {
218 severity = std::get<InfoLogger::InfoLogger::Severity>(logType.second);
219 level = std::get<int>(logType.second);
224 f.nBytes +=
line.size();
226 nBytes +=
line.size();
227 if (
f.nLines >= MAX_LINES_FILE ||
f.nBytes >= MAX_BYTES_FILE) {
228 sendLog(
f.name,
"Exceeded log size for process " +
f.name +
" (" +
std::to_string(
f.nLines) +
" lines, " +
std::to_string(
f.nBytes) +
" bytes), not reporting any more errors from this file...");
232 if (nLines >= MAX_LINES_TOTAL || nBytes >= MAX_BYTES_TOTAL) {
237 }
while (!
file.eof());
241 if (nLines >= MAX_LINES_TOTAL || nBytes >= MAX_BYTES_TOTAL) {
242 sendLog(
"",
"Max total stderr log size exceeded (" +
std::to_string(nLines) +
" lines, " +
std::to_string(nBytes) +
"), not sending any more stderr logs from this node...");
249 inotify_rm_watch(fd, wd);
252 printf(
"EPN stderr Monitor terminating\n");
255static std::unique_ptr<EPNMonitor> gEPNMonitor;
262 std::string
path = getenv(
"DDS_LOCATION") ? (std::string(getenv(
"DDS_LOCATION")) +
"/") : std::string(
".");
263 bool infoLogger = fConfig->GetProperty<
int>(
"infologger");
266 std::string partition =
"";
268 partition = fConfig->GetProperty<std::string>(
"environment_id",
"");
269 printf(
"Got environment_id: %s\n", partition.c_str());
271 printf(
"Error getting environment_id\n");
274 gEPNMonitor = std::make_unique<EPNMonitor>(
path, infoLogger, 0, partition);
280 runNumber = atoi(fConfig->GetProperty<std::string>(
"runNumber",
"").c_str());
281 printf(
"Got runNumber: %d\n", runNumber);
283 printf(
"Error getting runNumber\n");
285 gEPNMonitor->setRunNr(runNumber);
296 options.add_options()(
"infologger", bpo::value<int>()->default_value(0),
"Send via infologger");
299std::unique_ptr<fair::mq::Device>
getDevice(fair::mq::ProgOptions& config)
301 return std::make_unique<EPNstderrMonitor>();
void addCustomOptions(bpo::options_description &options)
o2::devices::O2SimDevice * getDevice()
EPNMonitor(std::string path, bool infoLogger, int runNumber, std::string partition)
GLuint const GLchar * name
GLint GLint GLint GLint GLint GLint GLint GLbitfield GLenum filter
GLsizei const GLchar *const * path
GLuint GLsizei const GLchar * message
DeliveryType read(const std::string &str)
int32_t const char int32_t line
TFitResultPtr fit(const size_t nBins, const T *arr, const T xMin, const T xMax, TF1 &func, std::string_view option="")
Polygon< T > close(Polygon< T > polygon)
Defining DataPointCompositeObject explicitly as copiable.
std::string to_string(gsl::span< T, Size > span)
bool ConditionalRun() override
fileMon(const std::string &path, const std::string &filename)