1 /*=========================================================================
2 
3   Program:   Visualization Toolkit
4   Module:    vtkLogger.h
5 
6   Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
7   All rights reserved.
8   See Copyright.txt or http://www.kitware.com/Copyright.htm for details.
9 
10      This software is distributed WITHOUT ANY WARRANTY; without even
11      the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
12      PURPOSE.  See the above copyright notice for more information.
13 
14 =========================================================================*/
15 /**
16  * @class vtkLogger
17  * @brief logging framework for use in VTK and in applications based on VTK
18  *
19  * vtkLogger acts as the entry point to VTK's logging framework. The
20  * implementation uses the loguru (https://github.com/emilk/loguru). vtkLogger
21  * provides some static API to initialize and configure logging together with a
22  * collection of macros that can be used to add items to the generated log.
23  *
24  * The logging framework is based on verbosity levels. Level 0-9 are supported
25  * in addition to named levels such as ERROR, WARNING, and INFO. When a log for
26  * a particular verbosity level is being generated, all log additions issued
27  * with verbosity level less than or equal to the requested verbosity level will
28  * get logged.
29  *
30  * When using any of the logging macros, it must be noted that unless a log output
31  * is requesting that verbosity provided (or higher), the call is a no-op and
32  * the message stream or printf-style arguments will not be evaluated.
33  *
34  * @section Setup Setup
35  *
36  * To initialize logging, in your application's `main()` you may call
37  * `vtkLogger::Init(argv, argc)`. This is totally optional but useful to
38  * time-stamp the  start of the  log. Furthermore, it can optionally detect
39  * verbosity level on the command line as `-v` (or any another string pass as
40  * the optional argument to `Init`) that will be used as the verbosity level for
41  * logging on to `stderr`. By default, it is set to `0` (or `INFO`) unless
42  * changed by calling `vtkLogger::SetStderrVerbosity`.
43  *
44  * In additional to logging to `stderr`, one can accumulate logs to one or more files using
45  * `vtkLogger::LogToFile`. Each log file can be given its own verbosity level.
46  *
47  * For multithreaded applications, you may want to name each of the threads so
48  * that the generated log can use human readable names for the threads. For
49  * that, use `vtkLogger::SetThreadName`. Calling `vtkLogger::Init` will set the name
50  * for the main thread.
51  *
52  * To prevent the logging framework from intercepting signals from your application,
53  * you can set the static variable `vtkLogger::EnableUnsafeSignalHandler` to `false`
54  * prior to calling `vtkLogger::Init(argc, argv)` or `vtkLogger::Init()`.
55  *
56  * @section Logging Logging
57  *
58  * vtkLogger provides several macros (again, based on `loguru`) that can be
59  * used to add the log. Both printf-style and stream-style is supported. All
60  * printf-style macros are suffixed with `F` to distinguish them from the stream
61  * macros. Another pattern in naming macros is the presence of `V`
62  * e.g. `vtkVLog` vs `vtkLog`. A macro with the `V` prefix takes a fully
63  * qualified verbosity enum e.g. `vtkLogger::VERBOSITY_INFO` or
64  * `vtkLogger::VERBOSITY_0`, while the non-`V` variant takes the verbosity
65  * name e.g. `INFO` or `0`.
66  *
67  * Following code snippet provides an overview of the available macros and their
68  * usage.
69  *
70  * @code{.cpp}
71  *
72  *  // Optional, leaving this as the default value `true` will let the logging
73  *  // framework log signals such as segmentation faults.
74  *
75  *  vtkLogger::EnableUnsafeSignalHandler = false;
76  *
77  *  // Optional, but useful to time-stamp the start of the log.
78  *  // Will also detect verbosity level on the command line as -v.
79  *
80  *  vtkLogger::Init(argc, argv);
81  *
82  *  // Put every log message in "everything.log":
83  *  vtkLogger::LogToFile("everything.log", vtkLogger::APPEND, vtkLogger::VERBOSITY_MAX);
84  *
85  *  // Only log INFO, WARNING, ERROR to "latest_readable.log":
86  *  vtkLogger::LogToFile("latest_readable.log", vtkLogger::TRUNCATE, vtkLogger::VERBOSITY_INFO);
87  *
88  *  // Only show most relevant things on stderr:
89  *  vtkLogger::SetStderrVerbosity(vtkLogger::VERBOSITY_1);
90  *
91  *  // add a line to log using the verbosity name.
92  *  vtkLogF(INFO, "I'm hungry for some %.3f!", 3.14159);
93  *  vtkLogF(0, "same deal");
94  *
95  *  // add a line to log using the verbosity enum.
96  *  vtkVLogF(vtkLogger::VERBOSITY_INFO, "I'm hungry for some %.3f!", 3.14159);
97  *  vtkVLogF(vtkLogger::VERBOSITY_0, "same deal");
98  *
99  *  // to add an identifier for a vtkObjectBase or subclass
100  *  vtkLogF(INFO, "The object is %s", vtkLogIdentifier(vtkobject));
101  *
102  *  // add a line conditionally to log if the condition succeeds:
103  *  vtkLogIfF(INFO, ptr == nullptr, "ptr is nullptr (some number: %.3f)", *  3.14159);
104  *
105  *  vtkLogScopeF(INFO, "Will indent all log messages within this scope.");
106  *  // in a function, you may use vtkLogScopeFunction(INFO)
107  *
108  *  // scope can be explicitly started and closed by vtkLogStartScope (or
109  *  // vtkLogStartScopef) and vtkLogEndScope
110  *  vtkLogStartScope(INFO, "id-used-as-message");
111  *  vtkLogStartScopeF(INFO, "id", "message-%d", 1);
112  *  vtkLogEndScope("id");
113  *  vtkLogEndScope("id-used-as-message");
114  *
115  *  // alternatively, you can use streams instead of printf-style
116  *  vtkLog(INFO, "I'm hungry for some " << 3.14159 << "!");
117  *  vtkLogIF(INFO, ptr == nullptr, "ptr is " << "nullptr");
118  *
119  * @endcode
120  *
121  * @section LoggingAndLegacyMacros Logging and VTK error macros
122  *
123  * VTK has long supported multiple macros to report errors, warnings and debug
124  * messages through `vtkErrorMacro`, `vtkWarningMacro`, `vtkDebugMacro`, etc.
125  * In addition to performing the traditional message reporting via
126  * `vtkOutputWindow`, these macros also log to the logging sub-system with
127  * appropriate verbosity levels.
128  *
129  * To avoid the vtkLogger and vtkOutputWindow both posting the message to the
130  * standard output streams, vtkOutputWindow now supports an ability to specify
131  * terminal display mode, via `vtkOutputWindow::SetDisplayMode`. If display mode
132  * is `vtkOutputWindow::DEFAULT` then the output window will not
133  * post messages originating from the standard error/warning/debug macros to the
134  * standard output if VTK is built with logging support. If VTK is not built
135  * with logging support, then vtkOutputWindow will post the messages to the
136  * standard output streams, unless disabled explicitly.
137  *
138  * @section Callbacks Custom callbacks/handlers for log messages
139  *
140  * vtkLogger supports ability to register callbacks to call on each logged
141  * message. This is useful to show the messages in application specific
142  * viewports, e.g. a special message widget.
143  *
144  * To register a callback use `vtkLogger::AddCallback` and to remove a callback
145  * use `vtkLogger::RemoveCallback` with the id provided when registering the
146  * callback.
147  *
148  */
149 
150 #ifndef vtkLogger_h
151 #define vtkLogger_h
152 
153 #include "vtkObjectBase.h"
154 #include "vtkSetGet.h" // needed for macros
155 
156 #include <string> // needed for std::string
157 
158 #if defined(_MSC_VER)
159 #include <sal.h> // Needed for _In_z_ etc annotations
160 #endif
161 
162 // this is copied from `loguru.hpp`
163 #if defined(__clang__) || defined(__GNUC__)
164 // Helper macro for declaring functions as having similar signature to printf.
165 // This allows the compiler to catch format errors at compile-time.
166 #define VTK_PRINTF_LIKE(fmtarg, firstvararg)                                                       \
167   __attribute__((__format__(__printf__, fmtarg, firstvararg)))
168 #define VTK_FORMAT_STRING_TYPE const char*
169 #elif defined(_MSC_VER)
170 #define VTK_PRINTF_LIKE(fmtarg, firstvararg)
171 #define VTK_FORMAT_STRING_TYPE _In_z_ _Printf_format_string_ const char*
172 #else
173 #define VTK_PRINTF_LIKE(fmtarg, firstvararg)
174 #define VTK_FORMAT_STRING_TYPE const char*
175 #endif
176 
177 class VTKCOMMONCORE_EXPORT vtkLogger : public vtkObjectBase
178 {
179 public:
180   vtkBaseTypeMacro(vtkLogger, vtkObjectBase);
181   void PrintSelf(ostream& os, vtkIndent indent) override;
182 
183   enum Verbosity
184   {
185     // Used to mark an invalid verbosity. Do not log to this level.
186     VERBOSITY_INVALID = -10, // Never do LOG_F(INVALID)
187 
188     // You may use VERBOSITY_OFF on g_stderr_verbosity, but for nothing else!
189     VERBOSITY_OFF = -9, // Never do LOG_F(OFF)
190 
191     VERBOSITY_ERROR = -2,
192     VERBOSITY_WARNING = -1,
193 
194     // Normal messages. By default written to stderr.
195     VERBOSITY_INFO = 0,
196 
197     // Same as VERBOSITY_INFO in every way.
198     VERBOSITY_0 = 0,
199 
200     // Verbosity levels 1-9 are generally not written to stderr, but are written to file.
201     VERBOSITY_1 = +1,
202     VERBOSITY_2 = +2,
203     VERBOSITY_3 = +3,
204     VERBOSITY_4 = +4,
205     VERBOSITY_5 = +5,
206     VERBOSITY_6 = +6,
207     VERBOSITY_7 = +7,
208     VERBOSITY_8 = +8,
209     VERBOSITY_9 = +9,
210 
211     // trace level, same as VERBOSITY_9
212     VERBOSITY_TRACE = +9,
213 
214     // Don not use higher verbosity levels, as that will make grepping log files harder.
215     VERBOSITY_MAX = +9,
216   };
217 
218   /**
219    * Initializes logging. This should be called from the main thread, if at all.
220    * Your application doesn't *need* to call this, but if you do:
221    *  * signal handlers are installed
222    *  * program arguments are logged
223    *  * working directory is logged
224    *  * optional -v verbosity flag is parsed
225    *  * main thread name is set to "main thread"
226    *  * explanation of the preamble (date, threadname, etc.) is logged.
227    *
228    * This method will look for arguments meant for logging subsystem and remove
229    * them. Arguments meant for logging subsystem are:
230    *
231    * -v n Set stderr logging verbosity. Examples
232    *    -v 3        Show verbosity level 3 and lower.
233    *    -v 0        Only show INFO, WARNING, ERROR, FATAL (default).
234    *    -v INFO     Only show INFO, WARNING, ERROR, FATAL (default).
235    *    -v WARNING  Only show WARNING, ERROR, FATAL.
236    *    -v ERROR    Only show ERROR, FATAL.
237    *    -v FATAL    Only show FATAL.
238    *    -v OFF      Turn off logging to stderr.
239    *
240    * You can set the default logging verbosity programmatically by calling
241    * `vtkLogger::SetStderrVerbosity` before calling `vtkLogger::Init`. That
242    * way, you can specify a default that the user can override using command
243    * line arguments. Note that this does not affect file logging.
244    *
245    * You can also use something else instead of '-v' flag by the via
246    * `verbosity_flag` argument. You can also set to nullptr to skip parsing
247    * verbosity level from the command line arguments.
248    *
249    * For applications that do not want loguru to handle any signals, i.e.,
250    * print a stack trace when a signal is intercepted, the
251    * `vtkLogger::EnableUnsafeSignalHandler` static member variable
252    * should be set to `false`.
253    * @{
254    */
255   static void Init(int& argc, char* argv[], const char* verbosity_flag = "-v");
256   static void Init();
257   /** @} */
258 
259   /**
260    * Set the verbosity level for the output logged to stderr. Everything with a
261    * verbosity equal or less than the level specified will be written to
262    * stderr. Set to `VERBOSITY_OFF` to write nothing to stderr.
263    * Default is 0.
264    */
265   static void SetStderrVerbosity(Verbosity level);
266 
267   /**
268    * Set internal messages verbosity level. The library used by VTK, `loguru`
269    * generates log messages during initialization and at exit. These are logged
270    * as log level VERBOSITY_1, by default. One can change that using this
271    * method. Typically, you want to call this before `vtkLogger::Init`.
272    */
273   static void SetInternalVerbosityLevel(Verbosity level);
274 
275   /**
276    * Support log file modes: `TRUNCATE` truncates the file clearing any existing
277    * contents while `APPEND` appends to the existing log file contents, if any.
278    */
279   enum FileMode
280   {
281     TRUNCATE,
282     APPEND
283   };
284 
285   /**
286    * Enable logging to a file at the given path.
287    * Any logging message with verbosity lower or equal to the given verbosity
288    * will be included. This method will create all directories in the 'path' if
289    * needed. To stop the file logging, call `EndLogToFile` with the same path.
290    */
291   static void LogToFile(const char* path, FileMode filemode, Verbosity verbosity);
292 
293   /**
294    * Stop logging to a file at the given path.
295    */
296   static void EndLogToFile(const char* path);
297 
298   ///@{
299   /**
300    * Get/Set the name to identify the current thread in the log output.
301    */
302   static void SetThreadName(const std::string& name);
303   static std::string GetThreadName();
304   ///@}
305 
306   /**
307    * Returns a printable string for a vtkObjectBase instance.
308    */
309   static std::string GetIdentifier(vtkObjectBase* obj);
310 
311   /**
312    * The message structure that is passed to custom callbacks registered using
313    * `vtkLogger::AddCallback`.
314    */
315   struct Message
316   {
317     // You would generally print a Message by just concatenating the buffers without spacing.
318     // Optionally, ignore preamble and indentation.
319     Verbosity verbosity;     // Already part of preamble
320     const char* filename;    // Already part of preamble
321     unsigned line;           // Already part of preamble
322     const char* preamble;    // Date, time, uptime, thread, file:line, verbosity.
323     const char* indentation; // Just a bunch of spacing.
324     const char* prefix;      // Assertion failure info goes here (or "").
325     const char* message;     // User message goes here.
326   };
327 
328   ///@{
329   /**
330    * Callback handle types.
331    */
332   using LogHandlerCallbackT = void (*)(void* user_data, const Message& message);
333   using CloseHandlerCallbackT = void (*)(void* user_data);
334   using FlushHandlerCallbackT = void (*)(void* user_data);
335   ///@}
336 
337   /**
338    * Add a callback to call on each log message with a  verbosity less or equal
339    * to the given one.  Useful for displaying messages in an application output
340    * window, for example. The given `on_close` is also expected to flush (if
341    * desired).
342    *
343    * Note that if logging is disabled at compile time, then these callback will
344    * never be called.
345    */
346   static void AddCallback(const char* id, LogHandlerCallbackT callback, void* user_data,
347     Verbosity verbosity, CloseHandlerCallbackT on_close = nullptr,
348     FlushHandlerCallbackT on_flush = nullptr);
349 
350   /**
351    * Remove a callback using the id specified.
352    * Returns true if and only if the callback was found (and removed).
353    */
354   static bool RemoveCallback(const char* id);
355 
356   /**
357    * Returns true if VTK is built with logging support enabled.
358    */
359   static bool IsEnabled();
360 
361   /**
362    * Returns the maximum verbosity of all log outputs. A log item for a
363    * verbosity higher than this will not be generated in any of the currently
364    * active outputs.
365    */
366   static Verbosity GetCurrentVerbosityCutoff();
367 
368   /**
369    * Convenience function to convert an integer to matching verbosity level. If
370    * val is less than or equal to vtkLogger::VERBOSITY_INVALID, then
371    * vtkLogger::VERBOSITY_INVALID is returned. If value is greater than
372    * vtkLogger::VERBOSITY_MAX, then vtkLogger::VERBOSITY_MAX is returned.
373    */
374   static Verbosity ConvertToVerbosity(int value);
375 
376   /**
377    * Convenience function to convert a string to matching verbosity level.
378    * vtkLogger::VERBOSITY_INVALID will be return for invalid strings.
379    * Accepted string values are OFF, ERROR, WARNING, INFO, TRACE, MAX, INVALID or ASCII
380    * representation for an integer in the range [-9,9].
381    */
382   static Verbosity ConvertToVerbosity(const char* text);
383 
384   ///@{
385   /**
386    * @internal
387    *
388    * Not intended for public use, please use the logging macros instead.
389    */
390   static void Log(
391     Verbosity verbosity, VTK_FILEPATH const char* fname, unsigned int lineno, const char* txt);
392   static void StartScope(
393     Verbosity verbosity, const char* id, VTK_FILEPATH const char* fname, unsigned int lineno);
394   static void EndScope(const char* id);
395 #if !defined(__WRAP__)
396   static void LogF(Verbosity verbosity, VTK_FILEPATH const char* fname, unsigned int lineno,
397     VTK_FORMAT_STRING_TYPE format, ...) VTK_PRINTF_LIKE(4, 5);
398   static void StartScopeF(Verbosity verbosity, const char* id, VTK_FILEPATH const char* fname,
399     unsigned int lineno, VTK_FORMAT_STRING_TYPE format, ...) VTK_PRINTF_LIKE(5, 6);
400 
401   class VTKCOMMONCORE_EXPORT LogScopeRAII
402   {
403   public:
404     LogScopeRAII();
405     LogScopeRAII(vtkLogger::Verbosity verbosity, const char* fname, unsigned int lineno,
406       VTK_FORMAT_STRING_TYPE format, ...) VTK_PRINTF_LIKE(5, 6);
407     ~LogScopeRAII();
408 #if defined(_MSC_VER) && _MSC_VER > 1800
409     // see loguru.hpp for the reason why this is needed on MSVC
LogScopeRAII(LogScopeRAII && other)410     LogScopeRAII(LogScopeRAII&& other)
411       : Internals(other.Internals)
412     {
413       other.Internals = nullptr;
414     }
415 #else
416     LogScopeRAII(LogScopeRAII&&) = default;
417 #endif
418 
419   private:
420     LogScopeRAII(const LogScopeRAII&) = delete;
421     void operator=(const LogScopeRAII&) = delete;
422     class LSInternals;
423     LSInternals* Internals;
424   };
425 #endif
426   ///@}
427 
428   /**
429    * Flag to enable/disable the logging frameworks printing of a stack trace
430    * when catching signals, which could lead to crashes and deadlocks in
431    * certain circumstances.
432    */
433   static bool EnableUnsafeSignalHandler;
434 
435 protected:
436   vtkLogger();
437   ~vtkLogger() override;
438 
439 private:
440   vtkLogger(const vtkLogger&) = delete;
441   void operator=(const vtkLogger&) = delete;
442   static vtkLogger::Verbosity InternalVerbosityLevel;
443   static std::string ThreadName;
444 };
445 
446 ///@{
447 /**
448  * Add to log given the verbosity level.
449  * The text will be logged when the log verbosity is set to the specified level
450  * or higher.
451  *
452  *     // using printf-style
453  *     vtkLogF(INFO, "Hello %s", "world!");
454  *     vtkVLogF(vtkLogger::VERBOSITY_INFO, "Hello %s", "world!");
455  *
456  *     // using streams
457  *     vtkLog(INFO, "Hello " << "world!");
458  *     vtkVLog(vtkLogger::VERBOSITY_INFO, << "Hello world!");
459  *
460  */
461 #define vtkVLogF(level, ...)                                                                       \
462   ((level) > vtkLogger::GetCurrentVerbosityCutoff())                                               \
463     ? (void)0                                                                                      \
464     : vtkLogger::LogF(level, __FILE__, __LINE__, __VA_ARGS__)
465 #define vtkLogF(verbosity_name, ...) vtkVLogF(vtkLogger::VERBOSITY_##verbosity_name, __VA_ARGS__)
466 #define vtkVLog(level, x)                                                                          \
467   if ((level) <= vtkLogger::GetCurrentVerbosityCutoff())                                           \
468   {                                                                                                \
469     vtkOStrStreamWrapper::EndlType endl;                                                           \
470     vtkOStrStreamWrapper::UseEndl(endl);                                                           \
471     vtkOStrStreamWrapper vtkmsg;                                                                   \
472     vtkmsg << "" x;                                                                                \
473     vtkLogger::Log(level, __FILE__, __LINE__, vtkmsg.str());                                       \
474     vtkmsg.rdbuf()->freeze(0);                                                                     \
475   }
476 #define vtkLog(verbosity_name, x) vtkVLog(vtkLogger::VERBOSITY_##verbosity_name, x)
477 ///@}
478 
479 ///@{
480 /**
481  * Add to log only when the `cond` passes.
482  *
483  *     // using printf-style
484  *     vtkLogIfF(ERROR, ptr == nullptr, "`ptr` cannot be null!");
485  *     vtkVLogIfF(vtkLogger::VERBOSITY_ERROR, ptr == nullptr, "`ptr` cannot be null!");
486  *
487  *     // using streams
488  *     vtkLogIf(ERROR, ptr == nullptr, "`ptr` cannot be null!");
489  *     vtkVLogIf(vtkLogger::VERBOSITY_ERROR, ptr == nullptr, << "`ptr` cannot be null!");
490  *
491  */
492 #define vtkVLogIfF(level, cond, ...)                                                               \
493   ((level) > vtkLogger::GetCurrentVerbosityCutoff() || (cond) == false)                            \
494     ? (void)0                                                                                      \
495     : vtkLogger::LogF(level, __FILE__, __LINE__, __VA_ARGS__)
496 
497 #define vtkLogIfF(verbosity_name, cond, ...)                                                       \
498   vtkVLogIfF(vtkLogger::VERBOSITY_##verbosity_name, cond, __VA_ARGS__)
499 
500 #define vtkVLogIf(level, cond, x)                                                                  \
501   if ((level) <= vtkLogger::GetCurrentVerbosityCutoff() && (cond))                                 \
502   {                                                                                                \
503     vtkOStrStreamWrapper::EndlType endl;                                                           \
504     vtkOStrStreamWrapper::UseEndl(endl);                                                           \
505     vtkOStrStreamWrapper vtkmsg;                                                                   \
506     vtkmsg << "" x;                                                                                \
507     vtkLogger::Log(level, __FILE__, __LINE__, vtkmsg.str());                                       \
508     vtkmsg.rdbuf()->freeze(0);                                                                     \
509   }
510 #define vtkLogIf(verbosity_name, cond, x) vtkVLogIf(vtkLogger::VERBOSITY_##verbosity_name, cond, x)
511 ///@}
512 
513 #define VTKLOG_CONCAT_IMPL(s1, s2) s1##s2
514 #define VTKLOG_CONCAT(s1, s2) VTKLOG_CONCAT_IMPL(s1, s2)
515 #define VTKLOG_ANONYMOUS_VARIABLE(x) VTKLOG_CONCAT(x, __LINE__)
516 
517 #define vtkVLogScopeF(level, ...)                                                                  \
518   auto VTKLOG_ANONYMOUS_VARIABLE(msg_context) = ((level) > vtkLogger::GetCurrentVerbosityCutoff()) \
519     ? vtkLogger::LogScopeRAII()                                                                    \
520     : vtkLogger::LogScopeRAII(level, __FILE__, __LINE__, __VA_ARGS__)
521 
522 #define vtkLogScopeF(verbosity_name, ...)                                                          \
523   vtkVLogScopeF(vtkLogger::VERBOSITY_##verbosity_name, __VA_ARGS__)
524 
525 #define vtkLogScopeFunction(verbosity_name) vtkLogScopeF(verbosity_name, "%s", __func__)
526 #define vtkVLogScopeFunction(level) vtkVLogScopeF(level, "%s", __func__)
527 
528 ///@{
529 /**
530  * Explicitly mark start and end of log scope. This is useful in cases where the
531  * start and end of the scope does not happen within the same C++ scope.
532  */
533 #define vtkLogStartScope(verbosity_name, id)                                                       \
534   vtkLogger::StartScope(vtkLogger::VERBOSITY_##verbosity_name, id, __FILE__, __LINE__)
535 #define vtkLogEndScope(id) vtkLogger::EndScope(id)
536 
537 #define vtkLogStartScopeF(verbosity_name, id, ...)                                                 \
538   vtkLogger::StartScopeF(vtkLogger::VERBOSITY_##verbosity_name, id, __FILE__, __LINE__, __VA_ARGS__)
539 
540 #define vtkVLogStartScope(level, id) vtkLogger::StartScope(level, id, __FILE__, __LINE__)
541 #define vtkVLogStartScopeF(level, id, ...)                                                         \
542   vtkLogger::StartScopeF(level, id, __FILE__, __LINE__, __VA_ARGS__)
543 ///@}
544 
545 /**
546  * Convenience macro to generate an identifier string for any vtkObjectBase subclass.
547  * @note do not store the returned value as it returns a char* pointer to a
548  * temporary std::string that will be released as soon as it goes out of scope.
549  */
550 #define vtkLogIdentifier(vtkobject) vtkLogger::GetIdentifier(vtkobject).c_str()
551 
552 #endif
553