IMP  2.3.1
The Integrative Modeling Platform
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-2014 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 #endif
228 
229 #if IMP_HAS_LOG >= IMP_TERSE
230 #define IMP_LOG_TERSE(expr) \
231  if (IMP::base::get_log_level() >= IMP::base::TERSE) { \
232  std::ostringstream oss; \
233  oss << expr; \
234  IMP::base::add_to_log(oss.str()); \
235  }
236 
237 #endif
238 
239 #if IMP_HAS_LOG >= IMP_VERBOSE
240 #define IMP_LOG_VERBOSE(expr) \
241  if (IMP::base::get_log_level() >= IMP::base::VERBOSE) { \
242  std::ostringstream oss; \
243  oss << expr; \
244  IMP::base::add_to_log(oss.str()); \
245  }
246 #define IMP_LOG_MEMORY(expr) \
247  if (IMP::base::get_log_level() >= IMP::base::MEMORY) { \
248  std::ostringstream oss; \
249  oss << expr; \
250  IMP::base::add_to_log(oss.str()); \
251  }
252 #endif
253 
254 #define IMP_ERROR(expr) \
255  { \
256  std::cerr << "ERROR: " << expr << std::endl; \
257  std::ostringstream oss; \
258  oss << expr; \
259  throw IMP::base::InternalException(oss.str().c_str()); \
260  }
261 
262 #endif // log4cxx
263 
264 #endif // else on IMP_DXOYGEN
265 
266 #define IMP_ERROR_WRITE(expr) \
267  { \
268  std::ostringstream IMP_STREAM; \
269  expr; \
270  IMP_STREAM << std::endl; \
271  IMP_ERROR(IMP_STREAM.str()); \
272  }
273 
274 #define IMP_LOG_WRITE(level, expr) \
275  IMP_IF_LOG(level) { \
276  std::ostringstream IMP_STREAM; \
277  expr; \
278  IMP_STREAM << std::endl; \
279  IMP_LOG(level, IMP_STREAM.str()); \
280  }
281 
282 #define IMP_WARN_WRITE(expr) \
283  IMP_IF_LOG(WARNING) { \
284  std::ostringstream IMP_STREAM; \
285  expr; \
286  IMP_STREAM << std::endl; \
287  IMP_WARN(IMP_STREAM.str()); \
288  }
289 
290 #if IMP_HAS_LOG
291 
292 //! Set the log level to the object's log level.
293 /** All non-trivial Object methods should start with this. It creates a
294  RAII-style object which sets the log level to the local one,
295  if appropriate, until it goes out of scope.
296  */
297 #define IMP_OBJECT_LOG \
298  IMP::base::SetLogState log_state_guard__(this->get_log_level()); \
299  IMP::base::SetCheckState check_state_guard__(this->get_check_level()); \
300  IMP_CHECK_OBJECT(this); \
301  IMP::base::CreateLogContext log_context__(IMP_CURRENT_FUNCTION, this)
302 
303 //! Beginning logging for a non-member function
304 /**
305  */
306 #define IMP_FUNCTION_LOG \
307  IMP::base::CreateLogContext log_context__(IMP_CURRENT_FUNCTION)
308 
309 //! Create a new log context from a streamed name
310 #define IMP_LOG_CONTEXT(name) \
311  IMP::base::CreateLogContext imp_log_context(name, nullptr)
312 
313 //! Write a warning once per context object
314 /** Use this macro to, for example, warn on unprocessable fields in a PDB,
315  since they tend to come together. The key is what is tested
316  for uniqueness, the expr is what is output.
317 
318  Warnings are only output when the context object is destroyed.
319  */
320 #define IMP_WARN_ONCE(key, expr, context) \
321  IMP_IF_LOG(WARNING) { \
322  std::ostringstream oss; \
323  oss << expr << std::flush; \
324  context.add_warning(key, oss.str()); \
325  }
326 
327 /** Like IMP::base::set_progress_display() but you can use stream operations
328  for the name.*/
329 #define IMP_PROGRESS_DISPLAY(name, steps) \
330  { \
331  if (IMP::base::get_log_level() >= IMP::base::PROGRESS) { \
332  std::ostringstream oss; \
333  oss << name; \
334  IMP::base::set_progress_display(oss.str(), steps); \
335  } \
336  }
337 
338 #else
339 #define IMP_OBJECT_LOG
340 #define IMP_FUNCTION_LOG
341 #define IMP_LOG_CONTEXT(name)
342 #define IMP_WARN_ONCE(key, expr, context)
343 #define IMP_PROGRESS_DISPLAY(name, steps)
344 #endif
345 
346 #endif /* IMPBASE_LOG_MACROS_H */
Checking and error reporting support.
Basic types used by IMP.
Logging and error reporting support.
Various compiler workarounds.
Logging and error reporting support.