LDMX Software
Logger.cxx
1#include "Framework/Logger.h"
2
3// STL
4#include <fstream>
5#include <iostream>
6#include <ostream>
7
8// Boost
9#include <boost/core/null_deleter.hpp> //to avoid deleting std::cout
10#include <boost/log/utility/setup/common_attributes.hpp> //for loading commont attributes
11
12namespace framework {
13
14namespace logging {
15
25level convertLevel(int iLvl) {
26 if (iLvl < -1)
27 iLvl = -1;
28 else if (iLvl > 4)
29 iLvl = 4;
30 return level(iLvl);
31}
32
33logger makeLogger(const std::string& name) {
34 logger lg(log::keywords::channel = name); // already has severity built in
35 return boost::move(lg);
36}
37
38template <typename T>
39const T& safe_extract(log::attribute_value attr) {
40 static const T empty_value = {};
41 auto attr_val = log::extract<T>(attr);
42 if (attr_val) {
43 return *attr_val;
44 }
45 return empty_value;
46}
47
56class Filter {
57 level fallback_level_;
58 std::unordered_map<std::string, level> custom_levels_;
59
60 public:
61 Filter(level fallback, std::unordered_map<std::string, level> custom)
62 : fallback_level_{fallback}, custom_levels_{custom} {}
63 Filter(level fallback) : Filter(fallback, {}) {}
64 bool operator()(log::attribute_value_set const& attrs) {
65 auto it = custom_levels_.find(safe_extract<std::string>(attrs["Channel"]));
66 if (it != custom_levels_.end()) {
67 return safe_extract<level>(attrs["Severity"]) >= it->second;
68 }
69 return safe_extract<level>(attrs["Severity"]) >= fallback_level_;
70 }
71};
72
73void open(const framework::config::Parameters& p) {
74 // some helpful types
75 typedef sinks::text_ostream_backend ourSinkBack_t;
76 typedef sinks::synchronous_sink<ourSinkBack_t> ourSinkFront_t;
77
78 level fileLevel{convertLevel(p.getParameter<int>("fileLevel", 0))};
79 std::string filePath{p.getParameter<std::string>("filePath", "")};
80
81 level termLevel{convertLevel(p.getParameter<int>("termLevel", 4))};
82 std::vector<framework::config::Parameters> empty{};
83 const auto& logRules{
84 p.get<std::vector<framework::config::Parameters>>("logRules", empty)};
85 std::unordered_map<std::string, level> custom_levels;
86 for (const auto& logRule : logRules) {
87 custom_levels[logRule.getParameter<std::string>("name")] =
88 convertLevel(logRule.getParameter<int>("level"));
89 }
90
91 // allow our logs to access common attributes, the ones availabe are
92 // "LineID" : counter increments for each record being made (terminal or
93 // file) "TimeStamp" : time the log message was created "ProcessID" : machine
94 // ID for the process that is running "ThreadID" : machine ID for the thread
95 // the message is in
96 log::add_common_attributes();
97
98 // get the core logging service
99 boost::shared_ptr<log::core> core = log::core::get();
100
101 // file sink is optional
102 // don't even make it if no filePath is provided
103 if (not filePath.empty()) {
104 boost::shared_ptr<ourSinkBack_t> fileBack =
105 boost::make_shared<ourSinkBack_t>();
106 fileBack->add_stream(boost::make_shared<std::ofstream>(filePath));
107
108 boost::shared_ptr<ourSinkFront_t> fileSink =
109 boost::make_shared<ourSinkFront_t>(fileBack);
110
111 // this is where the logging level is set
112 fileSink->set_filter(Filter(fileLevel, custom_levels));
113 fileSink->set_formatter(
114 [](const log::record_view& view, log::formatting_ostream& os) {
115 Formatter::get()(view, os);
116 });
117 core->add_sink(fileSink);
118 } // file set to pass something
119
120 // terminal sink is always created
121 boost::shared_ptr<ourSinkBack_t> termBack =
122 boost::make_shared<ourSinkBack_t>();
123 termBack->add_stream(boost::shared_ptr<std::ostream>(
124 &std::cout, // point this stream to std::cout
125 boost::null_deleter() // don't let boost delete std::cout
126 ));
127 // flushes message to screen **after each message**
128 termBack->auto_flush(true);
129
130 boost::shared_ptr<ourSinkFront_t> termSink =
131 boost::make_shared<ourSinkFront_t>(termBack);
132
133 // translate integer level to enum
134 termSink->set_filter(Filter(termLevel, custom_levels));
135 // need to wrap formatter in lambda to enforce singleton formatter
136 termSink->set_formatter(
137 [](const log::record_view& view, log::formatting_ostream& os) {
138 Formatter::get()(view, os);
139 });
140 core->add_sink(termSink);
141
142 return;
143
144} // open
145
146void close() {
147 // prevents crashes on some systems when logging to a file
148 log::core::get()->remove_all_sinks();
149
150 return;
151}
152
154 static Formatter the_formatter;
155 return the_formatter;
156}
157
158void Formatter::set(int n) { Formatter::get().event_number_ = n; }
159
160void Formatter::operator()(const log::record_view& view,
161 log::formatting_ostream& os) {
162 os << "[ " << log::extract<std::string>("Channel", view) << " ] "
163 << event_number_ << " ";
168 const level msg_level{safe_extract<level>(view["Severity"])};
169 switch (msg_level) {
170 case level::trace:
171 os << "trace";
172 break;
173 case level::debug:
174 os << "debug";
175 break;
176 case level::info:
177 os << " info";
178 break;
179 case level::warn:
180 os << " warn";
181 break;
182 case level::error:
183 os << "error";
184 break;
185 case level::fatal:
186 os << "fatal";
187 break;
188 default:
189 // this should never happen since the loggers created
190 // with makeLogger use the level enum and thus check
191 // at compile time that the given level is an good option.
192 // That being said, we leave this in case someone creates
193 // their own logger circumventing makeLogger for whatever
194 // reason and changes the enum defining the severity.
195 os << "?????";
196 break;
197 }
198 os << ": " << view[log::expressions::smessage];
199}
200
201} // namespace logging
202
203} // namespace framework
Class encapsulating parameters for configuring a processor.
Definition Parameters.h:29
const T & get(const std::string &name) const
Retrieve the parameter of the given name.
Definition Parameters.h:78
Our filter implementation aligning with Boost.Log.
Definition Logger.cxx:56
Our logging formatter.
Definition Logger.h:94
void operator()(const log::record_view &view, log::formatting_ostream &os)
format the passed record view into the output stream
Definition Logger.cxx:160
static Formatter & get()
get reference to the current single Formatter
Definition Logger.cxx:153
static void set(int n)
set the event number in the current Formatter
Definition Logger.cxx:158
All classes in the ldmx-sw project use this namespace.
Definition PerfDict.cxx:45