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 
49 #include <atomic>
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, or if none of the delegates abort
259  /// the process, this method will print the error msg and abort the process.
260  [[noreturn]]
261  TF_API
262  void PostFatal(TfCallContext const &context, TfEnum statusCode,
263  std::string const &msg) const;
264 
265  /// Return true if an instance of TfErrorMark exists in the current thread
266  /// of execution, false otherwise.
267  bool HasActiveErrorMark() { return _errorMarkCounts.local() > 0; }
268 
269 #if !defined(doxygen)
270  //
271  // Public, but *only* meant to be used by the TF_ERROR() macro.
272  //
273  /// \private
274  class ErrorHelper {
275  public:
276  ErrorHelper(TfCallContext const &context, TfEnum errorCode,
277  const char* errorCodeString)
278  : _context(context), _errorCode(errorCode),
279  _errorCodeString(errorCodeString)
280  {
281  }
282 
283  TF_API
284  void Post(const char* fmt, ...) const
285  ARCH_PRINTF_FUNCTION(2,3);
286 
287  TF_API
288  void PostQuietly(const char* fmt, ...) const
289  ARCH_PRINTF_FUNCTION(2,3);
290 
291  TF_API
292  void Post(const std::string& msg) const;
293 
294  TF_API
295  void PostWithInfo(
296  const std::string& msg,
297  TfDiagnosticInfo info = TfDiagnosticInfo()) const;
298 
299  TF_API
300  void PostQuietly(const std::string& msg,
301  TfDiagnosticInfo info = TfDiagnosticInfo()) const;
302 
303  private:
304  TfCallContext _context;
305  TfEnum _errorCode;
306  const char *_errorCodeString;
307  };
308 
309  struct WarningHelper {
310  WarningHelper(TfCallContext const &context, TfEnum warningCode,
311  const char *warningCodeString)
312  : _context(context), _warningCode(warningCode),
313  _warningCodeString(warningCodeString)
314  {
315  }
316 
317  TF_API
318  void Post(const char* fmt, ...) const
319  ARCH_PRINTF_FUNCTION(2,3);
320 
321  TF_API
322  void PostQuietly(const char* fmt, ...) const
323  ARCH_PRINTF_FUNCTION(2,3);
324 
325  TF_API
326  void Post(const std::string &str) const;
327 
328  TF_API
329  void PostWithInfo(
330  const std::string& msg,
331  TfDiagnosticInfo info = TfDiagnosticInfo()) const;
332 
333  TF_API
334  void PostQuietly(const std::string& msg) const;
335 
336  private:
337  TfCallContext _context;
338  TfEnum _warningCode;
339  const char *_warningCodeString;
340  };
341 
342  struct StatusHelper {
343  StatusHelper(TfCallContext const &context, TfEnum statusCode,
344  const char *statusCodeString)
345  : _context(context), _statusCode(statusCode),
346  _statusCodeString(statusCodeString)
347  {
348  }
349 
350  TF_API
351  void Post(const char* fmt, ...) const
352  ARCH_PRINTF_FUNCTION(2,3);
353 
354  TF_API
355  void PostQuietly(const char* fmt, ...) const
356  ARCH_PRINTF_FUNCTION(2,3);
357 
358  TF_API
359  void Post(const std::string &str) const;
360 
361  TF_API
362  void PostWithInfo(
363  const std::string& msg,
364  TfDiagnosticInfo info = TfDiagnosticInfo()) const;
365 
366  TF_API
367  void PostQuietly(const std::string& msg) const;
368 
369  private:
370  TfCallContext _context;
371  TfEnum _statusCode;
372  const char *_statusCodeString;
373  };
374 
375  struct FatalHelper {
376  FatalHelper(TfCallContext const &context, TfEnum statusCode)
377  : _context(context),
378  _statusCode(statusCode)
379  {
380  }
381  [[noreturn]]
382  void Post(const std::string &str) const {
383  This::GetInstance().PostFatal(_context, _statusCode, str);
384  }
385  private:
386  TfCallContext _context;
387  TfEnum _statusCode;
388  };
389 
390 #endif
391 
392 private:
393 
394  TfDiagnosticMgr();
395  virtual ~TfDiagnosticMgr();
396  friend class TfSingleton<This>;
397 
398  // Return an iterator to the first error with serial number >= mark, or the
399  // past-the-end iterator, if no such errors exist.
400  TF_API
401  ErrorIterator _GetErrorMarkBegin(size_t mark, size_t *nErrors);
402 
403  // Invoked by ErrorMark ctor.
404  inline void _CreateErrorMark() { ++_errorMarkCounts.local(); }
405 
406  // Invoked by ErrorMark dtor.
407  inline bool _DestroyErrorMark() { return --_errorMarkCounts.local() == 0; }
408 
409  // Report an error, either via delegate or print to stderr, and issue a
410  // notice if this thread of execution is the main thread.
411  void _ReportError(const TfError &err);
412 
413  // Splice the errors in src into this thread's local list. Also reassign
414  // serial numbers to all the spliced errors to ensure they work correctly
415  // with local error marks.
416  void _SpliceErrors(ErrorList &src);
417 
418  // Helper to append pending error messages to the crash log.
419  void _AppendErrorsToLogText(ErrorIterator i);
420 
421  // Helper to fully rebuild the crash log error text when errors are erased
422  // from the middle.
423  void _RebuildErrorLogText();
424 
425  // Helper to actually publish log text into the Arch crash handler.
426  void _SetLogInfoForErrors(std::vector<std::string> const &logText) const;
427 
428  // A guard used to protect reentrency when adding/removing
429  // delegates as well as posting errors/warnings/statuses
430  mutable tbb::enumerable_thread_specific<bool> _reentrantGuard;
431 
432  // The registered delegates.
433  std::vector<Delegate*> _delegates;
434 
435  mutable tbb::spin_rw_mutex _delegatesMutex;
436 
437  // Global serial number for sorting.
438  std::atomic<size_t> _nextSerial;
439 
440  // Thread-specific error list.
441  tbb::enumerable_thread_specific<ErrorList> _errorList;
442 
443  // Thread-specific diagnostic log text for pending errors.
444  struct _LogText {
445  void AppendAndPublish(ErrorIterator i, ErrorIterator end);
446  void RebuildAndPublish(ErrorIterator i, ErrorIterator end);
447 
448  std::pair<std::vector<std::string>,
449  std::vector<std::string>> texts;
450  bool parity = false;
451  private:
452  void _AppendAndPublishImpl(bool clear,
454  };
455  tbb::enumerable_thread_specific<_LogText> _logText;
456 
457  // Thread-specific error mark counts. Use a native key for best performance
458  // here.
459  tbb::enumerable_thread_specific<
460  size_t, tbb::cache_aligned_allocator<size_t>,
461  tbb::ets_key_per_instance> _errorMarkCounts;
462 
463  bool _quiet;
464 
465  friend class TfError;
466  friend class TfErrorTransport;
467  friend class TfErrorMark;
468 };
469 
471 
473 
474 #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:137
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.
GLsizei const GLchar *const * string
Definition: glcorearb.h:814
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
Definition: enum.h:137
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: glcorearb.h:475
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
PXR_NAMESPACE_CLOSE_SCOPE PXR_NAMESPACE_OPEN_SCOPE
Definition: path.h:1441
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 >)
GLenum src
Definition: glcorearb.h:1793