ChimeraTK-ApplicationCore 04.08.00
Loading...
Searching...
No Matches
Logger.cc
Go to the documentation of this file.
1// SPDX-FileCopyrightText: Deutsches Elektronen-Synchrotron DESY, MSK, ChimeraTK Project <chimeratk-support@desy.de>
2// SPDX-License-Identifier: LGPL-3.0-or-later
3#include "Logger.h"
4
5#include <cstdlib>
6#include <format>
7#include <iostream>
8
9namespace ChimeraTK {
10
11 /********************************************************************************************************************/
12
13 Logger::Severity Logger::defaultSeverityFromEnv() {
14 const auto* envValue = std::getenv("CHIMERATK_LOG_LEVEL");
15 if(envValue == nullptr) {
16 return Severity::info;
17 }
18
19 auto severity = Severity::fromString(envValue);
20
21 if(!severity.has_value()) {
22 std::cerr << std::format("Warning: CHIMERATK_LOG_LEVEL has invalid value '{}'. {}. Falling back to default.",
23 envValue, severity.error())
24 << std::endl;
25 }
26
27 return severity.value_or(Severity::info);
28 }
29
30 /********************************************************************************************************************/
31
33 if(_mainLoopThread.joinable()) {
34 retry:
35 try {
36 _mainLoopThread.interrupt();
37
38 // try joining the thread
39 do {
40 // it may not suffice to send interrupt() once, as the exception might get
41 // overwritten in the queue, thus we repeat this until the thread was
42 // joined.
43 _messageQueue.push_exception(std::make_exception_ptr(boost::thread_interrupted()));
44 } while(!_mainLoopThread.try_join_for(boost::chrono::milliseconds(10)));
45 }
46 catch(boost::thread_interrupted&) {
47 // ignore interruptions at this point
48 goto retry;
49 }
50 catch(std::system_error& e) {
51 std::cerr << "std::system_error caught: " << e.what() << std::endl;
52 std::terminate();
53 }
54 catch(...) {
55 std::cerr << "unknown exception caught." << std::endl;
56 std::terminate();
57 }
58 }
59 assert(!_mainLoopThread.joinable());
60 }
61
62 /********************************************************************************************************************/
63
65 return {this, severity, std::move(context)};
66 }
67
68 /********************************************************************************************************************/
69
70 Logger::StreamProxy::StreamProxy(Logger* logger, Severity severity, std::string context)
71 : std::ostream(severity >= logger->_minSeverity ? &_buf : nullptr), _severity(severity), _context(std::move(context)),
72 _logger(*logger) {}
73
74 /********************************************************************************************************************/
75
77 // Send out the log message
78 _logger.log(_severity, std::move(_context), _buf.str());
79 }
80
81 /********************************************************************************************************************/
82
83 void Logger::log(Logger::Severity severity, std::string context, std::string message) noexcept {
84 try {
85 _messageQueue.push({severity, std::move(context), std::move(message)});
86 }
87 catch(std::system_error& e) {
88 std::cerr << "std::system_error caught: " << e.what() << std::endl;
89 std::terminate();
90 }
91 }
92
93 /********************************************************************************************************************/
94
95 std::string Logger::severityToString(Severity severity) {
96 switch(severity) {
98 return "t";
100 return "d";
102 return "i";
104 return "W";
106 return "E";
107 }
108 return "?";
109 }
110
111 /********************************************************************************************************************/
112
113 void Logger::mainLoop() {
114 while(true) {
115 LogMessage message;
116 _messageQueue.pop_wait(message);
117
118 auto* stream = &std::cout;
119 if(message.severity >= Severity::warning) {
120 stream = &std::cerr;
121 }
122
123 // Prefix with time stamp, source and severity. This format matches the DOOCS format (except that we added the
124 // severity).
125 auto t = std::time(nullptr);
126 auto tm = *std::localtime(&t);
127 std::stringstream prefix;
128 prefix.setf(std::ios::left, std::ios::adjustfield);
129 prefix << std::put_time(&tm, "%Y-%m-%dT%H:%M:%S") << " " << std::setw(20) << message.context.substr(0, 20) << " ["
130 << severityToString(message.severity) << "] ";
131
132 // print text line by line with prefix to stream
133 std::stringstream ss(message.text);
134 std::string line;
135 while(std::getline(ss, line, '\n')) {
136 *stream << prefix.str() << line << "\n";
137 }
138 *stream << std::flush;
139 }
140 }
141
142 /********************************************************************************************************************/
143
144} // namespace ChimeraTK
Severity levels used by the Logger.
Definition Logger.h:29
static constexpr std::expected< Logger::Severity, std::string > fromString(const std::string &string)
Set Severity from string.
Definition Logger.h:194
Proxy for output stream, handed out to the log sources by the Logger::Module.
Definition Logger.h:65
StreamProxy(Logger *logger, Severity severity, std::string context)
Definition Logger.cc:70
StreamProxy getStream(Severity severity, std::string context)
Return an output stream object for the given severity.
Definition Logger.cc:64
InvalidityTracer application module.
Logger::StreamProxy logger(Logger::Severity severity, std::string context)
Convenience function to obtain the logger stream.
Definition Logger.h:156