Fix LogMessage format to print Filename / Functioname / Line
[platform/core/uifw/dali-core.git] / dali / integration-api / debug.h
1 #ifndef DALI_INTEGRATION_DEBUG_H
2 #define DALI_INTEGRATION_DEBUG_H
3
4 /*
5  * Copyright (c) 2021 Samsung Electronics Co., Ltd.
6  *
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
10  *
11  * http://www.apache.org/licenses/LICENSE-2.0
12  *
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.
18  *
19  */
20
21 // EXTERNAL INCLUDES
22 #include <stdint.h>
23 #include <iostream>
24 #include <list>
25 #include <sstream>
26 #include <string>
27 #include <cstring>
28
29 #include <dali/public-api/common/vector-wrapper.h>
30 #include <dali/public-api/object/property-map.h>
31
32 // INTERNAL INCLUDES
33 #include <dali/public-api/common/dali-common.h>
34
35 // Using Debug namespace alias shortens the log usage significantly
36 namespace Dali
37 {
38 namespace Integration
39 {
40 namespace Log
41 {
42 }
43 } // namespace Integration
44 } // namespace Dali
45 namespace Debug = Dali::Integration::Log;
46
47 namespace Dali
48 {
49 struct Vector2;
50 struct Vector3;
51 struct Vector4;
52 class Matrix3;
53 class Matrix;
54 class Quaternion;
55
56 #if defined(DEBUG_ENABLED)
57
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>;
63
64 struct DebugPropertyValueMap
65 {
66   DebugStringValueContainer stringValues;
67   DebugIndexValueContainer  intValues;
68 };
69
70 // Fake globals for gdb typedefs
71 extern Dali::DebugPropertyValueArray gValueArray;
72 extern Dali::DebugPropertyValueMap   gValueMap;
73
74 #endif
75
76 namespace Integration
77 {
78 namespace Log
79 {
80 enum DebugPriority
81 {
82   DebugInfo,
83   DebugWarning,
84   DebugError
85 };
86
87 /**
88  * Used by logging macros to log a message
89  * @param level debug level
90  * @param format string format
91  */
92 DALI_CORE_API void LogMessage(enum DebugPriority level, const char* format, ...);
93
94 /**
95  * Prefix macros to sync with dlog logger format
96  * __MODULE__ macro also defined at dlog-internal.h
97  */
98 #ifndef DALI_LOG_FORMAT_PREFIX
99 #ifndef __MODULE__
100 #define __MODULE__ (std::strrchr(__FILE__, '/') ? std::strrchr(__FILE__, '/') + 1 : __FILE__)
101 #endif
102 #define DALI_LOG_FORMAT_PREFIX "%s: %s(%d) > "
103 #define DALI_LOG_FORMAT_PREFIX_ARGS __MODULE__,__func__,__LINE__
104 #endif
105
106 /**
107  * Global logging macros to log a message along with function/class name and line
108  * @param level debug level
109  * @param format string format
110  */
111 #define LogMessageWithFunctionLine(level, format, ...)                 \
112   LogMessage(level,                                                    \
113   (std::string(DALI_LOG_FORMAT_PREFIX) + std::string(format)).c_str(), \
114   DALI_LOG_FORMAT_PREFIX_ARGS,                                         \
115   ##__VA_ARGS__)
116
117 /**
118  * typedef for the logging function.
119  */
120 using LogFunction = void (*)(DebugPriority, std::string&);
121
122 /**
123  * A log function has to be installed for every thread that wants to use logging.
124  * This should be done by the adaptor.
125  * The log function can be different for each thread.
126  * @param logFunction the log function to install
127  * @param logOpts the log options to save in thread
128  */
129 DALI_CORE_API void InstallLogFunction(const LogFunction& logFunction);
130
131 /**
132  * A log function has to be uninstalled for every thread that wants to use logging.
133  * The log function can be different for each thread.
134  */
135 DALI_CORE_API void UninstallLogFunction();
136
137 /********************************************************************************
138  *                            Error/Warning  macros.                            *
139  ********************************************************************************/
140
141 /**
142  * Provides unfiltered logging for global error level messages
143  */
144 #define DALI_LOG_ERROR(format, ...) Dali::Integration::Log::LogMessageWithFunctionLine(Dali::Integration::Log::DebugError, format, ##__VA_ARGS__)
145
146 #define DALI_LOG_ERROR_NOFN(format, ...) Dali::Integration::Log::LogMessage(Dali::Integration::Log::DebugError, format, ##__VA_ARGS__)
147
148 #define DALI_LOG_WARNING_NOFN(format, ...) Dali::Integration::Log::LogMessage(Dali::Integration::Log::DebugWarning, format, ##__VA_ARGS__)
149
150 /**
151  * Provides unfiltered logging for fps monitor
152  */
153 #define DALI_LOG_FPS(format, ...) Dali::Integration::Log::LogMessage(Dali::Integration::Log::DebugInfo, format, ##__VA_ARGS__)
154
155 /**
156  * Provides unfiltered logging for update status
157  */
158 #define DALI_LOG_UPDATE_STATUS(format, ...) Dali::Integration::Log::LogMessage(Dali::Integration::Log::DebugInfo, format, ##__VA_ARGS__)
159
160 /**
161  * Provides unfiltered logging for render information
162  */
163 #define DALI_LOG_RENDER_INFO(format, ...) Dali::Integration::Log::LogMessage(Dali::Integration::Log::DebugInfo, format, ##__VA_ARGS__)
164
165 /**
166  * Provides unfiltered logging for release
167  */
168 #define DALI_LOG_RELEASE_INFO(format, ...) Dali::Integration::Log::LogMessageWithFunctionLine(Dali::Integration::Log::DebugInfo, format, ##__VA_ARGS__)
169
170 #ifdef DEBUG_ENABLED
171
172 /**
173  * Provides unfiltered logging for global warning level messages
174  */
175 #define DALI_LOG_WARNING(format, ...) Dali::Integration::Log::LogMessageWithFunctionLine(Dali::Integration::Log::DebugWarning, "%s " format, ASSERT_LOCATION, ##__VA_ARGS__)
176
177 #else // DEBUG_ENABLED
178
179 // Don't warn on release build
180 #define DALI_LOG_WARNING(format, ...)
181
182 #endif
183
184 /********************************************************************************
185  *                                    Filter                                    *
186  ********************************************************************************/
187
188 #ifdef DEBUG_ENABLED
189
190 /**
191  * Enumeration of logging levels.
192  * Used by the filters to provide multiple log levels.
193  * In general, the higher the value, the more debug is available for that filter.
194  */
195 enum LogLevel
196 {
197   NoLogging = 0,
198   Concise   = 1,
199   General   = 2,
200   Verbose   = 3
201 };
202
203 /**
204  * The Filter object is used by the DALI_LOG_INFO macro and others to determine if the logging
205  * should take place, and routes the logging via the platform abstraction's LogMessage.
206  *
207  * It provides a logging level. If this is set to zero, then DALI_LOG_INFO won't log anything.
208  * It provides the ability to turn tracing on or off.
209  *
210  */
211 class DALI_CORE_API Filter
212 {
213 public:
214   using FilterList = std::list<Filter*>;
215   using FilterIter = std::list<Filter*>::iterator;
216
217 public:
218   /**
219    * Test if the filter is enabled for the given logging level
220    * @param[in] level - the level to test.
221    * @return true if this level of logging is enabled.
222    */
223   bool IsEnabledFor(LogLevel level)
224   {
225     return level != Debug::NoLogging && level <= mLoggingLevel;
226   }
227
228   /**
229    * Test if trace is enabled for this filter.
230    * @return true if trace is enabled;
231    */
232   bool IsTraceEnabled()
233   {
234     return mTraceEnabled;
235   }
236
237   /**
238    * Enable tracing on this filter.
239    */
240   void EnableTrace()
241   {
242     mTraceEnabled = true;
243   }
244
245   /**
246    * Disable tracing on this filter.
247    */
248   void DisableTrace()
249   {
250     mTraceEnabled = false;
251   }
252
253   /**
254    * Set the log level for this filter. Setting to a higher value than Debug::General also
255    * enables General;
256    */
257   void SetLogLevel(LogLevel level)
258   {
259     mLoggingLevel = level;
260   }
261
262   /**
263    * Perform the logging for this filter.
264    */
265   void Log(LogLevel level, const char* format, ...);
266
267   /**
268    * Create a new filter whose debug level and trace can be modified through the use of an
269    * environment variable.
270    *
271    * @param[in] level The default log level
272    * @param[in] trace The default trace level. If true, function tracing is on.
273    * @param[in] environmentVariableName The environment variable name used in order to change the
274    *                                    log level or trace.
275    *
276    * @info To modify logg level/trace at runtime, you can should define your filter as shown below:
277    *
278    * @code
279    * Debug::Filter* filter = Debug::Filter::New( Debug::NoLogging, false, "FILTER_ENV" );
280    * @endcode
281    *
282    * And to use it when running an executable:
283    * @code
284    * FILTER_ENV=3 dali-demo        // LogLevel Verbose,   Trace using default
285    * FILTER_ENV=1,true dali-demo   // LogLevel Concise,   Trace ON
286    * FILTER_ENV=2,false dali-demo  // LogLevel General,   Trace OFF
287    * FILTER_ENV=0,true dali-demo   // LogLevel NoLogging, Trace ON
288    * @endcode
289    */
290   static Filter* New(LogLevel level, bool trace, const char* environmentVariableName);
291
292   /**
293    * Enable trace on all filters.
294    */
295   static void EnableGlobalTrace();
296
297   /**
298    * Disable trace on all filters.
299    */
300   static void DisableGlobalTrace();
301
302   /**
303    * Set log level for all filters.
304    *
305    * @param[in] level The log level
306    */
307   static void SetGlobalLogLevel(LogLevel level);
308
309 private:
310   /**
311    * Constructor.
312    * @param[in] level - the highest log level.
313    * @param[in] trace - whether this filter allows tracing.
314    */
315   Filter(LogLevel level, bool trace)
316   : mLoggingLevel(level),
317     mTraceEnabled(trace),
318     mNesting(0)
319   {
320   }
321
322   static FilterList* GetActiveFilters();
323
324 public:
325   // High level filters. If these filters are too broad for your current requirement, then
326   // you can add a filter to your own class or source file. If you do, use Filter::New()
327   // to tell this class about it.
328
329   static Filter* gRender;
330   static Filter* gResource;
331   static Filter* gGLResource;
332   static Filter* gObject;
333   static Filter* gImage;
334   static Filter* gModel;
335   static Filter* gNode;
336   static Filter* gElement;
337   static Filter* gActor;
338   static Filter* gShader;
339
340 private:
341   LogLevel mLoggingLevel;
342   bool     mTraceEnabled;
343
344 public:
345   int mNesting;
346 };
347
348 #define DALI_LOG_FILTER_SET_LEVEL(filter, level) filter->SetLogLevel(level)
349 #define DALI_LOG_FILTER_ENABLE_TRACE(filter) filter->EnableTrace()
350 #define DALI_LOG_FILTER_DISABLE_TRACE(filter) filter->DisableTrace()
351
352 #else
353
354 #define DALI_LOG_FILTER_SET_LEVEL(filter, level)
355 #define DALI_LOG_FILTER_ENABLE_TRACE(filter)
356 #define DALI_LOG_FILTER_DISABLE_TRACE(filter)
357
358 #endif
359
360 /********************************************************************************
361  *                            General Logging macros                            *
362  ********************************************************************************/
363
364 #ifdef DEBUG_ENABLED
365
366 #define DALI_LOG_INFO(filter, level, format, ...)                        \
367   if(filter && filter->IsEnabledFor(level))                              \
368   {                                                                      \
369     filter->Log(level,                                                   \
370     (std::string(DALI_LOG_FORMAT_PREFIX) + std::string(format)).c_str(), \
371     DALI_LOG_FORMAT_PREFIX_ARGS,                                         \
372     ##__VA_ARGS__);                                                      \
373   }
374
375 #define DALI_LOG_STREAM(filter, level, stream) \
376   if(filter && filter->IsEnabledFor(level))    \
377   {                                            \
378     std::ostringstream o;                      \
379     o << stream << std::endl;                  \
380     filter->Log(level, "%s", o.str().c_str()); \
381   }
382
383 #else // DEBUG_ENABLED
384
385 #define DALI_LOG_INFO(filter, level, format, ...)
386 #define DALI_LOG_STREAM(filter, level, stream)
387
388 #endif // DEBUG_ENABLED
389
390 /********************************************************************************
391  *                                  Trace Macros                                *
392  ********************************************************************************/
393
394 /*
395  * These macros allow the instrumentation of methods. These translate into calls
396  * to LogMessage(DebugInfo).
397  */
398
399 #ifdef DEBUG_ENABLED
400
401 class DALI_CORE_API TraceObj
402 {
403 public:
404   TraceObj(Filter* filter, const char* fmt, ...);
405   ~TraceObj();
406
407 public:
408   std::string mMessage;
409   Filter*     mFilter;
410 };
411
412 #define DALI_LOG_TRACE_METHOD_FMT(filter, format, ...) \
413   Dali::Integration::Log::TraceObj debugTraceObj(filter, "%s: " format, ASSERT_LOCATION, ##__VA_ARGS__)
414
415 #define DALI_LOG_TRACE_METHOD(filter) \
416   Dali::Integration::Log::TraceObj debugTraceObj(filter, ASSERT_LOCATION)
417
418 #else // DEBUG_ENABLED
419
420 #define DALI_LOG_TRACE_METHOD_FMT(filter, format, ...)
421 #define DALI_LOG_TRACE_METHOD(filter)
422
423 #endif
424
425 /********************************************************************************
426  *                              Extra object debug                              *
427  ********************************************************************************/
428
429 #ifdef DEBUG_ENABLED
430
431 /**
432  * Warning, this macro changes the current scope, so should usually be put at the
433  * end of the class definition.
434  *
435  * Suggest that the value is usually set to the object's name.
436  * Warning - this will increase the size of the object for a debug build.
437  */
438 #define DALI_LOG_OBJECT_STRING_DECLARATION \
439 public:                                    \
440   std::string mDebugString;
441
442 /**
443  * Print all the actor tree names
444  **/
445 #define DALI_LOG_ACTOR_TREE(node)                                  \
446   {                                                                \
447     std::stringstream branch;                                      \
448     Node*             tempNode = node;                             \
449     while(tempNode)                                                \
450     {                                                              \
451       branch << "<" << tempNode->mDebugString << ">::";            \
452       tempNode = tempNode->GetParent();                            \
453     }                                                              \
454     DALI_LOG_ERROR_NOFN("Actor tree: %s\n", branch.str().c_str()); \
455   }
456
457 /**
458  * Allows one object to set another object's debug string
459  */
460 #define DALI_LOG_SET_OBJECT_STRING(object, string) (object->mDebugString = string)
461
462 /**
463  * Allows one object to set another object's std::string easily
464  */
465 #define DALI_LOG_FMT_OBJECT_STRING(object, fmt, ...) (object->mDebugString = FormatToString(fmt, ##__VA_ARGS__))
466
467 /**
468  * Allows one object to get another object's debug string
469  */
470 #define DALI_LOG_GET_OBJECT_STRING(object) (object->mDebugString)
471
472 /**
473  * Get the C string (for use in formatted logging)
474  */
475 #define DALI_LOG_GET_OBJECT_C_STR(object) (object->mDebugString.c_str())
476
477 /**
478  * Filtered logging of the object's debug string
479  */
480 #define DALI_LOG_OBJECT(filter, object) DALI_LOG_INFO(filter, Debug::General, object->mDebugString)
481
482 #else // DEBUG_ENABLED
483
484 #define DALI_LOG_OBJECT_STRING_DECLARATION
485 #define DALI_LOG_ACTOR_TREE(node)
486 #define DALI_LOG_SET_OBJECT_STRING(object, string)
487 #define DALI_LOG_FMT_OBJECT_STRING(object, fmt, ...)
488 #define DALI_LOG_GET_OBJECT_STRING(object)
489 #define DALI_LOG_GET_OBJECT_C_STR(object) ""
490 #define DALI_LOG_OBJECT(filter, object)
491
492 #endif
493
494 /********************************************************************************
495  *                            Time instrumentation                              *
496  ********************************************************************************/
497 #if defined(DEBUG_ENABLED)
498
499 /**
500   * @brief Get the monotonic time since the clock's epoch.
501   *
502   * @param[out]  timeInNanoseconds  The time in nanoseconds since the reference point.
503   *
504   * @note The maximum value timeInNanoseconds can hold is 0xFFFFFFFFFFFFFFFF which is 1.844674407e+19. Therefore, this can overflow after approximately 584 years.
505   */
506 void GetNanoseconds(uint64_t& timeInNanoseconds);
507
508 #define DALI_LOG_TIMER_START(timeVariable) \
509   uint64_t timeVariable##1;                \
510   Debug::GetNanoseconds(timeVariable##1);
511
512 #define DALI_LOG_TIMER_END(timeVariable, filter, level, preString) \
513   uint64_t timeVariable##2;                                        \
514   Debug::GetNanoseconds(timeVariable##2);                          \
515   DALI_LOG_INFO(filter, level, preString " %ld uSec\n", ((timeVariable##2 - timeVariable##1) / 1000));
516
517 #else // DEBUG_ENABLED
518
519 #define DALI_LOG_TIMER_START(timeVariable)
520 #define DALI_LOG_TIMER_END(timeVariable, filter, level, preString)
521
522 #endif
523
524 } // namespace Log
525 } // namespace Integration
526 } // namespace Dali
527
528 #endif // DALI_INTEGRATION_DEBUG_H