DUNE-DAQ
DUNE Trigger and Data Acquisition software
Loading...
Searching...
No Matches
Logger.hxx
Go to the documentation of this file.
1
8#ifndef LOGGING_INCLUDE_LOGGING_DETAIL_LOGGER_HXX_
9#define LOGGING_INCLUDE_LOGGING_DETAIL_LOGGER_HXX_
10
11#include <stdlib.h> // setenv
12
13/* verstrace_user
14 Only log and debug "levels" (or "streams") are supported
15 */
16#if defined(__has_feature)
17#if __has_feature(thread_sanitizer)
18__attribute__((no_sanitize("thread")))
19#endif
20#endif
21static void
22verstrace_user(struct timeval* /*tvp*/,
23 int TID,
24 uint8_t lvl,
25 const char* insert,
26 const char* file,
27 int line,
28 const char* function,
29 uint16_t nargs,
30 const char* msg,
31 va_list ap)
32{
33
34 size_t printed = 0;
35 int retval;
36 const char* outp;
37 char obuf[TRACE_USER_MSGMAX];
38
39 if ((insert && (printed = strlen(insert))) || nargs) {
40 /* check insert 1st to make sure printed is set */
41 // assume insert is smaller than obuf
42 if (printed) {
43 retval = snprintf(obuf, sizeof(obuf), "%s ", insert);
44 printed = TRACE_SNPRINTED(retval, sizeof(obuf));
45 }
46 if (nargs) {
47 retval =
48 vsnprintf(&(obuf[printed]), sizeof(obuf) - printed, msg, ap); // man page say obuf will always be terminated
49 printed += TRACE_SNPRINTED(retval, sizeof(obuf) - printed);
50 } else {
51 /* don't do any parsing for format specifiers in the msg -- tshow will
52 also know to do this on the memory side of things */
53 retval = snprintf(&(obuf[printed]), sizeof(obuf) - printed, "%s", msg);
54 printed += TRACE_SNPRINTED(retval, sizeof(obuf) - printed);
55 }
56 if (obuf[printed - 1] == '\n')
57 obuf[printed - 1] = '\0'; // DONE w/ printed (don't need to decrement
58 outp = obuf;
59 } else {
60 if (msg[strlen(msg) - 1] == '\n') { // need to copy to remove the trailing nl
61 retval = snprintf(obuf, sizeof(obuf), "%s", msg);
62 printed = TRACE_SNPRINTED(retval, sizeof(obuf));
63 if (obuf[printed - 1] == '\n')
64 obuf[printed - 1] = '\0'; // DONE w/ printed (don't need to decrement
65 outp = obuf;
66 } else
67 outp = msg;
68 }
69 // LocalContext args: 1-"package_name" 2-"file" 3-"line" 4-"pretty_function" 5-"include_stack"
70 ers::LocalContext lc(reinterpret_cast<char*>(idx2namsPtr(TID)), file, line, function, DEBUG_FORCED);
71 // std::ostringstream ers_report_impl_out_buffer;
72 // ers_report_impl_out_buffer << outp;
73 if (lvl < TLVL_DEBUG) { // NOTE: at least currently, TLVL_LOG is numerically 1 less than TLVL_DEBUG
74 // auto d = std::chrono::seconds{tvp->tv_sec} + std::chrono::microseconds{tvp->tv_usec};
76 // std::chrono::system_clock::time_point tp{d};
77 // PROTECTED - ers::Issue iss( ers::Issue( ers::Severity(ers::Log), tp, lc, outp, std::vector<std::string>(),
78 // std::map<std::string,std::string>(), nullptr ));
79 ers::log(ers::InternalMessage(lc, outp));
80 } else {
81 ers::debug(ers::InternalMessage(lc, outp), lvl - TLVL_DEBUG);
82 }
83}
84
85SUPPRESS_NOT_USED_WARN
86static void
87erstrace_user(struct timeval* tvp,
88 int TID,
89 uint8_t lvl,
90 const char* insert,
91 const char* file,
92 int line,
93 const char* function,
94 uint16_t nargs,
95 const char* msg,
96 ...)
97{
98 va_list ap;
99 va_start(ap, msg);
100 verstrace_user(tvp, TID, lvl, insert, file, line, function, nargs, msg, ap);
101 va_end(ap);
102}
103
104#pragma GCC diagnostic push
105#pragma GCC diagnostic ignored "-Wvarargs"
106SUPPRESS_NOT_USED_WARN
107static void
108erstrace_user(struct timeval* tvp,
109 int TID,
110 uint8_t lvl,
111 const char* insert,
112 const char* file,
113 int line,
114 const char* function,
115 uint16_t nargs,
116 const std::string& msg,
117 ...)
118{
119 va_list ap;
120 va_start(ap, msg);
121 verstrace_user(tvp, TID, lvl, insert, file, line, function, nargs, &msg[0], ap);
122 va_end(ap);
123} /* trace */
124#pragma GCC diagnostic pop
125
126// The following allow an ers::Issue to be streamed into TLOG() or TLOG_DEBUG(N)
127inline void
128operator<<(TraceStreamer& x, const ers::Issue& r)
129{
130 if (x.do_m) {
131 x.line_ = r.context().line_number();
132 x.msg_append(r.message().c_str());
133 // MAY NEED TO APPEND CHAINED ISSUE???
134 // const ers::Issue *issp = &r;
135 // while ((issp=issp->cause())) {
136 // }
137 }
138 if (x.do_s) {
139 if (x.lvl_ == TLVL_INFO)
140 ers::info(r);
141 else if (x.lvl_ == TLVL_LOG)
142 ers::log(r);
143 else
144 ers::debug(r, x.lvl_ - TLVL_DEBUG);
145 x.do_s = 0;
146 }
147}
148
149inline void
150operator<<(TraceStreamer& x, const ers::InternalMessage& r)
151{
152 if (x.do_m) {
153 x.line_ = r.context().line_number();
154 x.msg_append(r.message().c_str());
155 // MAY NEED TO APPEND CHAINED ISSUE???
156 }
157 if (x.do_s) {
158 if (x.lvl_ == TLVL_INFO)
159 ers::info(r);
160 else if (x.lvl_ == TLVL_LOG)
161 ers::log(r);
162 else
163 ers::debug(r, x.lvl_ - TLVL_DEBUG);
164 x.do_s = 0;
165 }
166}
167
168namespace { // unnamed namespace (i.e. static (for each compliation unit only))
169
170class ErsFatalStreamer
171{
172public:
173 inline ErsFatalStreamer& operator<<(const ers::Issue& r)
174 {
175 ers::fatal(r);
176 return *this;
177 }
178}; // class ErsFatalStreamer
179
180class ErsErrorStreamer
181{
182public:
183 inline ErsErrorStreamer& operator<<(const ers::Issue& r)
184 {
185 ers::error(r);
186 return *this;
187 }
188}; // class ErsErrorStreamer
189
190class ErsWarningStreamer
191{
192public:
193 // ErsWarningStreamer( ers::LocalContext c ) : _ctx(c) {}
194 // ers::LocalContext _ctx;
195 inline ErsWarningStreamer& operator<<(const ers::Issue& r)
196 {
197 // would be nice of the "context" could be created from the streamer instance
198 ers::warning(r);
199 return *this;
200 }
201}; // class ErsWarningStreamer
202class ErsInfoStreamer
203{
204public:
205 // ErsInfoStreamer( ers::LocalContext c ) : _ctx(c) {}
206 // ers::LocalContext _ctx;
207 inline ErsInfoStreamer& operator<<(const ers::Issue& r)
208 {
209 // would be nice of the "context" could be created from the streamer instance
210 ers::warning(r);
211 return *this;
212 }
213}; // class ErsInfoStreamer
214class ErsLogStreamer
215{
216public:
217 // ErsLogStreamer( ers::LocalContext c ) : _ctx(c) {}
218 // ers::LocalContext _ctx;
219 inline ErsLogStreamer& operator<<(const ers::Issue& r)
220 {
221 // would be nice of the "context" could be created from the streamer instance
222 ers::warning(r);
223 return *this;
224 }
225}; // class ErsLogStreamer
226} // namespace ""
227
228// The following allows "erstrace" to be included in the ERS configuration via
229// DUNEDAQ_ERS_{FATAL,ERROR,WARNING} environment variables.
230#include <ers/OutputStream.hpp>
231namespace ers {
233{
234 void write(const ers::Issue& issue)
235 {
236 ers::Severity sev = issue.severity();
237 uint8_t lvl_ = TLVL_DEBUG;
238 switch (sev.type) {
239 case ers::Debug:
240 lvl_ = TLVL_DEBUG + sev.rank;
241 break;
242 case ers::Log:
243 lvl_ = TLVL_LOG;
244 break;
245 case ers::Information:
246 lvl_ = TLVL_INFO;
247 break;
248 case ers::Warning:
249 lvl_ = TLVL_WARNING;
250 break;
251 case ers::Error:
252 lvl_ = TLVL_ERROR;
253 break;
254 case ers::Fatal:
255 lvl_ = TLVL_FATAL;
256 break;
257 }
258 struct
259 {
260 char tn[TRACE_TN_BUFSZ];
261 } _trc_;
262 if (TRACE_INIT_CHECK(trace_name(TRACE_NAME, issue.context().file_name(), _trc_.tn, sizeof(_trc_.tn)))) {
263 if (traceControl_rwp->mode.bits.M && (traceLvls_p[traceTID].M & TLVLMSK(lvl_))) {
264 struct timeval lclTime;
265 std::chrono::system_clock::time_point tp{ issue.ptime() };
266 // auto micros = std::chrono::duration_cast<std::chrono::microseconds>(tp.time_since_epoch());
267 std::chrono::microseconds micros = std::chrono::duration_cast<std::chrono::microseconds>(tp.time_since_epoch());
268 lclTime.tv_sec = micros.count() / 1000000;
269 lclTime.tv_usec = micros.count() % 1000000;
270 int traceID = trace_name2TID(trace_name(TRACE_NAME, issue.context().file_name(), _trc_.tn, sizeof(_trc_.tn)));
271 std::string complete_message = issue.message();
272 const ers::Issue* issp = &issue;
273 while ((issp = issp->cause())) {
274 char fbuf[0x100], tbuf[0x40];
275 int strip_ns = 1;
276 tp = issp->ptime();
277 std::chrono::milliseconds millis =
278 std::chrono::duration_cast<std::chrono::milliseconds>(tp.time_since_epoch());
279 struct tm tm_s;
280 time_t secs = millis.count() / 1000;
281 localtime_r(&secs, &tm_s);
282 if (strftime(tbuf, sizeof(tbuf), "%Y-%b-%d %H:%M:%S", &tm_s) == 0)
283 tbuf[0] = '\0';
284 complete_message += "\n\tcaused by: " + std::string(tbuf);
285 int milliseconds = millis.count() % 1000;
286 sprintf(tbuf, ",%03d ", milliseconds);
287 complete_message += std::string(tbuf);
288 trace_func_to_short_func(issp->context().function_name(), fbuf, sizeof(fbuf), strip_ns);
289 complete_message += ers::to_string(issp->severity()) + " [" + fbuf + " at " +
290 trace_path_components(issp->context().file_name(), 0) + ":" +
291 std::to_string(issp->context().line_number()) + "] " + issp->message();
292 }
293 trace(&lclTime,
294 traceID,
295 lvl_,
296 issue.context().line_number(),
297 issue.context().function_name(),
298 0 TRACE_XTRA_PASSED,
299 complete_message.c_str());
300 }
301 }
302 chained().write(issue);
303 }
304};
305}
306ERS_REGISTER_OUTPUT_STREAM(ers::erstraceStream, "erstrace", ERS_EMPTY) // last param is "param"
307
308// Support macros
309#define SL_FRC(lvl) ((lvl) >= 0 && (lvl) < TLVL_DEBUG)
310
311#define LOG0_()
312#define LOG1_(value) value,
313#define LOG2_(value, value1) value, value1,
314#define COMMA_IF_PARENS(...) ,
315#define LPAREN (
316#define EXPAND_(...) __VA_ARGS__
317#define CHOOSE_(...) EXPAND_(LOG__ LPAREN \
318 __VA_ARGS__ COMMA_IF_PARENS __VA_ARGS__ COMMA_IF_PARENS __VA_ARGS__ (), \
319 LOG2_, impossible, LOG2_, LOG1_, LOG0_, LOG1_, ))
320#define LOG__(a0, a1, a2, a3, a4, a5, arg, ...) arg
321#define _tlog_ARG2(a1, a2, ...) tlog_ARG2(a1, a2, __VA_ARGS__)
322#define _tlog_ARG3(a1, a2, a3, ...) tlog_ARG3(a1, a2, a3, __VA_ARGS__)
323
324#endif // LOGGING_INCLUDE_LOGGING_DETAIL_LOGGER_HXX_
#define ERS_EMPTY
static void verstrace_user(struct timeval *, int TID, uint8_t lvl, const char *insert, const char *file, int line, const char *function, uint16_t nargs, const char *msg, va_list ap)
Definition Logger.hxx:22
static SUPPRESS_NOT_USED_WARN void erstrace_user(struct timeval *tvp, int TID, uint8_t lvl, const char *insert, const char *file, int line, const char *function, uint16_t nargs, const char *msg,...)
Definition Logger.hxx:87
void operator<<(TraceStreamer &x, const ers::Issue &r)
Definition Logger.hxx:128
virtual int line_number() const =0
virtual const char * file_name() const =0
virtual const char * function_name() const =0
Base class for any user define issue.
Definition Issue.hpp:76
const Context & context() const
Context of the issue.
Definition Issue.hpp:102
ers::Severity severity() const
severity of the issue
Definition Issue.hpp:110
const system_clock::time_point & ptime() const
original time point of the issue
Definition Issue.hpp:131
const std::string & message() const
General cause of the issue.
Definition Issue.hpp:104
const Issue * cause() const
return the cause Issue of this Issue
Definition Issue.hpp:100
virtual void write(const Issue &issue)=0
OutputStream & chained()
#define ERS_REGISTER_OUTPUT_STREAM(class, name, param)
Definition macro.hpp:27
void warning(const Issue &issue)
Definition ers.hpp:150
void info(const Issue &issue)
Definition ers.hpp:121
void log(const Issue &issue)
Definition ers.hpp:131
std::string to_string(severity s)
void debug(const Issue &issue, int level=debug_level())
Definition ers.hpp:91
void fatal(const Issue &issue)
Definition ers.hpp:111
@ Debug
Definition Severity.hpp:38
@ Error
Definition Severity.hpp:42
@ Fatal
Definition Severity.hpp:43
@ Log
Definition Severity.hpp:39
@ Warning
Definition Severity.hpp:41
@ Information
Definition Severity.hpp:40
void error(const Issue &issue)
Definition ers.hpp:101
#define TRACE_NAME
enum severity type
Definition Severity.hpp:57
void write(const ers::Issue &issue)
Definition Logger.hxx:234