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 
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 
55 PXR_NAMESPACE_OPEN_SCOPE
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 
71 class TfDiagnosticMgr : public TfWeakBase {
72 public:
73 
74  typedef TfDiagnosticMgr This;
75 
76  typedef std::list<TfError> ErrorList;
77 
96  typedef ErrorList::iterator ErrorIterator;
97 
99  TF_API
100  static std::string GetCodeName(const TfEnum &code);
101 
106  TF_API
107  static std::string FormatDiagnostic(const TfEnum &code,
108  const TfCallContext &context, const std::string &msg,
109  const TfDiagnosticInfo &info);
110 
128  class Delegate {
129  public:
130  TF_API
131  virtual ~Delegate() = 0;
132 
134  virtual void IssueError(TfError const &err) = 0;
135 
138  virtual void IssueFatalError(TfCallContext const &context,
139  std::string const &msg) = 0;
140 
142  virtual void IssueStatus(TfStatus const &status) = 0;
143 
145  virtual void IssueWarning(TfWarning const &warning) = 0;
146 
147  protected:
151  TF_API
152  void _UnhandledAbort() const;
153  };
154 
156  TF_API static This &GetInstance() {
158  }
159 
167  TF_API
168  void AddDelegate(Delegate* delegate);
169 
173  TF_API
174  void RemoveDelegate(Delegate* delegate);
175 
178  TF_API
179  void SetQuiet(bool quiet) { _quiet = quiet; }
180 
182  ErrorIterator GetErrorBegin() { return _errorList.local().begin(); }
183 
185  ErrorIterator GetErrorEnd() { return _errorList.local().end(); }
186 
189  TF_API
191 
195  TF_API
197 
202  TF_API
203  void AppendError(TfError const &e);
204 
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 
221  TF_API
222  void PostError(const TfDiagnosticBase& diagnostic);
223 
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 
237  TF_API
238  void PostWarning(const TfDiagnosticBase& diagnostic) const;
239 
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 
253  TF_API
254  void PostStatus(const TfDiagnosticBase& diagnostic) const;
255 
260  [[noreturn]]
261  TF_API
262  void PostFatal(TfCallContext const &context, TfEnum statusCode,
263  std::string const &msg) const;
264 
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  //
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
286 
287  TF_API
288  void PostQuietly(const char* fmt, ...) const
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
320 
321  TF_API
322  void PostQuietly(const char* fmt, ...) const
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
353 
354  TF_API
355  void PostQuietly(const char* fmt, ...) const
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 
470 TF_API_TEMPLATE_CLASS(TfSingleton<TfDiagnosticMgr>);
471 
472 PXR_NAMESPACE_CLOSE_SCOPE
473 
474 #endif // PXR_BASE_TF_DIAGNOSTIC_MGR_H
Manage a single instance of an object.
Manage a single instance of an object (see.
Definition: singleton.h:119
Singleton class through which all errors and diagnostics pass.
Definition: diagnosticMgr.h:71
virtual void IssueStatus(TfStatus const &status)=0
Called when a TF_STATUS() is issued.
Functions for recording call locations.
Conditional debugging output class and macros.
Define preprocessor function name macros.
virtual void IssueWarning(TfWarning const &warning)=0
Called when a TF_WARNING() is issued.
TF_API void SetQuiet(bool quiet)
Set whether errors, warnings and status messages should be printed out to the terminal.
Define function attributes.
static TF_API std::string GetCodeName(const TfEnum &code)
Returns the name of the given diagnostic code.
Definitions of basic string utilities in tf.
An enum class that records both enum type and enum value.
Definition: enum.h:139
ErrorIterator GetErrorEnd()
Return an iterator to the end of this thread's error list.
static TF_API This & GetInstance()
Return the singleton instance.
Pointer storage with deletion detection.
static TF_API std::string FormatDiagnostic(const TfEnum &code, const TfCallContext &context, const std::string &msg, const TfDiagnosticInfo &info)
Return a human-readable diagnostic message.
#define TF_DEBUG_CODES(...)
Define debugging symbols.
Definition: debug.h:393
bool HasActiveErrorMark()
Return true if an instance of TfErrorMark exists in the current thread of execution,...
TF_API void AddDelegate(Delegate *delegate)
Add the delegate delegate to the list of current delegates.
Represents the base class of an object representing a diagnostic message.
ErrorIterator GetErrorBegin()
Return an iterator to the beginning of this thread's error list.
TF_API ErrorIterator EraseRange(ErrorIterator first, ErrorIterator last)
Remove all the errors in [first, last) from this thread's error stream.
Class used to record the end of the error-list.
Definition: errorMark.h:66
#define ARCH_PRINTF_FUNCTION(_fmt, _firstArg)
Macro used to indicate a function takes a printf-like specification.
Definition: attributes.h:51
TF_API void PostWarning(TfEnum warningCode, const char *warningCodeString, TfCallContext const &context, std::string const &commentary, TfDiagnosticInfo info, bool quiet) const
This method will create a TfWarning and pass it to all delegates.
Represents an object that contains information about a status message.
Definition: status.h:44
TF_API void _UnhandledAbort() const
Abort the program, but avoid the session logging mechanism.
static T & GetInstance()
Return a reference to an object of type T, creating it if necessary.
Definition: singleton.h:134
TF_API ErrorIterator EraseError(ErrorIterator i)
Remove error specified by iterator i.
Represents an object that contains error information.
Definition: error.h:49
Define integral types.
virtual void IssueError(TfError const &err)=0
Called when a TfError is posted.
TF_API void PostStatus(TfEnum statusCode, const char *statusCodeString, TfCallContext const &context, std::string const &commentary, TfDiagnosticInfo info, bool quiet) const
This method will create a TfStatus and pass it to all delegates.
TF_API void PostError(TfEnum errorCode, const char *errorCodeString, TfCallContext const &context, const std::string &commentary, TfDiagnosticInfo info, bool quiet)
This method will create a TfError, append it to the error list, and pass it to all delegates.
TF_API void RemoveDelegate(Delegate *delegate)
Removes all delegates equal to delegate from the current delegates.
TF_API void PostFatal(TfCallContext const &context, TfEnum statusCode, std::string const &msg) const
This method will issue a fatal error to all delegates.
Provide facilities for error handling in script.
Enable a concrete base class for use with TfWeakPtr.
Definition: weakBase.h:141
Represents an object that contains information about a warning.
Definition: warning.h:44
ErrorList::iterator ErrorIterator
Synonym for standard STL iterator to traverse the error list.
Definition: diagnosticMgr.h:96
One may set a delegate with the TfDiagnosticMgr which will be called to respond to errors and diagnos...
virtual void IssueFatalError(TfCallContext const &context, std::string const &msg)=0
Called when a TF_FATAL_ERROR is issued (or a failed TF_AXIOM).
A facility for transporting errors from thread to thread.
TF_API void AppendError(TfError const &e)
Append an error to the list of active errors.
Stripped down version of diagnostic.h that doesn't define std::string.