2 * Copyright (c) 2024 Samsung Electronics Co., Ltd.
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
19 #include <dali/integration-api/debug.h>
30 // Fake globals for gdb typedefs
31 Dali::DebugPropertyValueArray gValueArray;
32 Dali::DebugPropertyValueMap gValueMap;
42 void FormatPrintToStandardOutput(DebugPriority priority, const char* format, va_list args)
46 char* buffer = nullptr;
47 int bufferLength = vasprintf(&buffer, format, args); // Development note : bufferLength doesn't include null-terminated character.
49 if(bufferLength >= 0) // No error
51 // TODO : We need to consider thread-safety way to print something.
54 case DebugPriority::DEBUG:
55 case DebugPriority::INFO:
57 fprintf(stdout, "%.*s", bufferLength, buffer);
60 case DebugPriority::WARNING:
61 case DebugPriority::ERROR:
64 fprintf(stderr, "%.*s", bufferLength, buffer);
73 thread_local LogFunction gthreadLocalLogFunction = nullptr;
75 /* Forward declarations */
76 std::string FormatToString(const char* format, ...);
77 std::string ArgListToString(const char* format, va_list args);
79 void LogMessage(DebugPriority priority, const char* format, ...)
81 if(DALI_UNLIKELY(!gthreadLocalLogFunction))
84 va_start(arg, format);
85 FormatPrintToStandardOutput(priority, format, arg);
91 va_start(arg, format);
92 std::string message = ArgListToString(format, arg);
95 gthreadLocalLogFunction(priority, message);
99 void InstallLogFunction(const LogFunction& logFunction)
101 // TLS stores a pointer to an object.
102 // It needs to be allocated on the heap, because TLS will destroy it when the thread exits.
104 gthreadLocalLogFunction = logFunction;
107 void UninstallLogFunction()
109 gthreadLocalLogFunction = nullptr;
114 /*Change false to true if trace is needed but don't commit to codeline*/
115 Filter* Filter::gRender = Filter::New(Debug::Concise, false, "LOG_RENDER");
116 Filter* Filter::gResource = Filter::New(Debug::Concise, false, "LOG_RESOURCE");
117 Filter* Filter::gGLResource = Filter::New(Debug::Concise, false, "LOG_GL_RESOURCE");
118 Filter* Filter::gObject = nullptr;
119 Filter* Filter::gImage = Filter::New(Debug::Concise, false, "LOG_IMAGE");
120 Filter* Filter::gModel = Filter::New(Debug::Concise, false, "LOG_MODEL");
121 Filter* Filter::gNode = nullptr;
122 Filter* Filter::gElement = nullptr;
123 Filter* Filter::gActor = Filter::New(Debug::Concise, false, "LOG_ACTOR");
124 Filter* Filter::gShader = Filter::New(Debug::Concise, false, "LOG_SHADER");
126 typedef std::list<std::unique_ptr<Filter>> FilterList;
127 typedef std::list<std::unique_ptr<Filter>>::iterator FilterIter;
131 static FilterList& GetActiveFilters()
133 static FilterList activeFilters;
134 return activeFilters;
138 Filter* Filter::New(LogLevel level, bool trace, const char* environmentVariableName)
140 char* environmentVariableValue = getenv(environmentVariableName);
141 if(environmentVariableValue)
143 unsigned int envLevel(0);
144 char envTraceString(0);
145 sscanf(environmentVariableValue, "%u,%c", &envLevel, &envTraceString);
147 if(envLevel > Verbose)
151 level = LogLevel(envLevel);
153 // Just use 'f' and 't' as it's faster than doing full string comparisons
154 if(envTraceString == 't')
158 else if(envTraceString == 'f')
164 Filter* filter = new Filter(level, trace);
166 GetActiveFilters().push_back(std::unique_ptr<Filter>(filter));
171 * Enable trace on all filters.
173 void Filter::EnableGlobalTrace()
175 for(FilterIter iter = GetActiveFilters().begin(); iter != GetActiveFilters().end(); iter++)
177 (*iter)->EnableTrace();
182 * Disable trace on all filters.
184 void Filter::DisableGlobalTrace()
186 for(FilterIter iter = GetActiveFilters().begin(); iter != GetActiveFilters().end(); iter++)
188 (*iter)->DisableTrace();
192 void Filter::SetGlobalLogLevel(LogLevel level)
194 for(FilterIter iter = GetActiveFilters().begin(); iter != GetActiveFilters().end(); iter++)
196 (*iter)->SetLogLevel(level);
200 void Filter::Log(LogLevel level, const char* format, ...)
202 if(level <= mLoggingLevel)
205 va_start(arg, format);
209 char* buffer = nullptr;
210 int numChars = asprintf(&buffer, " %-*c %s", mNesting, ':', format);
211 if(numChars >= 0) // No error
213 std::string message = ArgListToString(buffer, arg);
214 LogMessage(INFO, message.c_str());
220 std::string message = ArgListToString(format, arg);
221 LogMessage(INFO, message.c_str());
227 TraceObj::TraceObj(Filter* filter, const char* format, ...)
230 if(mFilter && mFilter->IsTraceEnabled())
233 va_start(arg, format);
234 mMessage = ArgListToString(format, arg);
237 LogMessage(INFO, "Entr%-*c %s\n", mFilter->mNesting, ':', mMessage.c_str());
242 TraceObj::~TraceObj()
244 if(mFilter && mFilter->IsTraceEnabled())
246 if(mFilter->mNesting)
250 LogMessage(INFO, "Exit%-*c %s\n", mFilter->mNesting, ':', mMessage.c_str());
254 #endif // DEBUG_ENABLED
256 std::string ArgListToString(const char* format, va_list args)
258 std::string str; // empty string
259 if(format != nullptr)
261 char* buffer = nullptr;
262 int err = vasprintf(&buffer, format, args);
263 if(err >= 0) // No error
272 std::string FormatToString(const char* format, ...)
275 va_start(arg, format);
276 std::string s = ArgListToString(format, arg);
283 void GetNanoseconds(uint64_t& timeInNanoseconds)
285 // Get the time of a monotonic clock since its epoch.
286 auto epoch = std::chrono::steady_clock::now().time_since_epoch();
288 auto duration = std::chrono::duration_cast<std::chrono::nanoseconds>(epoch);
290 timeInNanoseconds = static_cast<uint64_t>(duration.count());
293 #endif // DEBUG_ENABLED
297 } // namespace Integration