HDK
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
logging.h
Go to the documentation of this file.
1 // Copyright Contributors to the OpenVDB Project
2 // SPDX-License-Identifier: MPL-2.0
3 
4 #ifndef OPENVDB_UTIL_LOGGING_HAS_BEEN_INCLUDED
5 #define OPENVDB_UTIL_LOGGING_HAS_BEEN_INCLUDED
6 
7 #include <openvdb/version.h>
8 
9 #ifdef OPENVDB_USE_LOG4CPLUS
10 
11 #include <log4cplus/appender.h>
12 #include <log4cplus/configurator.h>
13 #include <log4cplus/consoleappender.h>
14 #include <log4cplus/layout.h>
15 #include <log4cplus/logger.h>
16 #include <log4cplus/spi/loggingevent.h>
17 #include <algorithm> // for std::remove()
18 #include <cstring> // for ::strrchr()
19 #include <memory>
20 #include <sstream>
21 #include <string>
22 #include <vector>
23 
24 
25 namespace openvdb {
27 namespace OPENVDB_VERSION_NAME {
28 namespace logging {
29 
30 /// @brief Message severity level
31 enum class Level {
32  Debug = log4cplus::DEBUG_LOG_LEVEL,
33  Info = log4cplus::INFO_LOG_LEVEL,
34  Warn = log4cplus::WARN_LOG_LEVEL,
35  Error = log4cplus::ERROR_LOG_LEVEL,
36  Fatal = log4cplus::FATAL_LOG_LEVEL
37 };
38 
39 
40 namespace internal {
41 
42 /// @brief log4cplus layout that outputs text in different colors
43 /// for different log levels, using ANSI escape codes
44 class ColoredPatternLayout: public log4cplus::PatternLayout
45 {
46 public:
47  explicit ColoredPatternLayout(const std::string& progName_, bool useColor = true)
48  : log4cplus::PatternLayout(
49  progName_.empty() ? std::string{"%5p: %m%n"} : (progName_ + " %5p: %m%n"))
50  , mUseColor(useColor)
51  , mProgName(progName_)
52  {
53  }
54 
55  ~ColoredPatternLayout() override {}
56 
57  const std::string& progName() const { return mProgName; }
58 
59  void formatAndAppend(log4cplus::tostream& strm,
60  const log4cplus::spi::InternalLoggingEvent& event) override
61  {
62  if (!mUseColor) {
63  log4cplus::PatternLayout::formatAndAppend(strm, event);
64  return;
65  }
66  log4cplus::tostringstream s;
67  switch (event.getLogLevel()) {
68  case log4cplus::DEBUG_LOG_LEVEL: s << "\033[32m"; break; // green
69  case log4cplus::ERROR_LOG_LEVEL:
70  case log4cplus::FATAL_LOG_LEVEL: s << "\033[31m"; break; // red
71  case log4cplus::INFO_LOG_LEVEL: s << "\033[36m"; break; // cyan
72  case log4cplus::WARN_LOG_LEVEL: s << "\033[35m"; break; // magenta
73  }
74  log4cplus::PatternLayout::formatAndAppend(s, event);
75  strm << s.str() << "\033[0m" << std::flush;
76  }
77 
78 // Disable deprecation warnings for std::auto_ptr.
79 #if defined(__ICC)
80  #pragma warning push
81  #pragma warning disable:1478
82 #elif defined(__clang__)
83  #pragma clang diagnostic push
84  #pragma clang diagnostic ignored "-Wdeprecated-declarations"
85 #elif defined(__GNUC__)
86  #pragma GCC diagnostic push
87  #pragma GCC diagnostic ignored "-Wdeprecated-declarations"
88 #endif
89 
90 #if defined(LOG4CPLUS_VERSION) && defined(LOG4CPLUS_MAKE_VERSION)
91  #if LOG4CPLUS_VERSION >= LOG4CPLUS_MAKE_VERSION(2, 0, 0)
92  // In log4cplus 2.0.0, std::auto_ptr was replaced with std::unique_ptr.
93  using Ptr = std::unique_ptr<log4cplus::Layout>;
94  #else
95  using Ptr = std::auto_ptr<log4cplus::Layout>;
96  #endif
97 #else
98  using Ptr = std::auto_ptr<log4cplus::Layout>;
99 #endif
100 
101  static Ptr create(const std::string& progName_, bool useColor = true)
102  {
103  return Ptr{new ColoredPatternLayout{progName_, useColor}};
104  }
105 
106 #if defined(__ICC)
107  #pragma warning pop
108 #elif defined(__clang__)
109  #pragma clang diagnostic pop
110 #elif defined(__GNUC__)
111  #pragma GCC diagnostic pop
112 #endif
113 
114 private:
115  bool mUseColor = true;
116  std::string mProgName;
117 }; // class ColoredPatternLayout
118 
119 
120 inline log4cplus::Logger
121 getLogger()
122 {
123  return log4cplus::Logger::getInstance(LOG4CPLUS_TEXT("openvdb"));
124 }
125 
126 
127 inline log4cplus::SharedAppenderPtr
128 getAppender()
129 {
130  return getLogger().getAppender(LOG4CPLUS_TEXT("OPENVDB"));
131 }
132 
133 } // namespace internal
134 
135 
136 /// @brief Return the current logging level.
137 inline Level
138 getLevel()
139 {
140  switch (internal::getLogger().getLogLevel()) {
141  case log4cplus::DEBUG_LOG_LEVEL: return Level::Debug;
142  case log4cplus::INFO_LOG_LEVEL: return Level::Info;
143  case log4cplus::WARN_LOG_LEVEL: return Level::Warn;
144  case log4cplus::ERROR_LOG_LEVEL: return Level::Error;
145  case log4cplus::FATAL_LOG_LEVEL: break;
146  }
147  return Level::Fatal;
148 }
149 
150 
151 /// @brief Set the logging level. (Lower-level messages will be suppressed.)
152 inline void
153 setLevel(Level lvl)
154 {
155  internal::getLogger().setLogLevel(static_cast<log4cplus::LogLevel>(lvl));
156 }
157 
158 
159 /// @brief If "-debug", "-info", "-warn", "-error" or "-fatal" is found
160 /// in the given array of command-line arguments, set the logging level
161 /// appropriately and remove the relevant argument(s) from the array.
162 inline void
163 setLevel(int& argc, char* argv[])
164 {
165  for (int i = 1; i < argc; ++i) { // note: skip argv[0]
166  const std::string arg{argv[i]};
167  bool remove = true;
168  if (arg == "-debug") { setLevel(Level::Debug); }
169  else if (arg == "-error") { setLevel(Level::Error); }
170  else if (arg == "-fatal") { setLevel(Level::Fatal); }
171  else if (arg == "-info") { setLevel(Level::Info); }
172  else if (arg == "-warn") { setLevel(Level::Warn); }
173  else { remove = false; }
174  if (remove) argv[i] = nullptr;
175  }
176  auto end = std::remove(argv + 1, argv + argc, nullptr);
177  argc = static_cast<int>(end - argv);
178 }
179 
180 
181 /// @brief Specify a program name to be displayed in log messages.
182 inline void
183 setProgramName(const std::string& progName, bool useColor = true)
184 {
185  // Change the layout of the OpenVDB appender to use colored text
186  // and to incorporate the supplied program name.
187  if (auto appender = internal::getAppender()) {
188  appender->setLayout(internal::ColoredPatternLayout::create(progName, useColor));
189  }
190 }
191 
192 
193 /// @brief Initialize the logging system if it is not already initialized.
194 inline void
195 initialize(bool useColor = true)
196 {
198 
199  if (internal::getAppender()) return; // already initialized
200 
201  // Create the OpenVDB logger if it doesn't already exist.
202  auto logger = internal::getLogger();
203 
204  // Disable "additivity", so that OpenVDB-related messages are directed
205  // to the OpenVDB logger only and are not forwarded up the logger tree.
206  logger.setAdditivity(false);
207 
208  // Attach a console appender to the OpenVDB logger.
209  if (auto appender = log4cplus::SharedAppenderPtr{new log4cplus::ConsoleAppender}) {
210  appender->setName(LOG4CPLUS_TEXT("OPENVDB"));
211  logger.addAppender(appender);
212  }
213 
215  setProgramName("", useColor);
216 }
217 
218 
219 /// @brief Initialize the logging system from command-line arguments.
220 /// @details If "-debug", "-info", "-warn", "-error" or "-fatal" is found
221 /// in the given array of command-line arguments, set the logging level
222 /// appropriately and remove the relevant argument(s) from the array.
223 inline void
224 initialize(int& argc, char* argv[], bool useColor = true)
225 {
226  initialize();
227 
228  setLevel(argc, argv);
229 
230  auto progName = (argc > 0 ? argv[0] : "");
231  if (const char* ptr = ::strrchr(progName, '/')) progName = ptr + 1;
232  setProgramName(progName, useColor);
233 }
234 
235 } // namespace logging
236 } // namespace OPENVDB_VERSION_NAME
237 } // namespace openvdb
238 
239 
240 #define OPENVDB_LOG(level, message) \
241  do { \
242  auto _log = openvdb::logging::internal::getLogger(); \
243  if (_log.isEnabledFor(log4cplus::level##_LOG_LEVEL)) { \
244  std::ostringstream _buf; \
245  _buf << message; \
246  _log.forcedLog(log4cplus::level##_LOG_LEVEL, _buf.str(), __FILE__, __LINE__); \
247  } \
248  } while (0);
249 
250 /// Log an info message of the form '<TT>someVar << "some text" << ...</TT>'.
251 #define OPENVDB_LOG_INFO(message) OPENVDB_LOG(INFO, message)
252 /// Log a warning message of the form '<TT>someVar << "some text" << ...</TT>'.
253 #define OPENVDB_LOG_WARN(message) OPENVDB_LOG(WARN, message)
254 /// Log an error message of the form '<TT>someVar << "some text" << ...</TT>'.
255 #define OPENVDB_LOG_ERROR(message) OPENVDB_LOG(ERROR, message)
256 /// Log a fatal error message of the form '<TT>someVar << "some text" << ...</TT>'.
257 #define OPENVDB_LOG_FATAL(message) OPENVDB_LOG(FATAL, message)
258 #ifdef DEBUG
259 /// In debug builds only, log a debugging message of the form '<TT>someVar << "text" << ...</TT>'.
260 #define OPENVDB_LOG_DEBUG(message) OPENVDB_LOG(DEBUG, message)
261 #else
262 /// In debug builds only, log a debugging message of the form '<TT>someVar << "text" << ...</TT>'.
263 #define OPENVDB_LOG_DEBUG(message)
264 #endif
265 /// @brief Log a debugging message in both debug and optimized builds.
266 /// @warning Don't use this in performance-critical code.
267 #define OPENVDB_LOG_DEBUG_RUNTIME(message) OPENVDB_LOG(DEBUG, message)
268 
269 #else // ifdef OPENVDB_USE_LOG4CPLUS
270 
271 #include <iostream>
272 
273 #define OPENVDB_LOG_INFO(mesg)
274 #define OPENVDB_LOG_WARN(mesg) do { std::cerr << "WARNING: " << mesg << std::endl; } while (0);
275 #define OPENVDB_LOG_ERROR(mesg) do { std::cerr << "ERROR: " << mesg << std::endl; } while (0);
276 #define OPENVDB_LOG_FATAL(mesg) do { std::cerr << "FATAL: " << mesg << std::endl; } while (0);
277 #define OPENVDB_LOG_DEBUG(mesg)
278 #define OPENVDB_LOG_DEBUG_RUNTIME(mesg)
279 
280 namespace openvdb {
282 namespace OPENVDB_VERSION_NAME {
283 namespace logging {
284 
285 enum class Level { Debug, Info, Warn, Error, Fatal };
286 
287 inline Level getLevel() { return Level::Warn; }
288 inline void setLevel(Level) {}
289 inline void setLevel(int&, char*[]) {}
290 inline void setProgramName(const std::string&, bool = true) {}
291 inline void initialize() {}
292 inline void initialize(int&, char*[], bool = true) {}
293 
294 } // namespace logging
295 } // namespace OPENVDB_VERSION_NAME
296 } // namespace openvdb
297 
298 #endif // OPENVDB_USE_LOG4CPLUS
299 
300 
301 namespace openvdb {
303 namespace OPENVDB_VERSION_NAME {
304 namespace logging {
305 
306 /// @brief A LevelScope object sets the logging level to a given level
307 /// and restores it to the current level when the object goes out of scope.
309 {
311  explicit LevelScope(Level newLevel): level(getLevel()) { setLevel(newLevel); }
313 };
314 
315 } // namespace logging
316 } // namespace OPENVDB_VERSION_NAME
317 } // namespace openvdb
318 
319 #endif // OPENVDB_UTIL_LOGGING_HAS_BEEN_INCLUDED
GLdouble s
Definition: glew.h:1390
internal::named_arg< T, char > arg(string_view name, const T &arg)
Definition: core.h:1393
#define OPENVDB_USE_VERSION_NAMESPACE
Definition: version.h:166
OIIO_API bool remove(string_view path, std::string &err)
A LevelScope object sets the logging level to a given level and restores it to the current level when...
Definition: logging.h:308
void initialize(int &, char *[], bool=true)
Definition: logging.h:292
GLuint GLuint end
Definition: glew.h:1253
void setProgramName(const std::string &, bool=true)
Definition: logging.h:290
GLsizei const GLchar *const * string
Definition: glew.h:1844
cl_event event
Definition: glew.h:3695
const void * ptr(const T *p)
Definition: format.h:3292
void initialize()
Global registration of basic types.
Definition: logging.h:291
#define OPENVDB_VERSION_NAME
The version namespace name for this library version.
Definition: version.h:112
GLint level
Definition: glew.h:1252