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