Belle II Software development
LogListener.cc
1/**************************************************************************
2 * basf2 (Belle II Analysis Software Framework) *
3 * Author: The Belle II Collaboration *
4 * *
5 * See git log for contributors and copyright holders. *
6 * This file is licensed under LGPL-3.0, see LICENSE.md. *
7 **************************************************************************/
8#include "daq/slc/readout/LogListener.h"
9
10#include "daq/slc/readout/ProcessController.h"
11
12#include <daq/slc/runcontrol/RCCallback.h>
13#include <daq/slc/runcontrol/RCCommand.h>
14#include <daq/slc/nsm/NSMCommunicator.h>
15
16#include <daq/slc/system/File.h>
17#include <daq/slc/system/FileReader.h>
18
19#include <daq/slc/base/IOException.h>
20#include <daq/slc/base/StringUtil.h>
21#include <daq/slc/system/LogFile.h>
22
23#include <iostream>
24#include <sstream>
25#include <ctype.h>
26
27namespace Belle2 {
34
36}
37
38using namespace Belle2;
39
40void LogListener::run()
41{
42 File fd(m_pipe[0]);
43 PipeReader preader(fd);
44 std::stringstream ss;
45 std::string s;
46 LogFile::Priority priority = LogFile::UNKNOWN;
47 int count = 0;
48 try {
49 while (true) {
50 int c = preader.readChar(); //read next character from pipe
51
52 if (c != '\n' && iscntrl(c)) continue; //character is unprintable, skip
53
54 if (c == '\n' && count > 0) { //newline received line was not empty -> message is assembled, submit
55 std::string assembledLogMessage(ss.str());
56
57 // basf2 has a flag to escape newlines with "\\n" to write multi-line log messages into a single line
58 // see: https://gitlab.desy.de/belle2/software/basf2/-/issues/6353
59 // if m_enableUnescapeNewlines is set, these "\\n" will be replaced with "\n" newlines again before the log message is sent out
60
61 if (m_enableUnescapeNewlines) {
62 assembledLogMessage = StringUtil::replace(assembledLogMessage, "\\n", "\n");
63 }
64
65 s = m_con->getParName() + " : " + assembledLogMessage;
66 ss.str("");
67 //m_con->lock();
68 if (priority == LogFile::UNKNOWN) {
69 priority = LogFile::DEBUG;
70 }
71
72 if (priority > LogFile::DEBUG) {
73 m_con->getCallback()->log(priority, s);
74 } else {
75 LogFile::debug(s);
76 }
77
78 if (m_con->getCallback()->getNode().getState() == RCState::RUNNING_S) {
79 if (priority == LogFile::ERROR) {
80 // m_con->getCallback()->log(LogFile::ERROR, s);
81 } else if (priority == LogFile::FATAL) {
82 // m_con->getCallback()->log(LogFile::FATAL, s));
83 m_con->getCallback()->setState(RCState::ERROR_ES);
84 }
85 }
86 //m_con->unlock();
87 count = 0;
88 priority = LogFile::UNKNOWN;
89 } else if (isprint(c)) { //continue to assemble message
90 if (count == 0 && c == '[') { //start of a "[DEBUG]"-like priority identifier preceding each log line
91 ss << c;
92 while (true) {
93 c = preader.readChar();
94 if (c == ']') { //end of a "[DEBUG]"-like priority identifier
95 ss << c;
96 s = ss.str();
97 if (s == "[DEBUG]") priority = LogFile::DEBUG;
98 else if (s == "[INFO]") priority = LogFile::INFO;
99 else if (s == "[NOTICE]") priority = LogFile::NOTICE;
100 else if (s == "[WARNING]") priority = LogFile::WARNING;
101 else if (s == "[ERROR]") priority = LogFile::ERROR;
102 else if (s == "[FATAL]") priority = LogFile::FATAL;
103 else if (s.find("STOP") != std::string::npos) {
104 StringList sl = StringUtil::split(s, '=');
105 if (sl.size() > 1) {
106 std::string nodename = StringUtil::replace(sl[1], "]", "");
107 try {
108 NSMCommunicator::send(NSMMessage(NSMNode(nodename), RCCommand::STOP));
109 } catch (const std::exception& e) {
110 }
111 }
112 count = 0;
113 ss.str("");
114 break;
115 }
116 if (priority > 0) {
117 count = 0;
118 ss.str("");
119 } else {
120 priority = LogFile::DEBUG;
121 }
122 break;
123 }
124 ss << c;
125 }
126 } else {
127 if (c != ' ' || count > 0) {
128 ss << c;
129 count++;
130 }
131 }
132 }
133 }
134 } catch (const IOException& e) {
135 LogFile::debug(e.what());
136 if (count > 0) {
137 s = m_con->getParName() + " : " + ss.str();
138 ss.str("");
139 //m_con->lock();
140 if (priority == LogFile::UNKNOWN) {
141 priority = LogFile::DEBUG;
142 }
143 m_con->getCallback()->log(priority, s);
144 if (m_con->getCallback()->getNode().getState() == RCState::RUNNING_S) {
145 if (priority == LogFile::ERROR) {
146 //m_con->getCallback()->reply(NSMMessage(NSMCommand::ERROR, s));
147 } else if (priority == LogFile::FATAL) {
148 //m_con->getCallback()->reply(NSMMessage(NSMCommand::ERROR, s));
149 m_con->getCallback()->setState(RCState::ERROR_ES);
150 }
151 }
152 //m_con->unlock();
153 }
154 }
155 close(m_pipe[0]);
156}
Abstract base class for different kinds of events.