HDK
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
diagnosticMgr.h
Go to the documentation of this file.
1 //
2 // Copyright 2016 Pixar
3 //
4 // Licensed under the Apache License, Version 2.0 (the "Apache License")
5 // with the following modification; you may not use this file except in
6 // compliance with the Apache License and the following modification to it:
7 // Section 6. Trademarks. is deleted and replaced with:
8 //
9 // 6. Trademarks. This License does not grant permission to use the trade
10 // names, trademarks, service marks, or product names of the Licensor
11 // and its affiliates, except as required to comply with Section 4(c) of
12 // the License and to reproduce the content of the NOTICE file.
13 //
14 // You may obtain a copy of the Apache License at
15 //
16 // http://www.apache.org/licenses/LICENSE-2.0
17 //
18 // Unless required by applicable law or agreed to in writing, software
19 // distributed under the Apache License with the above modification is
20 // distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
21 // KIND, either express or implied. See the Apache License for the specific
22 // language governing permissions and limitations under the Apache License.
23 //
24 #ifndef PXR_BASE_TF_DIAGNOSTIC_MGR_H
25 #define PXR_BASE_TF_DIAGNOSTIC_MGR_H
26 
27 /// \file tf/diagnosticMgr.h
28 
29 #include "pxr/pxr.h"
31 #include "pxr/base/tf/debug.h"
33 #include "pxr/base/tf/error.h"
34 #include "pxr/base/tf/singleton.h"
35 #include "pxr/base/tf/status.h"
37 #include "pxr/base/tf/warning.h"
38 #include "pxr/base/tf/weakPtr.h"
39 #include "pxr/base/tf/enum.h"
40 #include "pxr/base/tf/api.h"
41 
42 #include "pxr/base/arch/inttypes.h"
45 
46 #include <tbb/enumerable_thread_specific.h>
47 #include <tbb/spin_rw_mutex.h>
48 #include <tbb/atomic.h>
49 
50 #include <cstdarg>
51 #include <list>
52 #include <string>
53 #include <vector>
54 
56 
58  TF_LOG_STACK_TRACE_ON_ERROR,
59  TF_LOG_STACK_TRACE_ON_WARNING,
60  TF_ERROR_MARK_TRACKING,
61  TF_PRINT_ALL_POSTED_ERRORS_TO_STDERR
62  );
63 
64 class TfError;
65 class TfErrorMark;
66 
67 /// \class TfDiagnosticMgr
68 /// \ingroup group_tf_Diagnostic
69 ///
70 /// Singleton class through which all errors and diagnostics pass.
71 class TfDiagnosticMgr : public TfWeakBase {
72 public:
73 
75 
76  typedef std::list<TfError> ErrorList;
77 
78  /// Synonym for standard STL iterator to traverse the error list.
79  ///
80  /// The error list for a thread is an STL list. The \c ErrorIterator type
81  /// is an STL iterator and can be used without restriction in any way that
82  /// it is legal to use an STL iterator.
83  ///
84  /// Given an iterator, one accesses the error in the standard STL fashion:
85  /// \code
86  /// TfErrorMark m;
87  ///
88  /// ... ;
89  /// if (!m.IsClean()) {
90  /// TfErrorMark::Iterator i;
91  /// for (i = m.GetBegin(); i != m.GetEnd(); ++i) {
92  /// cout << "file = " << i->GetSourceFileName()
93  /// << "line = " << i->GetSourceLineNumber() << "\n";
94  /// }
95  /// \endcode
96  typedef ErrorList::iterator ErrorIterator;
97 
98  /// Returns the name of the given diagnostic code.
99  TF_API
100  static std::string GetCodeName(const TfEnum &code);
101 
102  /// Return a human-readable diagnostic message. The TfDiagnosticMgr uses
103  /// this function to print diagnostics when no diagnostic delegates are
104  /// installed. Diagnostic delegate implementations can call this to produce
105  /// messages in the same format, if desired.
106  TF_API
107  static std::string FormatDiagnostic(const TfEnum &code,
108  const TfCallContext &context, const std::string &msg,
109  const TfDiagnosticInfo &info);
110 
111  /// \class Delegate
112  /// One may set a delegate with the \c TfDiagnosticMgr which will be
113  /// called to respond to errors and diagnostics.
114  ///
115  /// \note None of the methods in \c TfDiagnosticMgr::Delegate can be
116  /// reentrant.
117  ///
118  /// Practically speaking, this means they cannot invoke:
119  ///
120  /// - TF_ERROR
121  /// - TF_RUNTIME_ERROR
122  /// - TF_CODING_ERROR
123  /// - TF_WARN
124  /// - TF_STATUS
125  ///
126  /// For a more complete list, see diagnostic.h
127  ///
128  class Delegate {
129  public:
130  TF_API
131  virtual ~Delegate() = 0;
132 
133  /// Called when a \c TfError is posted.
134  virtual void IssueError(TfError const &err) = 0;
135 
136  /// Called when a \c TF_FATAL_ERROR is issued (or a failed
137  /// \c TF_AXIOM).
138  virtual void IssueFatalError(TfCallContext const &context,
139  std::string const &msg) = 0;
140 
141  /// Called when a \c TF_STATUS() is issued.
142  virtual void IssueStatus(TfStatus const &status) = 0;
143 
144  /// Called when a \c TF_WARNING() is issued.
145  virtual void IssueWarning(TfWarning const &warning) = 0;
146 
147  protected:
148  /// Abort the program, but avoid the session logging mechanism. This
149  /// is intended to be used for fatal error cases where any information
150  /// has already been logged.
151  TF_API
152  void _UnhandledAbort() const;
153  };
154 
155  /// Return the singleton instance.
156  TF_API static This &GetInstance() {
158  }
159 
160  /// Add the delegate \p delegate to the list of current delegates.
161  ///
162  /// This will add the delegate even if it already exists in the list.
163  ///
164  /// Each delegate will be called when diagnostics and errors are invoked
165  ///
166  /// This function is thread safe.
167  TF_API
168  void AddDelegate(Delegate* delegate);
169 
170  /// Removes all delegates equal to \p delegate from the current delegates.
171  ///
172  /// This function is thread safe.
173  TF_API
174  void RemoveDelegate(Delegate* delegate);
175 
176  /// Set whether errors, warnings and status messages should be printed out
177  /// to the terminal.
178  TF_API
179  void SetQuiet(bool quiet) { _quiet = quiet; }
180 
181  /// Return an iterator to the beginning of this thread's error list.
182  ErrorIterator GetErrorBegin() { return _errorList.local().begin(); }
183 
184  /// Return an iterator to the end of this thread's error list.
185  ErrorIterator GetErrorEnd() { return _errorList.local().end(); }
186 
187  /// Remove error specified by iterator \p i.
188  /// \deprecated Use TfErrorMark instead.
189  TF_API
191 
192  /// Remove all the errors in [first, last) from this thread's error
193  /// stream. This should generally not be invoked directly. Use TfErrorMark
194  /// instead.
195  TF_API
197 
198  /// Append an error to the list of active errors. This is generally not
199  /// meant to be called by user code. It is public so that the system
200  /// which translates tf errors to and from python exceptions can manage
201  /// errors.
202  TF_API
203  void AppendError(TfError const &e);
204 
205  /// This method will create a TfError, append it to the error list, and
206  /// pass it to all delegates.
207  ///
208  /// If no delegates have been registered and no error mark is active, this
209  /// method will print the error to stderr.
210  TF_API
211  void PostError(TfEnum errorCode, const char* errorCodeString,
212  TfCallContext const &context,
213  const std::string& commentary, TfDiagnosticInfo info,
214  bool quiet);
215 
216  /// This method will create a TfError, append it to the error list, and
217  /// pass it to all delegates.
218  ///
219  /// If no delegates have been registered and no error mark is active, this
220  /// method will print the error to stderr.
221  TF_API
222  void PostError(const TfDiagnosticBase& diagnostic);
223 
224  /// This method will create a TfWarning and pass it to all delegates.
225  ///
226  /// If no delegates have been registered, this method will print the
227  /// warning msg to stderr.
228  TF_API
229  void PostWarning(TfEnum warningCode, const char *warningCodeString,
230  TfCallContext const &context, std::string const &commentary,
231  TfDiagnosticInfo info, bool quiet) const;
232 
233  /// This method will create a TfWarning and pass it to all delegates.
234  ///
235  /// If no delegates have been registered, this method will print the
236  /// warning msg to stderr.
237  TF_API
238  void PostWarning(const TfDiagnosticBase& diagnostic) const;
239 
240  /// This method will create a TfStatus and pass it to all delegates.
241  ///
242  /// If no delegates have been registered, this method will print the
243  /// status msg to stderr.
244  TF_API
245  void PostStatus(TfEnum statusCode, const char *statusCodeString,
246  TfCallContext const &context, std::string const &commentary,
247  TfDiagnosticInfo info, bool quiet) const;
248 
249  /// This method will create a TfStatus and pass it to all delegates.
250  ///
251  /// If no delegates have been registered, this method will print the
252  /// status msg to stderr.
253  TF_API
254  void PostStatus(const TfDiagnosticBase& diagnostic) const;
255 
256  /// This method will issue a fatal error to all delegates.
257  ///
258  /// If no delegates have been registered, this method will print the error
259  /// msg and abort the process.
260  TF_API
261  void PostFatal(TfCallContext const &context, TfEnum statusCode,
262  std::string const &msg) const;
263 
264  /// Return true if an instance of TfErrorMark exists in the current thread
265  /// of execution, false otherwise.
266  bool HasActiveErrorMark() { return _errorMarkCounts.local() > 0; }
267 
268 #if !defined(doxygen)
269  //
270  // Public, but *only* meant to be used by the TF_ERROR() macro.
271  //
272  /// \private
273  class ErrorHelper {
274  public:
275  ErrorHelper(TfCallContext const &context, TfEnum errorCode,
276  const char* errorCodeString)
277  : _context(context), _errorCode(errorCode),
278  _errorCodeString(errorCodeString)
279  {
280  }
281 
282  TF_API
283  void Post(const char* fmt, ...) const
284  ARCH_PRINTF_FUNCTION(2,3);
285 
286  TF_API
287  void PostQuietly(const char* fmt, ...) const
288  ARCH_PRINTF_FUNCTION(2,3);
289 
290  TF_API
291  void Post(const std::string& msg) const;
292 
293  TF_API
294  void PostWithInfo(
295  const std::string& msg,
296  TfDiagnosticInfo info = TfDiagnosticInfo()) const;
297 
298  TF_API
299  void PostQuietly(const std::string& msg,
300  TfDiagnosticInfo info = TfDiagnosticInfo()) const;
301 
302  private:
303  TfCallContext _context;
304  TfEnum _errorCode;
305  const char *_errorCodeString;
306  };
307 
308  struct WarningHelper {
310  const char *warningCodeString)
311  : _context(context), _warningCode(warningCode),
312  _warningCodeString(warningCodeString)
313  {
314  }
315 
316  TF_API
317  void Post(const char* fmt, ...) const
318  ARCH_PRINTF_FUNCTION(2,3);
319 
320  TF_API
321  void PostQuietly(const char* fmt, ...) const
322  ARCH_PRINTF_FUNCTION(2,3);
323 
324  TF_API
325  void Post(const std::string &str) const;
326 
327  TF_API
328  void PostWithInfo(
329  const std::string& msg,
330  TfDiagnosticInfo info = TfDiagnosticInfo()) const;
331 
332  TF_API
333  void PostQuietly(const std::string& msg) const;
334 
335  private:
336  TfCallContext _context;
337  TfEnum _warningCode;
338  const char *_warningCodeString;
339  };
340 
341  struct StatusHelper {
343  const char *statusCodeString)
344  : _context(context), _statusCode(statusCode),
345  _statusCodeString(statusCodeString)
346  {
347  }
348 
349  TF_API
350  void Post(const char* fmt, ...) const
351  ARCH_PRINTF_FUNCTION(2,3);
352 
353  TF_API
354  void PostQuietly(const char* fmt, ...) const
355  ARCH_PRINTF_FUNCTION(2,3);
356 
357  TF_API
358  void Post(const std::string &str) const;
359 
360  TF_API
361  void PostWithInfo(
362  const std::string& msg,
363  TfDiagnosticInfo info = TfDiagnosticInfo()) const;
364 
365  TF_API
366  void PostQuietly(const std::string& msg) const;
367 
368  private:
369  TfCallContext _context;
370  TfEnum _statusCode;
371  const char *_statusCodeString;
372  };
373 
374  struct FatalHelper {
376  : _context(context),
377  _statusCode(statusCode)
378  {
379  }
380 
381  void Post(const std::string &str) const {
382  This::GetInstance().PostFatal(_context, _statusCode, str);
383  }
384  private:
385  TfCallContext _context;
386  TfEnum _statusCode;
387  };
388 
389 #endif
390 
391 private:
392 
393  TfDiagnosticMgr();
394  virtual ~TfDiagnosticMgr();
395  friend class TfSingleton<This>;
396 
397  // Return an iterator to the first error with serial number >= mark, or the
398  // past-the-end iterator, if no such errors exist.
399  TF_API
400  ErrorIterator _GetErrorMarkBegin(size_t mark, size_t *nErrors);
401 
402  // Invoked by ErrorMark ctor.
403  inline void _CreateErrorMark() { ++_errorMarkCounts.local(); }
404 
405  // Invoked by ErrorMark dtor.
406  inline bool _DestroyErrorMark() { return --_errorMarkCounts.local() == 0; }
407 
408  // Report an error, either via delegate or print to stderr, and issue a
409  // notice if this thread of execution is the main thread.
410  void _ReportError(const TfError &err);
411 
412  // Splice the errors in src into this thread's local list. Also reassign
413  // serial numbers to all the spliced errors to ensure they work correctly
414  // with local error marks.
415  void _SpliceErrors(ErrorList &src);
416 
417  // Helper to append pending error messages to the crash log.
418  void _AppendErrorsToLogText(ErrorIterator i);
419 
420  // Helper to fully rebuild the crash log error text when errors are erased
421  // from the middle.
422  void _RebuildErrorLogText();
423 
424  // Helper to actually publish log text into the Arch crash handler.
425  void _SetLogInfoForErrors(std::vector<std::string> const &logText) const;
426 
427  // A guard used to protect reentrency when adding/removing
428  // delegates as well as posting errors/warnings/statuses
429  mutable tbb::enumerable_thread_specific<bool> _reentrantGuard;
430 
431  // The registered delegates.
432  std::vector<Delegate*> _delegates;
433 
434  mutable tbb::spin_rw_mutex _delegatesMutex;
435 
436  // Global serial number for sorting.
437  tbb::atomic<size_t> _nextSerial;
438 
439  // Thread-specific error list.
440  tbb::enumerable_thread_specific<ErrorList> _errorList;
441 
442  // Thread-specific diagnostic log text for pending errors.
443  struct _LogText {
444  void AppendAndPublish(ErrorIterator i, ErrorIterator end);
445  void RebuildAndPublish(ErrorIterator i, ErrorIterator end);
446 
447  std::pair<std::vector<std::string>,
448  std::vector<std::string>> texts;
449  bool parity = false;
450  private:
451  void _AppendAndPublishImpl(bool clear,
453  };
454  tbb::enumerable_thread_specific<_LogText> _logText;
455 
456  // Thread-specific error mark counts. Use a native key for best performance
457  // here.
458  tbb::enumerable_thread_specific<
459  size_t, tbb::cache_aligned_allocator<size_t>,
460  tbb::ets_key_per_instance> _errorMarkCounts;
461 
462  bool _quiet;
463 
464  friend class TfError;
465  friend class TfErrorTransport;
466  friend class TfErrorMark;
467 };
468 
470 
472 
473 #endif // PXR_BASE_TF_DIAGNOSTIC_MGR_H
WarningHelper(TfCallContext const &context, TfEnum warningCode, const char *warningCodeString)
static T & GetInstance()
Definition: singleton.h:137
GLenum src
Definition: glew.h:2410
virtual TF_API ~Delegate()=0
#define TF_API
Definition: api.h:40
TF_API ErrorIterator EraseRange(ErrorIterator first, ErrorIterator last)
static TF_API std::string GetCodeName(const TfEnum &code)
Returns the name of the given diagnostic code.
TF_API void PostError(TfEnum errorCode, const char *errorCodeString, TfCallContext const &context, const std::string &commentary, TfDiagnosticInfo info, bool quiet)
TF_API void _UnhandledAbort() const
ErrorIterator GetErrorBegin()
Return an iterator to the beginning of this thread's error list.
ErrorList::iterator ErrorIterator
Definition: diagnosticMgr.h:96
StatusHelper(TfCallContext const &context, TfEnum statusCode, const char *statusCodeString)
static TF_API This & GetInstance()
Return the singleton instance.
TfDiagnosticMgr This
Definition: diagnosticMgr.h:74
TF_API void PostStatus(TfEnum statusCode, const char *statusCodeString, TfCallContext const &context, std::string const &commentary, TfDiagnosticInfo info, bool quiet) const
const GLint * first
Definition: glew.h:1528
Definition: enum.h:139
TF_API ErrorIterator EraseError(ErrorIterator i)
PXR_NAMESPACE_OPEN_SCOPE typedef hboost::any TfDiagnosticInfo
TF_API void PostFatal(TfCallContext const &context, TfEnum statusCode, std::string const &msg) const
virtual void IssueError(TfError const &err)=0
Called when a TfError is posted.
GLuint GLuint end
Definition: glew.h:1253
TF_API void AppendError(TfError const &e)
std::list< TfError > ErrorList
Definition: diagnosticMgr.h:76
FatalHelper(TfCallContext const &context, TfEnum statusCode)
virtual void IssueWarning(TfWarning const &warning)=0
Called when a TF_WARNING() is issued.
TF_API void RemoveDelegate(Delegate *delegate)
bool HasActiveErrorMark()
TF_API void AddDelegate(Delegate *delegate)
TF_API void SetQuiet(bool quiet)
virtual void IssueStatus(TfStatus const &status)=0
Called when a TF_STATUS() is issued.
Definition: error.h:49
GLsizei const GLchar *const * string
Definition: glew.h:1844
PXR_NAMESPACE_CLOSE_SCOPE PXR_NAMESPACE_OPEN_SCOPE
Definition: path.h:1346
TF_API void PostWarning(TfEnum warningCode, const char *warningCodeString, TfCallContext const &context, std::string const &commentary, TfDiagnosticInfo info, bool quiet) const
ErrorIterator GetErrorEnd()
Return an iterator to the end of this thread's error list.
void Post(const std::string &str) const
static TF_API std::string FormatDiagnostic(const TfEnum &code, const TfCallContext &context, const std::string &msg, const TfDiagnosticInfo &info)
#define PXR_NAMESPACE_CLOSE_SCOPE
Definition: pxr.h:91
virtual void IssueFatalError(TfCallContext const &context, std::string const &msg)=0
#define const
Definition: zconf.h:214
PXR_NAMESPACE_OPEN_SCOPE TF_DEBUG_CODES(TF_LOG_STACK_TRACE_ON_ERROR, TF_LOG_STACK_TRACE_ON_WARNING, TF_ERROR_MARK_TRACKING, TF_PRINT_ALL_POSTED_ERRORS_TO_STDERR)
TF_API_TEMPLATE_CLASS(TfSingleton< TfDiagnosticMgr >)