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 <sys/syscall.h>
22 #include <unistd.h>
23 #define GET_TID() syscall(__NR_gettid)
24
25 #ifdef LOGGER_NO_COLOR
26 #define IF_COLOR(x)
27 #else
28 #define IF_COLOR(x) x
29 #endif
30
31 namespace OHOS {
32 namespace Rosen {
33 namespace TextEngine {
34 namespace {
GetLevelStr(enum Logger::LOG_LEVEL level)35 const char *GetLevelStr(enum Logger::LOG_LEVEL level)
36 {
37 switch (level) {
38 case Logger::LOG_LEVEL::DEBUG:
39 return IF_COLOR("\033[37m") "D" IF_COLOR("\033[0m");
40 case Logger::LOG_LEVEL::INFO:
41 return IF_COLOR("\033[36m") "I" IF_COLOR("\033[0m");
42 case Logger::LOG_LEVEL::WARN:
43 return IF_COLOR("\033[33m") "W" IF_COLOR("\033[0m");
44 case Logger::LOG_LEVEL::ERROR:
45 return IF_COLOR("\033[31m") "E" IF_COLOR("\033[0m");
46 case Logger::LOG_LEVEL::FATAL:
47 return IF_COLOR("\033[4;31m") "F" IF_COLOR("\033[0m");
48 }
49 return "?";
50 }
51 } // namespace
52
SetToNoReturn(Logger & logger,enum LOG_PHASE phase)53 void Logger::SetToNoReturn(Logger &logger, enum LOG_PHASE phase)
54 {
55 logger.return_ = false;
56 }
57
SetToContinue(Logger & logger,enum LOG_PHASE phase)58 void Logger::SetToContinue(Logger &logger, enum LOG_PHASE phase)
59 {
60 logger.continue_ = true;
61 }
62
OutputByStdout(Logger & logger,enum LOG_PHASE phase)63 void Logger::OutputByStdout(Logger &logger, enum LOG_PHASE phase)
64 {
65 if (phase == LOG_PHASE::BEGIN) {
66 return;
67 }
68
69 // LOG_PHASE::END
70 if (logger.continue_ == false) {
71 std::cout << GetLevelStr(logger.GetLevel()) << " ";
72 }
73
74 std::cout << logger.str();
75 if (logger.return_) {
76 std::cout << std::endl;
77 }
78 }
79
OutputByStderr(Logger & logger,enum LOG_PHASE phase)80 void Logger::OutputByStderr(Logger &logger, enum LOG_PHASE phase)
81 {
82 if (phase == LOG_PHASE::BEGIN) {
83 return;
84 }
85
86 // LOG_PHASE::END
87 if (logger.continue_ == false) {
88 std::cerr << GetLevelStr(logger.GetLevel()) << " ";
89 }
90
91 std::cerr << logger.str();
92 if (logger.return_) {
93 std::cerr << std::endl;
94 }
95 }
96
OutputByFileLog(Logger & logger,enum LOG_PHASE phase)97 void Logger::OutputByFileLog(Logger &logger, enum LOG_PHASE phase)
98 {
99 struct FileLogData {
100 const char *filename;
101 };
102 auto data = logger.GetData<struct FileLogData>();
103 if (phase == LOG_PHASE::BEGIN) {
104 auto filename = va_arg(logger.GetVariousArgument(), const char *);
105 data->filename = filename;
106 return;
107 }
108
109 // LOG_PHASE::END
110 std::ofstream ofs(data->filename, std::ofstream::out | std::ofstream::app);
111 if (!ofs) {
112 // open failed, errno
113 return;
114 }
115
116 if (logger.continue_ == false) {
117 ofs << GetLevelStr(logger.GetLevel()) << " ";
118 }
119
120 ofs << logger.str();
121 if (logger.return_) {
122 ofs << std::endl;
123 }
124 ofs.close();
125 }
126
AppendFunc(Logger & logger,enum LOG_PHASE phase)127 void Logger::AppendFunc(Logger &logger, enum LOG_PHASE phase)
128 {
129 if (phase == LOG_PHASE::BEGIN) {
130 logger << IF_COLOR("\033[34m");
131 logger.AlignFunc();
132 logger << logger.GetFunc() << IF_COLOR("\033[0m") " ";
133 }
134 }
135
AppendFuncLine(Logger & logger,enum LOG_PHASE phase)136 void Logger::AppendFuncLine(Logger &logger, enum LOG_PHASE phase)
137 {
138 if (phase == LOG_PHASE::BEGIN) {
139 logger << IF_COLOR("\033[34m");
140 logger.AlignFunc();
141 logger << logger.GetFunc() << " ";
142 logger.AlignLine();
143 logger << IF_COLOR("\033[35m") "+" << logger.GetLine() << IF_COLOR("\033[0m") " ";
144 }
145 }
146
AppendFileLine(Logger & logger,enum LOG_PHASE phase)147 void Logger::AppendFileLine(Logger &logger, enum LOG_PHASE phase)
148 {
149 if (phase == LOG_PHASE::BEGIN) {
150 logger << IF_COLOR("\033[34m") << logger.GetFile() << " ";
151 logger.AlignLine();
152 logger << IF_COLOR("\033[35m") "+" << logger.GetLine() << IF_COLOR("\033[0m") " ";
153 }
154 }
155
AppendFileFuncLine(Logger & logger,enum LOG_PHASE phase)156 void Logger::AppendFileFuncLine(Logger &logger, enum LOG_PHASE phase)
157 {
158 if (phase == LOG_PHASE::BEGIN) {
159 logger << IF_COLOR("\033[34m") << logger.GetFile() << " ";
160 logger.AlignLine();
161 logger << IF_COLOR("\033[35m") "+" << logger.GetLine() << " ";
162 logger.AlignFunc();
163 logger << logger.GetFunc() << IF_COLOR("\033[0m") " ";
164 }
165 }
166
AppendPidTid(Logger & logger,enum LOG_PHASE phase)167 void Logger::AppendPidTid(Logger &logger, enum LOG_PHASE phase)
168 {
169 if (phase == LOG_PHASE::BEGIN) {
170 logger << getpid() << ":" << GET_TID() << " ";
171 }
172 }
173
SetScopeParam(int func,int line)174 void Logger::SetScopeParam(int func, int line)
175 {
176 alignFunc = func;
177 alignLine = line;
178 }
179
EnterScope()180 void Logger::EnterScope()
181 {
182 std::lock_guard<std::mutex> lock(scopeMutex_);
183 scope_++;
184 }
185
ExitScope()186 void Logger::ExitScope()
187 {
188 std::lock_guard<std::mutex> lock(scopeMutex_);
189 scope_--;
190 }
191
Logger(const std::string & file,const std::string & func,int line,enum LOG_LEVEL level,...)192 Logger::Logger(const std::string &file, const std::string &func, int line, enum LOG_LEVEL level, ...)
193 {
194 *this << std::boolalpha;
195 file_ = file;
196 func_ = func;
197 line_ = line;
198 level_ = level;
199 va_start(vl_, level);
200
201 while (true) {
202 LoggerWrapperFunc f = va_arg(vl_, LoggerWrapperFunc);
203 if (f == nullptr) {
204 break;
205 }
206
207 f(*this, LOG_PHASE::BEGIN);
208 wrappers_.push_back(f);
209 }
210
211 #ifdef LOGGER_ENABLE_SCOPE
212 {
213 std::lock_guard<std::mutex> lock(scopeMutex_);
214 // The number of space if enable scope
215 Align(scope_ * 2); // 2 means multiple
216 }
217 #endif
218 }
219
Logger(const Logger & logger)220 Logger::Logger(const Logger &logger)
221 {
222 file_ = logger.file_;
223 func_ = logger.func_;
224 line_ = logger.line_;
225 level_ = logger.level_;
226 data_ = logger.data_;
227 wrappers_ = logger.wrappers_;
228 *this << logger.str();
229 }
230
Logger(Logger && logger)231 Logger::Logger(Logger &&logger)
232 {
233 file_ = logger.file_;
234 func_ = logger.func_;
235 line_ = logger.line_;
236 level_ = logger.level_;
237 data_ = logger.data_;
238 wrappers_ = logger.wrappers_;
239 *this << logger.str();
240
241 logger.wrappers_.clear();
242 }
243
~Logger()244 Logger::~Logger()
245 {
246 for (const auto &wrapper : wrappers_) {
247 wrapper(*this, LOG_PHASE::END);
248 }
249 }
250
GetFile() const251 const std::string &Logger::GetFile() const
252 {
253 return file_;
254 }
255
GetFunc() const256 const std::string &Logger::GetFunc() const
257 {
258 return func_;
259 }
260
GetLine() const261 int Logger::GetLine() const
262 {
263 return line_;
264 }
265
GetLevel() const266 enum Logger::LOG_LEVEL Logger::GetLevel() const
267 {
268 return level_;
269 }
270
GetVariousArgument()271 va_list &Logger::GetVariousArgument()
272 {
273 return vl_;
274 }
275
Align(int num)276 void Logger::Align(int num)
277 {
278 if (continue_) {
279 return;
280 }
281
282 for (int32_t i = 0; i < num; i++) {
283 *this << " ";
284 }
285 }
286
AlignLine()287 void Logger::AlignLine()
288 {
289 if (alignLine) {
290 auto line = GetLine();
291 auto num = line == 0 ? 1 : 0;
292 while (line) {
293 // 10 is to calculate the number of bits in the row where the function is located
294 line /= 10;
295 num++;
296 }
297 Align(alignLine - num);
298 }
299 }
300
AlignFunc()301 void Logger::AlignFunc()
302 {
303 if (alignFunc) {
304 Align(alignFunc - GetFunc().size());
305 }
306 }
307
ScopedLogger(NoLogger && logger)308 ScopedLogger::ScopedLogger(NoLogger &&logger)
309 {
310 }
311
ScopedLogger(NoLogger && logger,const std::string & name)312 ScopedLogger::ScopedLogger(NoLogger &&logger, const std::string &name)
313 {
314 }
315
ScopedLogger(Logger && logger)316 ScopedLogger::ScopedLogger(Logger &&logger)
317 : ScopedLogger(std::move(logger), "")
318 {
319 }
320
ScopedLogger(Logger && logger,const std::string & name)321 ScopedLogger::ScopedLogger(Logger &&logger, const std::string &name)
322 {
323 #ifdef LOGGER_ENABLE_SCOPE
324 logger_ = new Logger(logger);
325 *logger_ << "} " << name;
326 logger << "{ ";
327 #endif
328 logger << name;
329 Logger::EnterScope();
330 }
331
~ScopedLogger()332 ScopedLogger::~ScopedLogger()
333 {
334 Finish();
335 }
336
Finish()337 void ScopedLogger::Finish()
338 {
339 if (logger_) {
340 Logger::ExitScope();
341 delete logger_;
342 logger_ = nullptr;
343 }
344 }
345 } // namespace TextEngine
346 } // namespace Rosen
347 } // namespace OHOS
348