preCICE v3.1.1
Loading...
Searching...
No Matches
LogConfiguration.cpp
Go to the documentation of this file.
2#include <algorithm>
3#include <boost/core/null_deleter.hpp>
4#include <boost/log/attributes/mutable_constant.hpp>
5#include <boost/log/core.hpp>
6#include <boost/log/expressions.hpp>
7#include <boost/log/sinks/sink.hpp>
8#include <boost/log/support/date_time.hpp>
9#include <boost/log/trivial.hpp>
10#include <boost/log/utility/setup/console.hpp>
11#include <boost/program_options.hpp>
12#include <deque>
13#include <filesystem>
14#include <fstream>
15#include <iostream>
16#include <iterator>
17#include <map>
18#include <sstream>
19#include <string>
20#include <utility>
21#include "utils/String.hpp"
22#include "utils/assertion.hpp"
23
25
27class timestamp_formatter_factory : public boost::log::basic_formatter_factory<char, boost::posix_time::ptime> {
28public:
29 formatter_type create_formatter(boost::log::attribute_name const &name, args_map const &args) override
30 {
31 namespace expr = boost::log::expressions;
32 args_map::const_iterator it = args.find("format");
33 if (it != args.end())
34 return expr::stream << expr::format_date_time<boost::posix_time::ptime>(expr::attr<boost::posix_time::ptime>(name), it->second);
35 else
36 return expr::stream << expr::attr<boost::posix_time::ptime>(name);
37 }
38};
39
41class colorized_severity_formatter_factory : public boost::log::formatter_factory<char> {
42public:
43 formatter_type create_formatter(boost::log::attribute_name const &name, args_map const &args) override
44 {
45 namespace expr = boost::log::expressions;
46 auto severity = expr::attr<boost::log::trivial::severity_level>("Severity");
47
48 return expr::stream
49 << expr::if_(severity == boost::log::trivial::severity_level::error)
50 [expr::stream << "\033[31m" //red
51 << "ERROR: "]
52 << expr::if_(severity == boost::log::trivial::severity_level::warning)
53 [expr::stream << "\033[36m" //cyan
54 << "WARNING: "]
55 << "\033[0m";
56 }
57};
58
60class severity_formatter_factory : public boost::log::formatter_factory<char> {
61public:
62 formatter_type create_formatter(boost::log::attribute_name const &name, args_map const &args) override
63 {
64 namespace expr = boost::log::expressions;
65 auto severity = expr::attr<boost::log::trivial::severity_level>("Severity");
66
67 return expr::stream
68 << expr::if_(severity == boost::log::trivial::severity_level::error)
69 [expr::stream
70 << "ERROR: "]
71 << expr::if_(severity == boost::log::trivial::severity_level::warning)
72 [expr::stream
73 << "WARNING: "];
74 }
75};
76
78class NullSink final : public boost::log::sinks::sink {
79public:
81 : boost::log::sinks::sink(false) {}
82
83 bool will_consume(boost::log::attribute_value_set const &) override
84 {
85 return false;
86 }
87
88 void consume(boost::log::record_view const &) override {}
89
90 bool try_consume(boost::log::record_view const &) override
91 {
92 return false;
93 }
94
95 void flush() override {}
96
97 bool is_cross_thread() const noexcept
98 {
99 return false;
100 }
101};
102
104
109class StreamBackend final : public boost::log::sinks::text_ostream_backend {
110private:
111 boost::shared_ptr<std::ostream> _ostream;
112
113public:
114 explicit StreamBackend(boost::shared_ptr<std::ostream> ostream)
115 : _ostream(std::move(ostream)) {}
116
117 void consume(boost::log::record_view const &rec, string_type const &formatted_record)
118 {
119 *_ostream << formatted_record << '\n'
120 << std::flush;
121 }
122};
123
126{
127 if (!std::filesystem::exists(filename)) {
128 return {};
129 }
130
131 namespace po = boost::program_options;
132 po::options_description desc;
133 std::ifstream ifs(filename);
134
136 try {
137 po::parsed_options parsed = parse_config_file(ifs, desc, true);
138 for (auto const &opt : parsed.options) {
139 std::string section = opt.string_key.substr(0, opt.string_key.find('.'));
140 std::string key = opt.string_key.substr(opt.string_key.find('.') + 1);
142 PRECICE_ASSERT(!opt.value.empty());
143 configs[section].setOption(key, opt.value[0]);
144 } else {
145 std::cerr << "WARNING: section [" << section << "] in configuration file \"" << filename << "\" contains invalid key \"" << key << "\"\n";
146 }
147 }
148 } catch (po::error &e) {
149 std::cout << "ERROR reading logging configuration: " << e.what() << "\n\n";
150 std::exit(-1);
151 }
152
154
155 for (auto const &c : configs)
156 if (c.second.enabled)
157 retVal.push_back(c.second);
158
159 return retVal;
160}
161
162// Default values for filter and format. They are also used from config/LogConfiguration.cpp
163const std::string BackendConfiguration::default_filter = "(%Severity% > debug) and not ((%Severity% = info) and (%Rank% != 0))";
164const std::string BackendConfiguration::default_formatter = "(%Rank%) %TimeStamp(format=\"%H:%M:%S\")% [%Module%]:%Line% in %Function%: %ColorizedSeverity%%Message%";
167
169{
170 boost::algorithm::to_lower(key);
171 if (key == "type") {
172 boost::algorithm::to_lower(value);
173 type = value;
174 }
175 if (key == "output")
176 output = value;
177 if (key == "filter")
178 filter = value;
179 if (key == "format")
180 format = value;
181}
182
184{
185 boost::algorithm::to_lower(key);
186 return key == "output" || key == "filter" || key == "format" || key == "type";
187}
188
190{
191 this->enabled = enabled;
192}
193
194void setupLogging(LoggingConfiguration configs, bool enabled)
195{
196 if (getGlobalLoggingConfig().locked)
197 return;
198
199 namespace bl = boost::log;
200 bl::register_formatter_factory("TimeStamp", boost::make_shared<timestamp_formatter_factory>());
201 bl::register_formatter_factory("ColorizedSeverity", boost::make_shared<colorized_severity_formatter_factory>());
202 bl::register_formatter_factory("Severity", boost::make_shared<severity_formatter_factory>());
203 bl::register_simple_filter_factory<bl::trivial::severity_level, char>("Severity");
204
205 // Possible, longer output format. Currently unused.
206 auto fmtStream =
207 bl::expressions::stream
208 << "(" << bl::expressions::attr<int>("Rank") << ") "
209 << bl::expressions::format_date_time<boost::posix_time::ptime>("TimeStamp", "%H:%M:%S") << " "
210 << bl::expressions::attr<std::string>("File") << ":"
211 << bl::expressions::attr<int>("Line")
212 << " [" << bl::expressions::attr<std::string>("Module") << "] in "
213 << bl::expressions::attr<std::string>("Function") << ": "
214 << bl::expressions::message;
215
216 // Remove active preCICE sinks
217 using sink_ptr = typename boost::shared_ptr<boost::log::sinks::sink>;
218
219 static std::vector<sink_ptr> activeSinks;
220 for (auto &sink : activeSinks) {
221 boost::log::core::get()->remove_sink(sink);
222 sink->flush();
223 sink.reset();
224 }
225 activeSinks.clear();
226
227 // If logging sinks are disabled, then we need to disable the default sink.
228 // We do this by adding a NullSink.
229 // We need to exit after the sink removal as the default sink exists before
230 // the log configuration is parsed.
231 if (auto noconfigs = std::none_of(configs.begin(), configs.end(), [](const auto &config) { return config.enabled; });
232 !enabled && noconfigs) {
233 auto sink = boost::make_shared<NullSink>();
234 boost::log::core::get()->add_sink(sink);
235 activeSinks.emplace_back(std::move(sink));
236 return;
237 }
238
239 // Add the default config in case no sinks are configured
240 if (configs.empty()) {
241 configs.emplace_back();
242 }
243
244 // Create new sinks
245 for (const auto &config : configs) {
246 if (!config.enabled) {
247 continue;
248 }
249
250 // Setup backend of sink
251 boost::shared_ptr<StreamBackend> backend;
252 if (config.type == "file")
253 backend = boost::make_shared<StreamBackend>(boost::shared_ptr<std::ostream>(new std::ofstream(config.output)));
254 if (config.type == "stream") {
255 if (config.output == "stdout")
256 backend = boost::make_shared<StreamBackend>(boost::shared_ptr<std::ostream>(&std::cout, boost::null_deleter()));
257 if (config.output == "stderr")
258 backend = boost::make_shared<StreamBackend>(boost::shared_ptr<std::ostream>(&std::cerr, boost::null_deleter()));
259 }
260 PRECICE_ASSERT(backend != nullptr, "The logging backend was not initialized properly. Check your log config.");
261 backend->auto_flush(true);
262
263 // Setup sink
264 auto sink = boost::make_shared<boost::log::sinks::synchronous_sink<StreamBackend>>(backend);
265 sink->set_formatter(boost::log::parse_formatter(config.format));
266
267 if (config.filter.empty()) {
268 sink->set_filter(boost::log::expressions::attr<bool>("preCICE") == true);
269 } else {
270 // We extend the filter here to filter all log entries not originating from preCICE.
271 sink->set_filter(boost::log::parse_filter("%preCICE% & ( " + config.filter + " )"));
272 }
273
274 boost::log::core::get()->add_sink(sink);
275 activeSinks.emplace_back(std::move(sink));
276 }
277}
278
279void setupLogging(std::string const &logConfigFile)
280{
281 setupLogging(readLogConfFile(logConfigFile));
282}
283
284void setMPIRank(int const rank)
285{
287}
288
289void setParticipant(std::string const &participant)
290{
291 getGlobalLoggingConfig().participant = participant;
292}
293
295{
296 static GlobalLoggingConfig instance;
297 return instance;
298}
299
301{
303}
304
305} // namespace precice::logging
std::string name
T none_of(T... args)
#define PRECICE_ASSERT(...)
Definition assertion.hpp:87
T begin(T... args)
A custom sink that does nothing. It is used to disable the default sink of boost.Log.
void consume(boost::log::record_view const &) override
bool is_cross_thread() const noexcept
bool will_consume(boost::log::attribute_value_set const &) override
bool try_consume(boost::log::record_view const &) override
A simple backends that outputs the message to a stream.
boost::shared_ptr< std::ostream > _ostream
StreamBackend(boost::shared_ptr< std::ostream > ostream)
void consume(boost::log::record_view const &rec, string_type const &formatted_record)
A custom formatter that handles the colorized Severity formatting.
formatter_type create_formatter(boost::log::attribute_name const &name, args_map const &args) override
A custom formatter that handles non-colorized Severity formatting.
formatter_type create_formatter(boost::log::attribute_name const &name, args_map const &args) override
A custom formatter that handles the TimeStamp format string.
formatter_type create_formatter(boost::log::attribute_name const &name, args_map const &args) override
T clear(T... args)
T emplace_back(T... args)
T empty(T... args)
T end(T... args)
T exists(T... args)
T exit(T... args)
T flush(T... args)
contains the logging framework.
void setupLogging(LoggingConfiguration configs, bool enabled)
Configures the logging from a LoggingConfiguration.
void setMPIRank(int const rank)
void setParticipant(std::string const &participant)
LoggingConfiguration readLogConfFile(std::string const &filename)
Reads a log file, returns a logging configuration.
GlobalLoggingConfig & getGlobalLoggingConfig()
Returns the global logging configuration.
STL namespace.
T push_back(T... args)
void setEnabled(bool enabled)
Sets weather the sink is enabled or disabled.
void setOption(std::string key, std::string value)
Sets on option, overwrites default values.
static bool isValidOption(std::string key)
Checks if an option is usable.
Holds global logging data in a central place.
T substr(T... args)