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