1 /*
2 * Copyright (c) 2023 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include "texgine/utils/logger.h"
17
18 #include <fstream>
19 #include <iomanip>
20 #include <iostream>
21 #include <unistd.h>
22
23 #ifdef BUILD_NON_SDK_VER
24 #include <sys/syscall.h>
25 #define GET_TID() syscall(__NR_gettid)
26 #else
27 #ifdef _WIN32
28 #include <windows.h>
29 #define GET_TID GetCurrentThreadId
30 #endif
31
32 #if defined(BUILD_SDK_MAC) || defined(BUILD_SDK_IOS)
33 #include <stdlib.h>
34 #include <sys/syscall.h>
35 #define GET_TID() syscall(SYS_thread_selfid)
36 #elif defined(BUILD_SDK_ANDROID)
37 #define GET_TID() gettid()
38 #else
39 #ifdef __gnu_linux__
40 #include <sys/types.h>
41 #include <sys/syscall.h>
42 #define GET_TID() syscall(SYS_gettid)
43 #endif
44 #endif
45
46 #ifdef __APPLE__
47 #define getpid getpid
48 #endif
49
50 #ifdef ERROR
51 #undef ERROR
52 #endif
53 #endif
54
55 #ifdef LOGGER_NO_COLOR
56 #define IF_COLOR(x)
57 #else
58 #define IF_COLOR(x) x
59 #endif
60
61 namespace OHOS {
62 namespace Rosen {
63 namespace TextEngine {
64 namespace {
GetLevelStr(enum Logger::LOG_LEVEL level)65 const char *GetLevelStr(enum Logger::LOG_LEVEL level)
66 {
67 switch (level) {
68 case Logger::LOG_LEVEL::DEBUG:
69 return IF_COLOR("\033[37m") "D" IF_COLOR("\033[0m");
70 case Logger::LOG_LEVEL::INFO:
71 return IF_COLOR("\033[36m") "I" IF_COLOR("\033[0m");
72 case Logger::LOG_LEVEL::WARN:
73 return IF_COLOR("\033[33m") "W" IF_COLOR("\033[0m");
74 case Logger::LOG_LEVEL::ERROR:
75 return IF_COLOR("\033[31m") "E" IF_COLOR("\033[0m");
76 case Logger::LOG_LEVEL::FATAL:
77 return IF_COLOR("\033[4;31m") "F" IF_COLOR("\033[0m");
78 }
79 return "?";
80 }
81 } // namespace
82
SetToNoReturn(Logger & logger,enum LOG_PHASE phase)83 void Logger::SetToNoReturn(Logger &logger, enum LOG_PHASE phase)
84 {
85 logger.return_ = false;
86 }
87
SetToContinue(Logger & logger,enum LOG_PHASE phase)88 void Logger::SetToContinue(Logger &logger, enum LOG_PHASE phase)
89 {
90 logger.continue_ = true;
91 }
92
OutputByStdout(Logger & logger,enum LOG_PHASE phase)93 void Logger::OutputByStdout(Logger &logger, enum LOG_PHASE phase)
94 {
95 if (phase == LOG_PHASE::BEGIN) {
96 return;
97 }
98
99 // LOG_PHASE::END
100 if (logger.continue_ == false) {
101 std::cout << GetLevelStr(logger.GetLevel()) << " ";
102 }
103
104 std::cout << logger.str();
105 if (logger.return_) {
106 std::cout << std::endl;
107 }
108 }
109
OutputByStderr(Logger & logger,enum LOG_PHASE phase)110 void Logger::OutputByStderr(Logger &logger, enum LOG_PHASE phase)
111 {
112 if (phase == LOG_PHASE::BEGIN) {
113 return;
114 }
115
116 // LOG_PHASE::END
117 if (logger.continue_ == false) {
118 std::cerr << GetLevelStr(logger.GetLevel()) << " ";
119 }
120
121 std::cerr << logger.str();
122 if (logger.return_) {
123 std::cerr << std::endl;
124 }
125 }
126
OutputByFileLog(Logger & logger,enum LOG_PHASE phase)127 void Logger::OutputByFileLog(Logger &logger, enum LOG_PHASE phase)
128 {
129 struct FileLogData {
130 const char *filename;
131 };
132 auto data = logger.GetData<struct FileLogData>();
133 if (phase == LOG_PHASE::BEGIN) {
134 auto filename = va_arg(logger.GetVariousArgument(), const char *);
135 data->filename = filename;
136 return;
137 }
138
139 // LOG_PHASE::END
140 std::ofstream ofs(data->filename, std::ofstream::out | std::ofstream::app);
141 if (!ofs) {
142 // open failed, errno
143 return;
144 }
145
146 if (logger.continue_ == false) {
147 ofs << GetLevelStr(logger.GetLevel()) << " ";
148 }
149
150 ofs << logger.str();
151 if (logger.return_) {
152 ofs << std::endl;
153 }
154 ofs.close();
155 }
156
AppendFunc(Logger & logger,enum LOG_PHASE phase)157 void Logger::AppendFunc(Logger &logger, enum LOG_PHASE phase)
158 {
159 if (phase == LOG_PHASE::BEGIN) {
160 logger << IF_COLOR("\033[34m");
161 logger.AlignFunc();
162 logger << logger.GetFunc() << IF_COLOR("\033[0m") " ";
163 }
164 }
165
AppendFuncLine(Logger & logger,enum LOG_PHASE phase)166 void Logger::AppendFuncLine(Logger &logger, enum LOG_PHASE phase)
167 {
168 if (phase == LOG_PHASE::BEGIN) {
169 logger << IF_COLOR("\033[34m");
170 logger.AlignFunc();
171 logger << logger.GetFunc() << " ";
172 logger.AlignLine();
173 logger << IF_COLOR("\033[35m") "+" << logger.GetLine() << IF_COLOR("\033[0m") " ";
174 }
175 }
176
AppendFileLine(Logger & logger,enum LOG_PHASE phase)177 void Logger::AppendFileLine(Logger &logger, enum LOG_PHASE phase)
178 {
179 if (phase == LOG_PHASE::BEGIN) {
180 logger << IF_COLOR("\033[34m") << logger.GetFile() << " ";
181 logger.AlignLine();
182 logger << IF_COLOR("\033[35m") "+" << logger.GetLine() << IF_COLOR("\033[0m") " ";
183 }
184 }
185
AppendFileFuncLine(Logger & logger,enum LOG_PHASE phase)186 void Logger::AppendFileFuncLine(Logger &logger, enum LOG_PHASE phase)
187 {
188 if (phase == LOG_PHASE::BEGIN) {
189 logger << IF_COLOR("\033[34m") << logger.GetFile() << " ";
190 logger.AlignLine();
191 logger << IF_COLOR("\033[35m") "+" << logger.GetLine() << " ";
192 logger.AlignFunc();
193 logger << logger.GetFunc() << IF_COLOR("\033[0m") " ";
194 }
195 }
196
AppendPidTid(Logger & logger,enum LOG_PHASE phase)197 void Logger::AppendPidTid(Logger &logger, enum LOG_PHASE phase)
198 {
199 if (phase == LOG_PHASE::BEGIN) {
200 logger << getpid() << ":" << GET_TID() << " ";
201 }
202 }
203
SetScopeParam(int func,int line)204 void Logger::SetScopeParam(int func, int line)
205 {
206 alignFunc = func;
207 alignLine = line;
208 }
209
EnterScope()210 void Logger::EnterScope()
211 {
212 std::lock_guard<std::mutex> lock(scopeMutex_);
213 scope_++;
214 }
215
ExitScope()216 void Logger::ExitScope()
217 {
218 std::lock_guard<std::mutex> lock(scopeMutex_);
219 scope_--;
220 }
221
Logger(const std::string & file,const std::string & func,int line,enum LOG_LEVEL level,...)222 Logger::Logger(const std::string &file, const std::string &func, int line, enum LOG_LEVEL level, ...)
223 {
224 *this << std::boolalpha;
225 file_ = file;
226 func_ = func;
227 line_ = line;
228 level_ = level;
229 va_start(vl_, level);
230
231 while (true) {
232 LoggerWrapperFunc f = va_arg(vl_, LoggerWrapperFunc);
233 if (f == nullptr) {
234 break;
235 }
236
237 f(*this, LOG_PHASE::BEGIN);
238 wrappers_.push_back(f);
239 }
240
241 #ifdef LOGGER_ENABLE_SCOPE
242 {
243 std::lock_guard<std::mutex> lock(scopeMutex_);
244 // The number of space if enable scope
245 Align(scope_ * 2); // 2 means multiple
246 }
247 #endif
248 }
249
Logger(const Logger & logger)250 Logger::Logger(const Logger &logger)
251 {
252 file_ = logger.file_;
253 func_ = logger.func_;
254 line_ = logger.line_;
255 level_ = logger.level_;
256 data_ = logger.data_;
257 wrappers_ = logger.wrappers_;
258 *this << logger.str();
259 }
260
Logger(Logger && logger)261 Logger::Logger(Logger &&logger)
262 {
263 file_ = logger.file_;
264 func_ = logger.func_;
265 line_ = logger.line_;
266 level_ = logger.level_;
267 data_ = logger.data_;
268 wrappers_ = logger.wrappers_;
269 *this << logger.str();
270
271 logger.wrappers_.clear();
272 }
273
~Logger()274 Logger::~Logger()
275 {
276 for (const auto &wrapper : wrappers_) {
277 wrapper(*this, LOG_PHASE::END);
278 }
279 }
280
GetFile() const281 const std::string &Logger::GetFile() const
282 {
283 return file_;
284 }
285
GetFunc() const286 const std::string &Logger::GetFunc() const
287 {
288 return func_;
289 }
290
GetLine() const291 int Logger::GetLine() const
292 {
293 return line_;
294 }
295
GetLevel() const296 enum Logger::LOG_LEVEL Logger::GetLevel() const
297 {
298 return level_;
299 }
300
GetVariousArgument()301 va_list &Logger::GetVariousArgument()
302 {
303 return vl_;
304 }
305
Align(int num)306 void Logger::Align(int num)
307 {
308 if (continue_) {
309 return;
310 }
311
312 for (int32_t i = 0; i < num; i++) {
313 *this << " ";
314 }
315 }
316
AlignLine()317 void Logger::AlignLine()
318 {
319 if (alignLine) {
320 auto line = GetLine();
321 auto num = line == 0 ? 1 : 0;
322 while (line) {
323 // 10 is to calculate the number of bits in the row where the function is located
324 line /= 10;
325 num++;
326 }
327 Align(alignLine - num);
328 }
329 }
330
AlignFunc()331 void Logger::AlignFunc()
332 {
333 if (alignFunc) {
334 Align(alignFunc - GetFunc().size());
335 }
336 }
337
ScopedLogger(NoLogger && logger)338 ScopedLogger::ScopedLogger(NoLogger &&logger)
339 {
340 }
341
ScopedLogger(NoLogger && logger,const std::string & name)342 ScopedLogger::ScopedLogger(NoLogger &&logger, const std::string &name)
343 {
344 }
345
ScopedLogger(Logger && logger)346 ScopedLogger::ScopedLogger(Logger &&logger)
347 : ScopedLogger(std::move(logger), "")
348 {
349 }
350
ScopedLogger(Logger && logger,const std::string & name)351 ScopedLogger::ScopedLogger(Logger &&logger, const std::string &name)
352 {
353 #ifdef LOGGER_ENABLE_SCOPE
354 logger_ = new Logger(logger);
355 *logger_ << "} " << name;
356 logger << "{ ";
357 #endif
358 logger << name;
359 Logger::EnterScope();
360 }
361
~ScopedLogger()362 ScopedLogger::~ScopedLogger()
363 {
364 Finish();
365 }
366
Finish()367 void ScopedLogger::Finish()
368 {
369 if (logger_) {
370 Logger::ExitScope();
371 delete logger_;
372 logger_ = nullptr;
373 }
374 }
375 } // namespace TextEngine
376 } // namespace Rosen
377 } // namespace OHOS
378