1 #ifndef DALI_INTEGRATION_DEBUG_H
2 #define DALI_INTEGRATION_DEBUG_H
5 * Copyright (c) 2022 Samsung Electronics Co., Ltd.
7 * Licensed under the Apache License, Version 2.0 (the "License");
8 * you may not use this file except in compliance with the License.
9 * You may obtain a copy of the License at
11 * http://www.apache.org/licenses/LICENSE-2.0
13 * Unless required by applicable law or agreed to in writing, software
14 * distributed under the License is distributed on an "AS IS" BASIS,
15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 * See the License for the specific language governing permissions and
17 * limitations under the License.
29 #include <dali/public-api/common/vector-wrapper.h>
30 #include <dali/public-api/object/property-map.h>
33 #include <dali/public-api/common/dali-common.h>
35 // Using Debug namespace alias shortens the log usage significantly
43 } // namespace Integration
45 namespace Debug = Dali::Integration::Log;
56 #if defined(DEBUG_ENABLED)
58 // Less opaque types for debugger
59 typedef std::vector<Dali::Property::Value> DebugPropertyValueArray;
60 using DebugIndexValuePair = std::pair<Property::Index, Property::Value>;
61 using DebugStringValueContainer = std::vector<Dali::StringValuePair>;
62 using DebugIndexValueContainer = std::vector<DebugIndexValuePair>;
64 struct DebugPropertyValueMap
66 DebugStringValueContainer stringValues;
67 DebugIndexValueContainer intValues;
70 // Fake globals for gdb typedefs
71 extern Dali::DebugPropertyValueArray gValueArray;
72 extern Dali::DebugPropertyValueMap gValueMap;
89 * Used by logging macros to log a message
90 * @param level debug level
91 * @param format string format
93 DALI_CORE_API void LogMessage(enum DebugPriority level, const char* format, ...);
96 * Prefix macros to sync with dlog logger format
97 * __MODULE__ macro also defined at dlog-internal.h
99 #ifndef DALI_LOG_FORMAT_PREFIX
101 #define __MODULE__ (std::strrchr(__FILE__, '/') ? std::strrchr(__FILE__, '/') + 1 : __FILE__)
103 #define DALI_LOG_FORMAT_PREFIX "%s: %s(%d) > "
104 #define DALI_LOG_FORMAT_PREFIX_ARGS __MODULE__, __func__, __LINE__
108 * Global logging macros to log a message along with function/class name and line
109 * @param level debug level
110 * @param format string format
112 #define LogMessageWithFunctionLine(level, format, ...) \
114 (std::string(DALI_LOG_FORMAT_PREFIX) + std::string(format)).c_str(), \
115 DALI_LOG_FORMAT_PREFIX_ARGS, \
119 * typedef for the logging function.
121 using LogFunction = void (*)(DebugPriority, std::string&);
124 * A log function has to be installed for every thread that wants to use logging.
125 * This should be done by the adaptor.
126 * The log function can be different for each thread.
127 * @param logFunction the log function to install
128 * @param logOpts the log options to save in thread
130 DALI_CORE_API void InstallLogFunction(const LogFunction& logFunction);
133 * A log function has to be uninstalled for every thread that wants to use logging.
134 * The log function can be different for each thread.
136 DALI_CORE_API void UninstallLogFunction();
138 /********************************************************************************
139 * Error/Warning macros. *
140 ********************************************************************************/
143 * Provides unfiltered logging for global error level messages
145 #define DALI_LOG_ERROR(format, ...) Dali::Integration::Log::LogMessageWithFunctionLine(Dali::Integration::Log::ERROR, format, ##__VA_ARGS__)
147 #define DALI_LOG_ERROR_NOFN(format, ...) Dali::Integration::Log::LogMessage(Dali::Integration::Log::ERROR, format, ##__VA_ARGS__)
149 #define DALI_LOG_WARNING_NOFN(format, ...) Dali::Integration::Log::LogMessage(Dali::Integration::Log::WARNING, format, ##__VA_ARGS__)
152 * Provides unfiltered logging for fps monitor
154 #define DALI_LOG_FPS(format, ...) Dali::Integration::Log::LogMessage(Dali::Integration::Log::INFO, format, ##__VA_ARGS__)
157 * Provides unfiltered logging for update status
159 #define DALI_LOG_UPDATE_STATUS(format, ...) Dali::Integration::Log::LogMessage(Dali::Integration::Log::INFO, format, ##__VA_ARGS__)
162 * Provides unfiltered logging for render information
164 #define DALI_LOG_RENDER_INFO(format, ...) Dali::Integration::Log::LogMessage(Dali::Integration::Log::INFO, format, ##__VA_ARGS__)
167 * Provides unfiltered logging for release
169 #define DALI_LOG_RELEASE_INFO(format, ...) Dali::Integration::Log::LogMessageWithFunctionLine(Dali::Integration::Log::INFO, format, ##__VA_ARGS__)
172 * Provides unfiltered logging for debuf information
174 #define DALI_LOG_DEBUG_INFO(format, ...) Dali::Integration::Log::LogMessageWithFunctionLine(Dali::Integration::Log::DEBUG, format, ##__VA_ARGS__)
179 * Provides unfiltered logging for global warning level messages
181 #define DALI_LOG_WARNING(format, ...) Dali::Integration::Log::LogMessageWithFunctionLine(Dali::Integration::Log::WARNING, "%s " format, ASSERT_LOCATION, ##__VA_ARGS__)
183 #else // DEBUG_ENABLED
185 // Don't warn on release build
186 #define DALI_LOG_WARNING(format, ...)
190 /********************************************************************************
192 ********************************************************************************/
197 * Enumeration of logging levels.
198 * Used by the filters to provide multiple log levels.
199 * In general, the higher the value, the more debug is available for that filter.
210 * The Filter object is used by the DALI_LOG_INFO macro and others to determine if the logging
211 * should take place, and routes the logging via the platform abstraction's LogMessage.
213 * It provides a logging level. If this is set to zero, then DALI_LOG_INFO won't log anything.
214 * It provides the ability to turn tracing on or off.
217 class DALI_CORE_API Filter
220 using FilterList = std::list<Filter*>;
221 using FilterIter = std::list<Filter*>::iterator;
225 * Test if the filter is enabled for the given logging level
226 * @param[in] level - the level to test.
227 * @return true if this level of logging is enabled.
229 bool IsEnabledFor(LogLevel level)
231 return level != Debug::NoLogging && level <= mLoggingLevel;
235 * Test if trace is enabled for this filter.
236 * @return true if trace is enabled;
238 bool IsTraceEnabled()
240 return mTraceEnabled;
244 * Enable tracing on this filter.
248 mTraceEnabled = true;
252 * Disable tracing on this filter.
256 mTraceEnabled = false;
260 * Set the log level for this filter. Setting to a higher value than Debug::General also
263 void SetLogLevel(LogLevel level)
265 mLoggingLevel = level;
269 * Perform the logging for this filter.
271 void Log(LogLevel level, const char* format, ...);
274 * Create a new filter whose debug level and trace can be modified through the use of an
275 * environment variable.
277 * @param[in] level The default log level
278 * @param[in] trace The default trace level. If true, function tracing is on.
279 * @param[in] environmentVariableName The environment variable name used in order to change the
280 * log level or trace.
282 * @info To modify logg level/trace at runtime, you can should define your filter as shown below:
285 * Debug::Filter* filter = Debug::Filter::New( Debug::NoLogging, false, "FILTER_ENV" );
288 * And to use it when running an executable:
290 * FILTER_ENV=3 dali-demo // LogLevel Verbose, Trace using default
291 * FILTER_ENV=1,true dali-demo // LogLevel Concise, Trace ON
292 * FILTER_ENV=2,false dali-demo // LogLevel General, Trace OFF
293 * FILTER_ENV=0,true dali-demo // LogLevel NoLogging, Trace ON
296 static Filter* New(LogLevel level, bool trace, const char* environmentVariableName);
299 * Enable trace on all filters.
301 static void EnableGlobalTrace();
304 * Disable trace on all filters.
306 static void DisableGlobalTrace();
309 * Set log level for all filters.
311 * @param[in] level The log level
313 static void SetGlobalLogLevel(LogLevel level);
318 * @param[in] level - the highest log level.
319 * @param[in] trace - whether this filter allows tracing.
321 Filter(LogLevel level, bool trace)
322 : mLoggingLevel(level),
323 mTraceEnabled(trace),
328 static FilterList* GetActiveFilters();
331 // High level filters. If these filters are too broad for your current requirement, then
332 // you can add a filter to your own class or source file. If you do, use Filter::New()
333 // to tell this class about it.
335 static Filter* gRender;
336 static Filter* gResource;
337 static Filter* gGLResource;
338 static Filter* gObject;
339 static Filter* gImage;
340 static Filter* gModel;
341 static Filter* gNode;
342 static Filter* gElement;
343 static Filter* gActor;
344 static Filter* gShader;
347 LogLevel mLoggingLevel;
354 #define DALI_LOG_FILTER_SET_LEVEL(filter, level) filter->SetLogLevel(level)
355 #define DALI_LOG_FILTER_ENABLE_TRACE(filter) filter->EnableTrace()
356 #define DALI_LOG_FILTER_DISABLE_TRACE(filter) filter->DisableTrace()
360 #define DALI_LOG_FILTER_SET_LEVEL(filter, level)
361 #define DALI_LOG_FILTER_ENABLE_TRACE(filter)
362 #define DALI_LOG_FILTER_DISABLE_TRACE(filter)
366 /********************************************************************************
367 * General Logging macros *
368 ********************************************************************************/
372 #define DALI_LOG_INFO(filter, level, format, ...) \
373 if(filter && filter->IsEnabledFor(level)) \
376 (std::string(DALI_LOG_FORMAT_PREFIX) + std::string(format)).c_str(), \
377 DALI_LOG_FORMAT_PREFIX_ARGS, \
381 #define DALI_LOG_STREAM(filter, level, stream) \
382 if(filter && filter->IsEnabledFor(level)) \
384 std::ostringstream o; \
385 o << stream << std::endl; \
386 filter->Log(level, "%s", o.str().c_str()); \
389 #else // DEBUG_ENABLED
391 #define DALI_LOG_INFO(filter, level, format, ...)
392 #define DALI_LOG_STREAM(filter, level, stream)
394 #endif // DEBUG_ENABLED
396 /********************************************************************************
398 ********************************************************************************/
401 * These macros allow the instrumentation of methods. These translate into calls
402 * to LogMessage(INFO).
407 class DALI_CORE_API TraceObj
410 TraceObj(Filter* filter, const char* fmt, ...);
414 std::string mMessage;
418 #define DALI_LOG_TRACE_METHOD_FMT(filter, format, ...) \
419 Dali::Integration::Log::TraceObj debugTraceObj(filter, "%s: " format, ASSERT_LOCATION, ##__VA_ARGS__)
421 #define DALI_LOG_TRACE_METHOD(filter) \
422 Dali::Integration::Log::TraceObj debugTraceObj(filter, ASSERT_LOCATION)
424 #else // DEBUG_ENABLED
426 #define DALI_LOG_TRACE_METHOD_FMT(filter, format, ...)
427 #define DALI_LOG_TRACE_METHOD(filter)
431 /********************************************************************************
432 * Extra object debug *
433 ********************************************************************************/
438 * Warning, this macro changes the current scope, so should usually be put at the
439 * end of the class definition.
441 * Suggest that the value is usually set to the object's name.
442 * Warning - this will increase the size of the object for a debug build.
444 #define DALI_LOG_OBJECT_STRING_DECLARATION \
446 std::string mDebugString;
449 * Print all the actor tree names
451 #define DALI_LOG_ACTOR_TREE(node) \
453 std::stringstream branch; \
454 Node* tempNode = node; \
457 branch << "<" << tempNode->mDebugString << ">::"; \
458 tempNode = tempNode->GetParent(); \
460 DALI_LOG_ERROR_NOFN("Actor tree: %s\n", branch.str().c_str()); \
464 * Allows one object to set another object's debug string
466 #define DALI_LOG_SET_OBJECT_STRING(object, string) (object->mDebugString = string)
469 * Allows one object to set another object's std::string easily
471 #define DALI_LOG_FMT_OBJECT_STRING(object, fmt, ...) (object->mDebugString = FormatToString(fmt, ##__VA_ARGS__))
474 * Allows one object to get another object's debug string
476 #define DALI_LOG_GET_OBJECT_STRING(object) (object->mDebugString)
479 * Get the C string (for use in formatted logging)
481 #define DALI_LOG_GET_OBJECT_C_STR(object) (object->mDebugString.c_str())
484 * Filtered logging of the object's debug string
486 #define DALI_LOG_OBJECT(filter, object) DALI_LOG_INFO(filter, Debug::General, object->mDebugString)
488 #else // DEBUG_ENABLED
490 #define DALI_LOG_OBJECT_STRING_DECLARATION
491 #define DALI_LOG_ACTOR_TREE(node)
492 #define DALI_LOG_SET_OBJECT_STRING(object, string)
493 #define DALI_LOG_FMT_OBJECT_STRING(object, fmt, ...)
494 #define DALI_LOG_GET_OBJECT_STRING(object)
495 #define DALI_LOG_GET_OBJECT_C_STR(object) ""
496 #define DALI_LOG_OBJECT(filter, object)
500 /********************************************************************************
501 * Time instrumentation *
502 ********************************************************************************/
503 #if defined(DEBUG_ENABLED)
506 * @brief Get the monotonic time since the clock's epoch.
508 * @param[out] timeInNanoseconds The time in nanoseconds since the reference point.
510 * @note The maximum value timeInNanoseconds can hold is 0xFFFFFFFFFFFFFFFF which is 1.844674407e+19. Therefore, this can overflow after approximately 584 years.
512 void GetNanoseconds(uint64_t& timeInNanoseconds);
514 #define DALI_LOG_TIMER_START(timeVariable) \
515 uint64_t timeVariable##1; \
516 Debug::GetNanoseconds(timeVariable##1);
518 #define DALI_LOG_TIMER_END(timeVariable, filter, level, preString) \
519 uint64_t timeVariable##2; \
520 Debug::GetNanoseconds(timeVariable##2); \
521 DALI_LOG_INFO(filter, level, preString " %ld uSec\n", ((timeVariable##2 - timeVariable##1) / 1000));
523 #else // DEBUG_ENABLED
525 #define DALI_LOG_TIMER_START(timeVariable)
526 #define DALI_LOG_TIMER_END(timeVariable, filter, level, preString)
531 } // namespace Integration
534 #endif // DALI_INTEGRATION_DEBUG_H