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