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