IMP  2.0.0
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-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 
26 #ifndef IMP_DOXYGEN
27 #define IMP_LOG_USING \
28  using IMP::base::VERBOSE; \
29  using IMP::base::TERSE; \
30  using IMP::base::SILENT; \
31  using IMP::base::WARNING; \
32  using IMP::base::PROGRESS; \
33  using IMP::base::MEMORY
34 
35 #endif
36 
37 #if !defined(IMP_HAS_LOG)
38 #error "IMP_HAS_LOG is not defined, compilation is broken"
39 #endif
40 
41 #if !defined(IMP_SILENT)
42 #error "IMP_SILENT is not defined, compilation is broken"
43 #endif
44 
45 #if defined(IMP_DOXYGEN)
46 //! Execute the code block if a certain level of logging is on
47 /**
48  The next code block (delimited by { }) is executed if
49  get_log_level() >= level.
50 
51  \code
52  IMP_IF_LOG(VERBOSE) {
53  Floats testp(input.begin(), input.end());
54  std::sort(testp.begin(), testp.end());
55  IMP_LOG_VERBOSE( "Sorted order is ");
56  IMP_LOG_WRITE(VERBOSE, std::copy(testp.begin(), testp.end(),
57  std::ostream_iterator<double>(IMP_STREAM, " ")));
58  }
59  \endcode
60  */
61 #define IMP_IF_LOG(level)
62 
63 //! Write a warning to a log.
64 /** \param[in] expr An expression to be output to the log. It is prefixed
65  by "WARNING"
66  */
67 #define IMP_WARN(expr)
68 
69 //! Write a warning to standard error.
70 /** \param[in] expr An expression to be output to std::cerr. It is prefixed
71  by "ERROR"
72  */
73 #define IMP_ERROR(expr)
74 
75 /** \param[in] expr A stream expression to be sent to the output stream if the
76  log level is at least TERSE.
77 
78  Usage:
79  \code
80  IMP_LOG_VERBOSE( "Hi there, I'm very talkative. My favorite numbers are "
81  << 1 << " " << 2 << " " << 3);
82  \endcode
83 */
84 #define IMP_LOG_TERSE(expr)
85 
86 /** \param[in] expr A stream expression to be sent to the output stream if the
87  log level is at least TERSE.
88 
89  Usage:
90  \code
91  IMP_LOG_VERBOSE( "Hi there, I'm very talkative. My favorite numbers are "
92  << 1 << " " << 2 << " " << 3);
93  \endcode
94 */
95 #define IMP_LOG_VERBOSE(expr)
96 
97 /** \param[in] expr A stream expression to be sent to the output stream if the
98  log level is at least PROGRESS.
99 
100  Usage:
101  \code
102  IMP_LOG_VERBOSE( "Hi there, I'm very talkative. My favorite numbers are "
103  << 1 << " " << 2 << " " << 3);
104  \endcode
105 */
106 #define IMP_LOG_PROGRESS(expr)
107 
108 /** Mark a variable as one that is only used in logging. This disables
109  unused variable warnings on it in fast mode.
110 */
111 #define IMP_LOG_VARIABLE(variable)
112 
113 
114 #else // IMP_DOXYGEN
115 
116 #define IMP_LOG(level, expr) \
117  { \
118  IMP_LOG_USING; \
119  switch(level) { \
120  case SILENT: \
121  break; \
122  case PROGRESS: \
123  IMP_LOG_PROGRESS(expr); break;\
124  case TERSE: \
125  IMP_LOG_TERSE(expr); break;\
126  case WARNING: \
127  IMP_WARN(expr); break;\
128  case VERBOSE: \
129  IMP_LOG_VERBOSE(expr); break;\
130  case MEMORY: \
131  IMP_LOG_MEMORY(expr); break;\
132  case IMP::base::DEFAULT: \
133  case IMP::base::ALL_LOG: \
134  default: \
135  IMP_ERROR("Unknown log level " \
136  << boost::lexical_cast<std::string>(level)); \
137  } \
138  }
139 
140 
141 #if IMP_HAS_LOG < IMP_PROGRESS
142 #define IMP_IF_LOG(level) if (false)
143 #define IMP_LOG_PROGRESS(expr)
144 #define IMP_WARN(expr) if (false) std::cout << expr;
145 #define IMP_LOG_VARIABLE(variable) IMP_UNUSED(variable)
146 #else
147 #define IMP_LOG_VARIABLE(variable)
148 #endif
149 
150 
151 #if IMP_HAS_LOG < IMP_TERSE
152 #define IMP_LOG_TERSE(expr)
153 #endif
154 
155 #if IMP_HAS_LOG < IMP_VERBOSE
156 #define IMP_LOG_VERBOSE(expr)
157 #define IMP_LOG_MEMORY(expr)
158 #endif
159 
160 #if IMP_BASE_HAS_LOG4CXX
161 
162 // figure out later
163 
164 #if IMP_HAS_LOG >= IMP_PROGRESS
165 #define IMP_IF_LOG(level) if (true)
166 #define IMP_LOG_PROGRESS(expr) {\
167  using IMP::base::internal::log::operator<<; \
168  LOG4CXX_INFO(IMP::base::get_logger(), expr);\
169  }
170 #define IMP_WARN(expr) { \
171  using IMP::base::internal::log::operator<<; \
172  LOG4CXX_WARN(IMP::base::get_logger(), expr); \
173  }
174 #endif
175 
176 #if IMP_HAS_LOG >= IMP_TERSE
177 #define IMP_LOG_TERSE(expr) { \
178  using IMP::base::internal::log::operator<<; \
179  LOG4CXX_INFO(IMP::base::get_logger(), expr); \
180  }
181 #endif
182 
183 #if IMP_HAS_LOG >= IMP_VERBOSE
184 #define IMP_LOG_VERBOSE(expr) { \
185  using IMP::base::internal::log::operator<<; \
186  LOG4CXX_DEBUG(IMP::base::get_logger(), expr); \
187  }
188 
189 #define IMP_LOG_MEMORY(expr) { \
190  using IMP::base::internal::log::operator<<; \
191  LOG4CXX_TRACE(IMP::base::get_logger(), expr); \
192  }
193 #endif
194 
195 
196 
197 #define IMP_ERROR(expr) { \
198  using IMP::base::internal::log::operator<<; \
199  LOG4CXX_ERROR(IMP::base::get_logger(), expr); \
200  }
201 
202 
203 #else // log4cxx
204 
205 #if IMP_HAS_LOG > IMP_SILENT
206 #define IMP_IF_LOG(level) \
207  IMP_LOG_USING; \
208  if (level <= ::IMP::base::get_log_level())
209 #define IMP_LOG_PROGRESS(expr) \
210  if (IMP::base::get_log_level() >= IMP::base::PROGRESS) {\
211  std::ostringstream oss; oss << expr;\
212  IMP::base::add_to_log(oss.str());\
213  }
214 
215 #define IMP_WARN(expr) if (IMP::base::get_log_level() >= IMP::base::WARNING) \
216  { std::ostringstream oss; \
217  oss << "WARNING " << expr << std::flush; \
218  IMP::base::add_to_log(oss.str()); \
219  };
220 #endif
221 
222 #if IMP_HAS_LOG >= IMP_TERSE
223 #define IMP_LOG_TERSE(expr) \
224  if (IMP::base::get_log_level() >= IMP::base::TERSE) {\
225  std::ostringstream oss; oss << expr;\
226  IMP::base::add_to_log(oss.str());\
227  }
228 
229 #endif
230 
231 #if IMP_HAS_LOG >= IMP_VERBOSE
232 #define IMP_LOG_VERBOSE(expr) \
233  if (IMP::base::get_log_level() >= IMP::base::VERBOSE) {\
234  std::ostringstream oss; oss << expr;\
235  IMP::base::add_to_log(oss.str());\
236  }
237 #define IMP_LOG_MEMORY(expr) \
238  if (IMP::base::get_log_level() >= IMP::base::MEMORY) {\
239  std::ostringstream oss; oss << expr;\
240  IMP::base::add_to_log(oss.str());\
241  }
242 #endif
243 
244 #define IMP_ERROR(expr) \
245  {\
246  std::cerr << "ERROR: " << expr << std::endl; \
247  throw IMP::base::InternalException("Failure");\
248 }
249 
250 #endif // log4cxx
251 
252 #endif // else on IMP_DXOYGEN
253 
254 #define IMP_ERROR_WRITE(expr) { \
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::base::SetLogState log_state_guard__(this->get_log_level()); \
286  IMP::base::SetCheckState check_state_guard__(this->get_check_level()); \
287  IMP_CHECK_OBJECT(this); \
288  IMP::base::CreateLogContext log_context__(__func__, this)
289 
290 //! Beginning logging for a non-member function
291 /**
292  */
293 #define IMP_FUNCTION_LOG \
294  IMP::base::CreateLogContext log_context__(__func__)
295 
296 //! Create a new long context from a streamed name
297 #define IMP_LOG_CONTEXT(name) \
298  IMP::base::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) IMP_IF_LOG(WARNING) { \
308  std::ostringstream oss; \
309  oss << expr << std::flush; \
310  context.add_warning(key, oss.str()); \
311  }
312 
313 
314 /** Like IMP::base::set_progress_display() but you can use stream operations
315  for the name.*/
316 #define IMP_PROGRESS_DISPLAY(name, steps) {\
317  if (IMP::base::get_log_level() >= IMP::base::PROGRESS) { \
318  std::ostringstream oss; \
319  oss << name; \
320  IMP::base::set_progress_display(oss.str(), steps); \
321  } \
322  }
323 
324 #else
325 #define IMP_OBJECT_LOG
326 #define IMP_FUNCTION_LOG
327 #define IMP_LOG_CONTEXT(name)
328 #define IMP_WARN_ONCE(key, expr, context)
329 #define IMP_PROGRESS_DISPLAY(name, steps)
330 #endif
331 
332 
333 #endif /* IMPBASE_LOG_MACROS_H */