Project
Loading...
Searching...
No Matches
EPNstderrMonitor.cxx
Go to the documentation of this file.
1// Copyright 2019-2020 CERN and copyright holders of ALICE O2.
2// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders.
3// All rights not expressly granted are reserved.
4//
5// This software is distributed under the terms of the GNU General Public
6// License v3 (GPL Version 3), copied verbatim in the file "COPYING".
7//
8// In applying this license CERN does not waive the privileges and immunities
9// granted to it by virtue of its status as an Intergovernmental Organization
10// or submit itself to any jurisdiction.
11
14
15#include <fairmq/Device.h>
16#include <fairmq/runDevice.h>
17
18#include "InfoLogger/InfoLogger.hxx"
19
20#include <string>
21#include <thread>
22#include <vector>
23#include <unordered_map>
24#include <regex>
25#include <filesystem>
26#include <chrono>
27#include <fstream>
28
29#include <unistd.h>
30#include <sys/inotify.h>
31#include <poll.h>
32
33using namespace AliceO2;
34
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;
39
40struct fileMon {
41 std::ifstream file;
42 std::string name;
43 unsigned int nLines = 0;
44 unsigned int nBytes = 0;
45 bool stopped = false;
46
47 fileMon(const std::string& path, const std::string& filename);
48 fileMon(const std::string& filename, std::ifstream&& f);
49};
50
51fileMon::fileMon(const std::string& path, const std::string& filename) : name(filename)
52{
53 printf("Monitoring file %s\n", filename.c_str());
54 file.open(path + "/" + filename, std::ifstream::in);
55}
56
57fileMon::fileMon(const std::string& filename, std::ifstream&& f) : file(std::move(f)), name(filename)
58{
59}
60
62{
63 public:
64 EPNMonitor(std::string path, bool infoLogger, int runNumber, std::string partition);
66 void setRunNr(int nr) { mRunNumber = nr; }
67
68 private:
69 void thread();
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);
73
74 bool mInfoLoggerActive;
75 volatile bool mTerminate = false;
76 std::thread mThread;
77 std::unordered_map<std::string, fileMon> mFiles;
78 std::string mPath;
79 std::vector<std::regex> mFilters;
80 std::unordered_map<std::string, std::pair<InfoLogger::InfoLogger::Severity, int>> mMapRootLogTypes;
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;
87};
88
89EPNMonitor::EPNMonitor(std::string path, bool infoLogger, int runNumber, std::string partition)
90{
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 mMapRootLogTypes.emplace("Info in <", std::pair<InfoLogger::InfoLogger::Severity, int>{InfoLogger::InfoLogger::Severity::Info, 13});
99 mMapRootLogTypes.emplace("Print in <", std::pair<InfoLogger::InfoLogger::Severity, int>{InfoLogger::InfoLogger::Severity::Info, 13});
100 mMapRootLogTypes.emplace("Warning in <", std::pair<InfoLogger::InfoLogger::Severity, int>{InfoLogger::InfoLogger::Severity::Warning, 11});
101 mMapRootLogTypes.emplace("Error in <", std::pair<InfoLogger::InfoLogger::Severity, int>{InfoLogger::InfoLogger::Severity::Error, 2});
102 mMapRootLogTypes.emplace("Fatal in <", std::pair<InfoLogger::InfoLogger::Severity, int>{InfoLogger::InfoLogger::Severity::Fatal, 1});
103 mMapRootLogTypes.emplace("*** Break ***", std::pair<InfoLogger::InfoLogger::Severity, int>{InfoLogger::InfoLogger::Severity::Fatal, 1});
104 mInfoLoggerActive = infoLogger;
105 mPath = path;
106 mRunNumber = runNumber;
107 mPartition = partition;
108 if (infoLogger) {
109 mLogger = std::make_unique<InfoLogger::InfoLogger>();
110 mLoggerContext = std::make_unique<InfoLogger::InfoLoggerContext>();
111 mLoggerContext->setField(InfoLogger::InfoLoggerContext::FieldName::Partition, partition != "" ? partition : "unspecified");
112 mLoggerContext->setField(InfoLogger::InfoLoggerContext::FieldName::System, std::string("STDERR"));
113 }
114 mThread = std::thread(&EPNMonitor::thread, this);
115}
116
118{
119 mTerminate = true;
120 mThread.join();
121}
122
123void EPNMonitor::check_add_file(const std::string& filename)
124{
125 //printf("Checking '%s'\n", filename.c_str());
126 static const std::regex match_stderr("_err\\.log$");
127 if (std::regex_search(filename, match_stderr)) {
128 mFiles.try_emplace(filename, mPath, filename);
129 }
130}
131
132void EPNMonitor::sendLog(const std::string& file, const std::string& message, const InfoLogger::InfoLogger::Severity severity, int level)
133{
134 if (mInfoLoggerActive) {
135 mLoggerContext->setField(InfoLogger::InfoLoggerContext::FieldName::Facility, ("stderr/" + file).substr(0, 31));
136 mLoggerContext->setField(InfoLogger::InfoLoggerContext::FieldName::Run, mRunNumber != 0 ? std::to_string(mRunNumber) : "unspecified");
137 static const InfoLogger::InfoLogger::InfoLoggerMessageOption opt = {severity, level, InfoLogger::InfoLogger::undefinedMessageOption.errorCode, InfoLogger::InfoLogger::undefinedMessageOption.sourceFile, InfoLogger::InfoLogger::undefinedMessageOption.sourceLine};
138 mLogger->log(opt, *mLoggerContext, "stderr: %s", file == "SYSLOG" ? (std::string("[GLOBAL SYSLOG]: ") + message).c_str() : message.c_str());
139 } else {
140 printf("stderr: [%c] %s: %s\n", severity, file.c_str(), message.c_str());
141 }
142}
143
144void EPNMonitor::thread()
145{
146 printf("EPN stderr Monitor active\n");
147
148 try {
149 std::string syslogfile = "/var/log/infologger_syslog";
150 std::ifstream file;
151 file.open(syslogfile, std::ifstream::in);
152 file.seekg(0, file.end);
153 mFiles.emplace(std::piecewise_construct, std::forward_as_tuple(syslogfile), std::forward_as_tuple(std::string("SYSLOG"), std::move(file)));
154 } catch (...) {
155 }
156
157 int fd;
158 int wd;
159 static constexpr size_t BUFFER_SIZE = 64 * 1024;
160 std::vector<char> evt_buffer(BUFFER_SIZE);
161 std::vector<char> text_buffer(8192);
162 fd = inotify_init();
163 wd = inotify_add_watch(fd, mPath.c_str(), IN_CREATE);
164 if (fd < 0) {
165 throw std::runtime_error(std::string("Error initializing inotify ") + std::to_string(fd) + " " + std::to_string(wd));
166 }
167 pollfd pfd = {fd, POLLIN, 0};
168
169 for (const auto& entry : std::filesystem::directory_iterator(mPath)) {
170 if (entry.is_regular_file()) {
171 check_add_file(entry.path().filename());
172 }
173 }
174
175 auto lastTime = std::chrono::system_clock::now();
176 while (!mTerminate) {
177 if (poll(&pfd, 1, 50) > 0) {
178 int l = read(fd, evt_buffer.data(), BUFFER_SIZE);
179 if (l < 0) {
180 throw std::runtime_error(std::string("Error waiting for inotify event ") + std::to_string(l));
181 }
182 for (int i = 0; i < l; i += sizeof(inotify_event)) {
183 inotify_event* event = (inotify_event*)&evt_buffer[i];
184 if (event->len && (event->mask & IN_CREATE) && !(event->mask & IN_ISDIR)) {
185 check_add_file(event->name);
186 }
187 i += event->len;
188 }
189 }
190 auto curTime = std::chrono::system_clock::now();
191 if (std::chrono::duration_cast<std::chrono::milliseconds>(curTime - lastTime).count() >= 1000) {
192 char* ptr = text_buffer.data();
193 std::string line;
194 for (auto fit = mFiles.begin(); fit != mFiles.end(); fit++) {
195 auto& f = fit->second;
196 if (f.stopped) {
197 continue;
198 }
199 auto& file = f.file;
200 file.clear();
201 do {
202 std::getline(file, line);
203 if (line.size()) {
204 bool filterLine = false;
205 for (const auto& filter : mFilters) {
206 if (std::regex_search(line, filter)) {
207 filterLine = true;
208 break;
209 }
210 }
211 if (filterLine) {
212 continue;
213 }
214 // assign proper severity / level for remaining ROOT log messages
215 auto severity{InfoLogger::InfoLogger::Severity::Error};
216 int level{3};
217 for (const auto& logType : mMapRootLogTypes) {
218 if (line.find(logType.first) != std::string::npos) {
219 severity = std::get<InfoLogger::InfoLogger::Severity>(logType.second);
220 level = std::get<int>(logType.second);
221 break;
222 }
223 }
224 f.nLines++;
225 f.nBytes += line.size();
226 nLines++;
227 nBytes += line.size();
228 if (f.nLines >= MAX_LINES_FILE || f.nBytes >= MAX_BYTES_FILE) {
229 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...");
230 f.stopped = true;
231 break;
232 }
233 if (nLines >= MAX_LINES_TOTAL || nBytes >= MAX_BYTES_TOTAL) {
234 break;
235 }
236 sendLog(f.name, line, severity, level);
237 }
238 } while (!file.eof());
239 }
240 lastTime = curTime;
241 }
242 if (nLines >= MAX_LINES_TOTAL || nBytes >= MAX_BYTES_TOTAL) {
243 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...");
244 break;
245 }
246
247 usleep(50000);
248 }
249
250 inotify_rm_watch(fd, wd);
251 close(fd);
252
253 printf("EPN stderr Monitor terminating\n");
254}
255
256static std::unique_ptr<EPNMonitor> gEPNMonitor;
257
258namespace bpo = boost::program_options;
259
261 void InitTask() override
262 {
263 std::string path = getenv("DDS_LOCATION") ? (std::string(getenv("DDS_LOCATION")) + "/") : std::string(".");
264 bool infoLogger = fConfig->GetProperty<int>("infologger");
265 bool dds = false;
266
267 std::string partition = "";
268 try {
269 partition = fConfig->GetProperty<std::string>("environment_id", "");
270 printf("Got environment_id: %s\n", partition.c_str());
271 } catch (...) {
272 printf("Error getting environment_id\n");
273 }
274
275 gEPNMonitor = std::make_unique<EPNMonitor>(path, infoLogger, 0, partition);
276 }
277 void PreRun() override
278 {
279 int runNumber = 0;
280 try {
281 runNumber = atoi(fConfig->GetProperty<std::string>("runNumber", "").c_str());
282 printf("Got runNumber: %d\n", runNumber);
283 } catch (...) {
284 printf("Error getting runNumber\n");
285 }
286 gEPNMonitor->setRunNr(runNumber);
287 }
288 bool ConditionalRun() override
289 {
290 usleep(100000);
291 return true;
292 }
293};
294
295void addCustomOptions(bpo::options_description& options)
296{
297 options.add_options()("infologger", bpo::value<int>()->default_value(0), "Send via infologger");
298}
299
300std::unique_ptr<fair::mq::Device> getDevice(fair::mq::ProgOptions& config)
301{
302 return std::make_unique<EPNstderrMonitor>();
303}
void addCustomOptions(bpo::options_description &options)
int32_t i
o2::devices::O2SimDevice * getDevice()
TBranch * ptr
EPNMonitor(std::string path, bool infoLogger, int runNumber, std::string partition)
void setRunNr(int nr)
struct _cl_event * event
Definition glcorearb.h:2982
GLint GLsizei count
Definition glcorearb.h:399
GLuint entry
Definition glcorearb.h:5735
GLuint const GLchar * name
Definition glcorearb.h:781
GLdouble f
Definition glcorearb.h:310
GLint GLint GLint GLint GLint GLint GLint GLbitfield GLenum filter
Definition glcorearb.h:1308
GLsizei const GLchar *const * path
Definition glcorearb.h:3591
GLuint GLsizei const GLchar * message
Definition glcorearb.h:2517
GLint level
Definition glcorearb.h:275
GLenum GLenum severity
Definition glcorearb.h:2513
DeliveryType read(const std::string &str)
TFitResultPtr fit(const size_t nBins, const T *arr, const T xMin, const T xMax, TF1 &func, std::string_view option="")
Definition fit.h:59
Polygon< T > close(Polygon< T > polygon)
Definition Polygon.h:126
Defining DataPointCompositeObject explicitly as copiable.
std::string to_string(gsl::span< T, Size > span)
Definition common.h:52
std::string filename()
bool ConditionalRun() override
void InitTask() override
void PreRun() override
unsigned int nLines
std::ifstream file
std::string name
fileMon(const std::string &path, const std::string &filename)
unsigned int nBytes