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