IMP logo
IMP Reference Guide  develop.1a86c4215a,2024/04/24
The Integrative Modeling Platform
log_macros.h
Go to the documentation of this file.
1 /**
2  * \file IMP/log_macros.h
3  * \brief Logging and error reporting support.
4  *
5  * Copyright 2007-2022 IMP Inventors. All rights reserved.
6  *
7  */
8 
9 #ifndef IMPKERNEL_LOG_MACROS_H
10 #define IMPKERNEL_LOG_MACROS_H
11 
12 #include <IMP/kernel_config.h>
13 #include "enums.h"
14 #include "log.h"
15 #include "CreateLogContext.h"
16 #include "compiler_macros.h"
17 #include "SetCheckState.h"
18 #include "internal/log.h"
19 #include <sstream>
20 
21 #if IMP_KERNEL_HAS_LOG4CXX
22 #include <log4cxx/logger.h>
23 #endif
24 
25 #if !defined(IMP_HAS_LOG)
26 #error "IMP_HAS_LOG is not defined, compilation is broken"
27 #endif
28 
29 #if !defined(IMP_SILENT)
30 #error "IMP_SILENT is not defined, compilation is broken"
31 #endif
32 
33 #if defined(IMP_DOXYGEN)
34 //! Execute the code block if a certain level of logging is on
35 /**
36  The next code block (delimited by { }) is executed if
37  get_log_level() >= level.
38 
39  \code
40  IMP_IF_LOG(VERBOSE) {
41  Floats testp(input.begin(), input.end());
42  std::sort(testp.begin(), testp.end());
43  IMP_LOG_VERBOSE( "Sorted order is ");
44  IMP_LOG_WRITE(VERBOSE, std::copy(testp.begin(), testp.end(),
45  std::ostream_iterator<double>(IMP_STREAM, " ")));
46  }
47  \endcode
48  */
49 #define IMP_IF_LOG(level)
50 
51 //! Write a warning to a log.
52 /** \param[in] expr An expression to be output to the log. It is prefixed
53  by "WARNING"
54  */
55 #define IMP_WARN(expr)
56 
57 //! Write a warning to standard error.
58 /** \param[in] expr An expression to be output to std::cerr. It is prefixed
59  by "ERROR"
60  */
61 #define IMP_ERROR(expr)
62 
63 /** \param[in] expr A stream expression to be sent to the output stream if the
64  log level is at least TERSE.
65 
66  Usage:
67  \code
68  IMP_LOG_VERBOSE( "Hi there, I'm very talkative. My favorite numbers are "
69  << 1 << " " << 2 << " " << 3);
70  \endcode
71 */
72 #define IMP_LOG_TERSE(expr)
73 
74 /** \param[in] expr A stream expression to be sent to the output stream if the
75  log level is at least VERBOSE.
76 
77  Usage:
78  \code
79  IMP_LOG_VERBOSE( "Hi there, I'm very talkative. My favorite numbers are "
80  << 1 << " " << 2 << " " << 3);
81  \endcode
82 */
83 #define IMP_LOG_VERBOSE(expr)
84 
85 /** \param[in] expr A stream expression to be sent to the output stream if the
86  log level is at least PROGRESS.
87 
88  Usage:
89  \code
90  IMP_LOG_PROGRESS( "Hi there, I'm very talkative. My favorite numbers are "
91  << 1 << " " << 2 << " " << 3);
92  \endcode
93 */
94 #define IMP_LOG_PROGRESS(expr)
95 
96 /** Mark a variable as one that is only used in logging. This disables
97  unused variable warnings on it in fast mode.
98 */
99 #define IMP_LOG_VARIABLE(variable)
100 
101 #else // IMP_DOXYGEN
102 
103 #define IMP_LOG(level, expr) \
104  { \
105  switch (level) { \
106  case IMP::SILENT: \
107  break; \
108  case IMP::PROGRESS: \
109  IMP_LOG_PROGRESS(expr); \
110  break; \
111  case IMP::TERSE: \
112  IMP_LOG_TERSE(expr); \
113  break; \
114  case IMP::WARNING: \
115  IMP_WARN(expr); \
116  break; \
117  case IMP::VERBOSE: \
118  IMP_LOG_VERBOSE(expr); \
119  break; \
120  case IMP::MEMORY: \
121  IMP_LOG_MEMORY(expr); \
122  break; \
123  case IMP::DEFAULT: \
124  case IMP::ALL_LOG: \
125  default: \
126  IMP_ERROR( \
127  "Unknown log level " << boost::lexical_cast<std::string>(level)); \
128  } \
129  }
130 
131 #if IMP_HAS_LOG < IMP_PROGRESS
132 #define IMP_IF_LOG(level) if (false)
133 #define IMP_LOG_PROGRESS(expr)
134 #define IMP_WARN(expr) \
135  if (false) std::cout << expr;
136 #define IMP_LOG_VARIABLE(variable) IMP_UNUSED(variable)
137 #else
138 #define IMP_LOG_VARIABLE(variable)
139 #endif
140 
141 #if IMP_HAS_LOG < IMP_TERSE
142 #define IMP_LOG_TERSE(expr)
143 #endif
144 
145 #if IMP_HAS_LOG < IMP_VERBOSE
146 #define IMP_LOG_VERBOSE(expr)
147 #define IMP_LOG_MEMORY(expr)
148 #endif
149 
150 #if IMP_KERNEL_HAS_LOG4CXX
151 
152 // figure out later
153 
154 #if IMP_HAS_LOG >= IMP_PROGRESS
155 #define IMP_IF_LOG(level) if (true)
156 #define IMP_LOG_PROGRESS(expr) \
157  { \
158  using IMP::internal::log::operator<<; \
159  LOG4CXX_INFO(IMP::get_logger(), expr); \
160  }
161 #define IMP_WARN(expr) \
162  { \
163  using IMP::internal::log::operator<<; \
164  LOG4CXX_WARN(IMP::get_logger(), expr); \
165  }
166 #endif
167 
168 #if IMP_HAS_LOG >= IMP_TERSE
169 #define IMP_LOG_TERSE(expr) \
170  { \
171  using IMP::internal::log::operator<<; \
172  LOG4CXX_INFO(IMP::get_logger(), expr); \
173  }
174 #endif
175 
176 #if IMP_HAS_LOG >= IMP_VERBOSE
177 #define IMP_LOG_VERBOSE(expr) \
178  { \
179  using IMP::internal::log::operator<<; \
180  LOG4CXX_DEBUG(IMP::get_logger(), expr); \
181  }
182 
183 #define IMP_LOG_MEMORY(expr) \
184  { \
185  using IMP::internal::log::operator<<; \
186  LOG4CXX_TRACE(IMP::get_logger(), expr); \
187  }
188 #endif
189 
190 #define IMP_ERROR(expr) \
191  { \
192  using IMP::internal::log::operator<<; \
193  LOG4CXX_ERROR(IMP::get_logger(), expr << std::endl); \
194  }
195 
196 #else // log4cxx
197 
198 #if IMP_HAS_LOG > IMP_SILENT
199 #define IMP_IF_LOG(level) \
200  if (level <= ::IMP::get_log_level())
201 #define IMP_LOG_PROGRESS(expr) \
202  if (IMP::get_log_level() >= IMP::PROGRESS) { \
203  std::ostringstream oss; \
204  oss << expr; \
205  IMP::add_to_log(oss.str()); \
206  }
207 
208 #define IMP_WARN(expr) \
209  if (IMP::get_log_level() >= IMP::WARNING) { \
210  std::ostringstream oss; \
211  oss << "WARNING " << expr << std::flush; \
212  IMP::add_to_log(oss.str()); \
213  };
214 #endif
215 
216 #if IMP_HAS_LOG >= IMP_TERSE
217 #define IMP_LOG_TERSE(expr) \
218  if (IMP::get_log_level() >= IMP::TERSE) { \
219  std::ostringstream oss; \
220  oss << expr; \
221  IMP::add_to_log(oss.str()); \
222  }
223 
224 #endif
225 
226 #if IMP_HAS_LOG >= IMP_VERBOSE
227 #define IMP_LOG_VERBOSE(expr) \
228  if (IMP::get_log_level() >= IMP::VERBOSE) { \
229  std::ostringstream oss; \
230  oss << expr; \
231  IMP::add_to_log(oss.str()); \
232  }
233 #define IMP_LOG_MEMORY(expr) \
234  if (IMP::get_log_level() >= IMP::MEMORY) { \
235  std::ostringstream oss; \
236  oss << expr; \
237  IMP::add_to_log(oss.str()); \
238  }
239 #endif
240 
241 #define IMP_ERROR(expr) \
242  { \
243  std::cerr << "ERROR: " << expr << std::endl; \
244  std::ostringstream oss; \
245  oss << expr; \
246  throw IMP::InternalException(oss.str().c_str()); \
247  }
248 
249 #endif // log4cxx
250 
251 #endif // else on IMP_DXOYGEN
252 
253 #define IMP_ERROR_WRITE(expr) \
254  { \
255  std::ostringstream IMP_STREAM; \
256  expr; \
257  IMP_STREAM << std::endl; \
258  IMP_ERROR(IMP_STREAM.str()); \
259  }
260 
261 #define IMP_LOG_WRITE(level, expr) \
262  IMP_IF_LOG(level) { \
263  std::ostringstream IMP_STREAM; \
264  expr; \
265  IMP_STREAM << std::endl; \
266  IMP_LOG(level, IMP_STREAM.str()); \
267  }
268 
269 #define IMP_WARN_WRITE(expr) \
270  IMP_IF_LOG(WARNING) { \
271  std::ostringstream IMP_STREAM; \
272  expr; \
273  IMP_STREAM << std::endl; \
274  IMP_WARN(IMP_STREAM.str()); \
275  }
276 
277 #if IMP_HAS_LOG
278 
279 //! Set the log level to the object's log level.
280 /** All non-trivial Object methods should start with this. It creates a
281  RAII-style object which sets the log level to the local one,
282  if appropriate, until it goes out of scope.
283  */
284 #define IMP_OBJECT_LOG \
285  IMP::SetLogState log_state_guard__(this->get_log_level()); \
286  IMP::SetCheckState check_state_guard__(this->get_check_level()); \
287  IMP_CHECK_OBJECT(this); \
288  IMP::CreateLogContext log_context__(IMP_CURRENT_FUNCTION, this)
289 
290 //! Beginning logging for a non-member function
291 /**
292  */
293 #define IMP_FUNCTION_LOG \
294  IMP::CreateLogContext log_context__(IMP_CURRENT_FUNCTION)
295 
296 //! Create a new log context from a streamed name
297 #define IMP_LOG_CONTEXT(name) \
298  IMP::CreateLogContext imp_log_context(name, nullptr)
299 
300 //! Write a warning once per context object
301 /** Use this macro to, for example, warn on unprocessable fields in a PDB,
302  since they tend to come together. The key is what is tested
303  for uniqueness, the expr is what is output.
304 
305  Warnings are only output when the context object is destroyed.
306  */
307 #define IMP_WARN_ONCE(key, expr, context) \
308  IMP_IF_LOG(WARNING) { \
309  std::ostringstream oss; \
310  oss << expr << std::flush; \
311  context.add_warning(key, oss.str()); \
312  }
313 
314 /** Like IMP::set_progress_display() but you can use stream operations
315  for the name.*/
316 #define IMP_PROGRESS_DISPLAY(name, steps) \
317  { \
318  if (IMP::get_log_level() >= IMP::PROGRESS) { \
319  std::ostringstream oss; \
320  oss << name; \
321  IMP::set_progress_display(oss.str(), steps); \
322  } \
323  }
324 
325 #else
326 #define IMP_OBJECT_LOG
327 #define IMP_FUNCTION_LOG
328 #define IMP_LOG_CONTEXT(name)
329 #define IMP_WARN_ONCE(key, expr, context)
330 #define IMP_PROGRESS_DISPLAY(name, steps)
331 #endif
332 
333 #endif /* IMPKERNEL_LOG_MACROS_H */
Checking and error reporting support.
Basic enumeration types used by IMP.
Logging and error reporting support.
Various compiler workarounds.
Logging and error reporting support.