Merge "Clean up the code to build successfully on macOS" into devel/master
[platform/core/uifw/dali-core.git] / dali / integration-api / debug.cpp
1 /*
2  * Copyright (c) 2020 Samsung Electronics Co., Ltd.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  *
16  */
17
18 // CLASS HEADER
19 #include <dali/integration-api/debug.h>
20
21 // EXTERNAL INCLUDES
22 #include <chrono>
23 #include <cstdarg>
24
25 namespace Dali
26 {
27 #ifdef DEBUG_ENABLED
28
29 // Fake globals for gdb typedefs
30 Dali::DebugPropertyValueArray gValueArray;
31 Dali::DebugPropertyValueMap   gValueMap;
32
33 #endif
34
35 namespace Integration
36 {
37 namespace Log
38 {
39 thread_local LogFunction gthreadLocalLogFunction = nullptr;
40
41 /* Forward declarations */
42 std::string FormatToString(const char* format, ...);
43 std::string ArgListToString(const char* format, va_list args);
44
45 void LogMessage(DebugPriority priority, const char* format, ...)
46 {
47   if(!gthreadLocalLogFunction)
48   {
49     return;
50   }
51
52   va_list arg;
53   va_start(arg, format);
54   std::string message = ArgListToString(format, arg);
55   va_end(arg);
56
57   gthreadLocalLogFunction(priority, message);
58 }
59
60 void InstallLogFunction(const LogFunction& logFunction)
61 {
62   // TLS stores a pointer to an object.
63   // It needs to be allocated on the heap, because TLS will destroy it when the thread exits.
64
65   gthreadLocalLogFunction = logFunction;
66 }
67
68 void UninstallLogFunction()
69 {
70   gthreadLocalLogFunction = nullptr;
71 }
72
73 #ifdef DEBUG_ENABLED
74
75 /*Change false to true if trace is needed but don't commit to codeline*/
76 Filter* Filter::gRender     = Filter::New(Debug::Concise, false, "LOG_RENDER");
77 Filter* Filter::gResource   = Filter::New(Debug::Concise, false, "LOG_RESOURCE");
78 Filter* Filter::gGLResource = Filter::New(Debug::Concise, false, "LOG_GL_RESOURCE");
79 Filter* Filter::gObject     = nullptr;
80 Filter* Filter::gImage      = Filter::New(Debug::Concise, false, "LOG_IMAGE");
81 Filter* Filter::gModel      = Filter::New(Debug::Concise, false, "LOG_MODEL");
82 Filter* Filter::gNode       = nullptr;
83 Filter* Filter::gElement    = nullptr;
84 Filter* Filter::gActor      = Filter::New(Debug::Concise, false, "LOG_ACTOR");
85 Filter* Filter::gShader     = Filter::New(Debug::Concise, false, "LOG_SHADER");
86
87 Filter::FilterList* Filter::GetActiveFilters()
88 {
89   static Filter::FilterList* activeFilters = new FilterList;
90   return activeFilters;
91 }
92
93 Filter* Filter::New(LogLevel level, bool trace, const char* environmentVariableName)
94 {
95   char* environmentVariableValue = getenv(environmentVariableName);
96   if(environmentVariableValue)
97   {
98     unsigned int envLevel(0);
99     char         envTraceString(0);
100     sscanf(environmentVariableValue, "%u,%c", &envLevel, &envTraceString);
101
102     if(envLevel > Verbose)
103     {
104       envLevel = Verbose;
105     }
106     level = LogLevel(envLevel);
107
108     // Just use 'f' and 't' as it's faster than doing full string comparisons
109     if(envTraceString == 't')
110     {
111       trace = true;
112     }
113     else if(envTraceString == 'f')
114     {
115       trace = false;
116     }
117   }
118
119   Filter* filter = new Filter(level, trace);
120   filter->mNesting++;
121   GetActiveFilters()->push_back(filter);
122   return filter;
123 }
124
125 /**
126  * Enable trace on all filters.
127  */
128 void Filter::EnableGlobalTrace()
129 {
130   for(FilterIter iter = GetActiveFilters()->begin(); iter != GetActiveFilters()->end(); iter++)
131   {
132     (*iter)->EnableTrace();
133   }
134 }
135
136 /**
137  * Disable trace on all filters.
138  */
139 void Filter::DisableGlobalTrace()
140 {
141   for(FilterIter iter = GetActiveFilters()->begin(); iter != GetActiveFilters()->end(); iter++)
142   {
143     (*iter)->DisableTrace();
144   }
145 }
146
147 void Filter::SetGlobalLogLevel(LogLevel level)
148 {
149   for(FilterIter iter = GetActiveFilters()->begin(); iter != GetActiveFilters()->end(); iter++)
150   {
151     (*iter)->SetLogLevel(level);
152   }
153 }
154
155 void Filter::Log(LogLevel level, const char* format, ...)
156 {
157   if(level <= mLoggingLevel)
158   {
159     va_list arg;
160     va_start(arg, format);
161
162     if(mTraceEnabled)
163     {
164       char* buffer   = nullptr;
165       int   numChars = asprintf(&buffer, "    %-*c %s", mNesting, ':', format);
166       if(numChars >= 0) // No error
167       {
168         std::string message = ArgListToString(buffer, arg);
169         LogMessage(DebugInfo, message.c_str());
170         free(buffer);
171       }
172     }
173     else
174     {
175       std::string message = ArgListToString(format, arg);
176       LogMessage(DebugInfo, message.c_str());
177     }
178     va_end(arg);
179   }
180 }
181
182 TraceObj::TraceObj(Filter* filter, const char* format, ...)
183 : mFilter(filter)
184 {
185   if(mFilter && mFilter->IsTraceEnabled())
186   {
187     va_list arg;
188     va_start(arg, format);
189     mMessage = ArgListToString(format, arg);
190     va_end(arg);
191
192     LogMessage(DebugInfo, "Entr%-*c %s\n", mFilter->mNesting, ':', mMessage.c_str());
193     ++mFilter->mNesting;
194   }
195 }
196
197 TraceObj::~TraceObj()
198 {
199   if(mFilter && mFilter->IsTraceEnabled())
200   {
201     if(mFilter->mNesting)
202     {
203       --mFilter->mNesting;
204     }
205     LogMessage(DebugInfo, "Exit%-*c %s\n", mFilter->mNesting, ':', mMessage.c_str());
206   }
207 }
208
209 #endif // DEBUG_ENABLED
210
211 std::string ArgListToString(const char* format, va_list args)
212 {
213   std::string str; // empty string
214   if(format != nullptr)
215   {
216     char* buffer = nullptr;
217     int   err    = vasprintf(&buffer, format, args);
218     if(err >= 0) // No error
219     {
220       str = buffer;
221       free(buffer);
222     }
223   }
224   return str;
225 }
226
227 std::string FormatToString(const char* format, ...)
228 {
229   va_list arg;
230   va_start(arg, format);
231   std::string s = ArgListToString(format, arg);
232   va_end(arg);
233   return s;
234 }
235
236 #ifdef DEBUG_ENABLED
237
238 void GetNanoseconds(uint64_t& timeInNanoseconds)
239 {
240   // Get the time of a monotonic clock since its epoch.
241   auto epoch = std::chrono::steady_clock::now().time_since_epoch();
242
243   auto duration = std::chrono::duration_cast<std::chrono::nanoseconds>(epoch);
244
245   timeInNanoseconds = static_cast<uint64_t>(duration.count());
246 }
247
248 #endif // DEBUG_ENABLED
249
250 } // namespace Log
251
252 } // namespace Integration
253
254 } // namespace Dali