Belle II Software development
LogConnectionConsole.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
9#include <framework/logging/LogConnectionConsole.h>
10#include <framework/logging/LogMessage.h>
11#include <Python.h>
12#include <boost/python.hpp>
13#include <boost/algorithm/string.hpp>
14#include <sstream>
15#include <cstring> // strerror()
16#include <unistd.h> // isatty(), dup()
17#include <cstdlib> // getenv()
18
19using namespace Belle2;
20
23
25 m_fd(dup(outputFD)), m_color(color)
26{
27 // check fd
28 if (m_fd < 0) throw std::runtime_error(std::string("Error duplicating file descriptor: ") + std::strerror(errno));
29}
30
35
37{
38 return (s_pythonLoggingEnabled and Py_IsInitialized()) || m_fd >= 0;
39}
40
42{
43 //enable color for TTYs with color support (list taken from gtest)
44 const bool isTTY = isatty(fileDescriptor);
45 const char* term = getenv("TERM");
46 const std::string termName = term ? term : "";
47 const bool useColor = isTTY and
48 (termName == "xterm" or termName == "xterm-color" or termName == "xterm-256color" or
49 termName == "screen" or termName == "screen-256color" or termName == "tmux" or
50 termName == "tmux-256color" or termName == "rxvt-unicode" or
51 termName == "rxvt-unicode-256color" or termName == "linux" or termName == "cygwin");
52 return useColor;
53}
54
55void LogConnectionConsole::write(const std::string& message)
56{
57 if (s_pythonLoggingEnabled and Py_IsInitialized()) {
58 auto pymessage = boost::python::import("sys").attr("stdout");
59 pymessage.attr("write")(message);
60 pymessage.attr("flush")();
61 } else {
62 ::write(m_fd, message.data(), message.size());
63 }
64}
65
67{
68 if (!isConnected()) return false;
69 // format message
70 std::stringstream stream;
71 if (m_color) {
72 const std::string color_str[] = {
73 "\x1b[32m", // Debug : green
74 "", // Info : terminal default
75 "\x1b[34m", // Result : blue
76 "\x1b[33m", // Warning: yellow
77 "\x1b[31m", // Error : red
78 "\x1b[07m\x1b[31m" // Fatal : red reversed
79 };
80 const std::string& c{color_str[message.getLogLevel()]};
81 stream << c;
82 }
83 stream << message;
84 std::string messagestr = stream.str();
86 // remove trailing whitespace
87 boost::trim_right_if(messagestr, boost::is_any_of(" \t\n\r"));
88 // escape all remaining newlines
89 boost::replace_all(messagestr, "\n", "\\n");
90 // and make sure we end in an actual newline
91 messagestr += "\n";
92 }
93 if (m_color) {
94 messagestr += "\x1b[m";
95 }
96 write(messagestr);
97 return true;
98}
99
101{
102 // If python logging is enabled we need to give jupyter some time to flush
103 // the output as this happens only in the output thread. Seems flushing again is fine :D
105 boost::python::import("sys").attr("stdout").attr("flush")();
106 }
107}
bool m_color
Flag for color output.
static bool getPythonLoggingEnabled()
Check whether console logging via python is enabled.
static bool s_escapeNewlinesEnabled
Flag to indicate whether newlines should be replaced by ' ' in the output.
~LogConnectionConsole() override
Destructor.
LogConnectionConsole(int outputFD, bool color)
Constructor.
static bool terminalSupportsColors(int fileDescriptor)
Returns true if the given file descriptor is a tty and supports colors.
static bool s_pythonLoggingEnabled
Flag to indicate whether log messages should be sent to python sys.stdout.
bool isConnected() override
Returns true if the connection to the io stream could be established.
bool sendMessage(const LogMessage &message) override
Sends a log message.
int m_fd
The output stream used for sending the log message.
void finalizeOnAbort() override
Make sure output is flushed on abort.
void write(const std::string &message)
Send a preformatted string message to the connected output.
The LogMessage class.
Definition LogMessage.h:29
Abstract base class for different kinds of events.