1 /*
2 * Copyright (c) 2021-2022 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 #ifndef HIPERF_DEBUG_H
17 #define HIPERF_DEBUG_H
18
19 #include <chrono>
20 #include <cstdio>
21 #include <cstring>
22 #include <map>
23 #include <memory>
24 #include <mutex>
25 #include <sstream>
26 #include <string>
27 #include <unistd.h>
28 #if !is_mingw
29 #include <sys/syscall.h>
30 #if !IS_WASM
31 #undef gettid
32 #define gettid() syscall(SYS_gettid)
33 #endif
34 #else
35 #include "windows.h"
gettid()36 inline long gettid()
37 {
38 return GetCurrentThreadId();
39 }
40 #endif // !is_mingw
41
42 namespace OHOS {
43 namespace Developtools {
44 namespace HiPerf {
45 enum DebugLevel {
46 LEVEL_MUCH = 1,
47 LEVEL_VERBOSE,
48 LEVEL_DEBUG,
49 LEVEL_INFO,
50 LEVEL_WARNING,
51 LEVEL_ERROR,
52 LEVEL_FATAL,
53 LEVEL_STDOUT, // printf
54 LEVEL_MAX, // max
55 };
56
57 #ifdef HIPERF_DEBUG
58 #if is_ohos || is_double_framework
59 const std::string DEFAULT_UT_LOG_DIR = "/data/local/tmp/";
60 const std::string DEFAULT_LOG_PATH = "/data/local/tmp/hiperf_log.txt";
61 #elif is_mingw
62 const std::string DEFAULT_LOG_PATH = ".\\hiperf_log.txt";
63 #elif is_linux || is_mac
64 const std::string DEFAULT_UT_LOG_DIR = "./";
65 const std::string DEFAULT_LOG_PATH = "hiperf_log.txt";
66 #else
67 #error unkow os
68 #endif
69
70 #define HILOG_BASE_TAG "HILOG"
71 #ifndef HILOG_TAG
72 #define HILOG_TAG ""
73 #define HILOG_TAG_NAME HILOG_BASE_TAG
74 #else
75 #define HILOG_TAG_NAME HILOG_BASE_TAG "_" HILOG_TAG
76 #endif
77
78 const std::map<DebugLevel, const std::string> DebugLevelMap = {
79 {LEVEL_MUCH, "M"}, {LEVEL_VERBOSE, "V"}, {LEVEL_DEBUG, "D"}, {LEVEL_INFO, "I"},
80 {LEVEL_WARNING, "W"}, {LEVEL_ERROR, "E"}, {LEVEL_FATAL, "F"},
81 };
82 constexpr const int LOG_BUFFER_SIZE = 4 * 1024 * 1024;
83
84 class DebugLogger {
85 public:
86 DebugLogger();
87 ~DebugLogger();
88
89 static DebugLogger *GetInstance();
90 DebugLevel SetLogLevel(const DebugLevel debugLevel);
91 bool SetMixLogOutput(const bool enable);
92 bool SetLogPath(const std::string &logPath);
93 void SetLogTags(const std::string &tags);
94
95 int Log(const DebugLevel level, const std::string &logTag, const char *fmt, ...) const
96 __attribute__((format(printf, 4, 5)));
97 // for class, pointer need add 1 offset (first one is *this)
98
99 bool EnableHiLog(const bool enable = true);
GetLogLevel()100 DebugLevel GetLogLevel() const
101 {
102 return debugLevel_;
103 };
104
105 void Disable(const bool disable = true);
106 static bool logDisabled_;
107
108 #ifdef HIPERF_DEBUG_TIME
109 mutable size_t logCount_ = 0;
110 mutable std::chrono::microseconds logTimes_ = std::chrono::microseconds::zero();
111 mutable std::chrono::microseconds logWriteTimes_ = std::chrono::microseconds::zero();
112 mutable std::chrono::microseconds logSprintfTimes_ = std::chrono::microseconds::zero();
113 #endif
114
115 // used in UT
116 bool OpenLog(const std::string &tempLogPath = "", const std::string &flags = "w");
117 bool RestoreLog();
118 void Reset();
119
120 private:
121 bool ShouldLog(const DebugLevel level, const std::string &logtag) const;
122 DebugLevel GetLogLevelByName(const std::string &) const;
123 DebugLevel GetLogLevelByTag(const std::string &) const;
124 const std::string GetLogLevelName(const DebugLevel) const;
125
126 int HiLog(std::string &buffer) const;
127
128 static std::unique_ptr<DebugLogger> logInstance_;
129
130 mutable std::recursive_mutex logMutex_;
131 static DebugLevel debugLevel_;
132 const std::chrono::steady_clock::time_point timeStamp_;
133 FILE *file_ = nullptr;
134 bool mixLogOutput_ = false; // log mix to std
135 bool enableHilog_ = false;
136 bool exitOnFatal_ = true;
137 std::string logPath_;
138 std::map<std::string, DebugLevel> logTagLevelmap_;
139 };
140
141 #ifdef HIPERF_DEBUG_PRINTF
142 #ifndef printf
143 #define printf(format, ...) \
144 do { \
145 std::printf(format, ##__VA_ARGS__); \
146 DebugLogger::GetInstance()->Log(LEVEL_STDOUT, HILOG_TAG, format, ##__VA_ARGS__); \
147 } while (0)
148 #endif
149
150 #ifndef perror
151 #define perror(format, ...) \
152 do { \
153 std::perror(format); \
154 DebugLogger::GetInstance()->Log(LEVEL_STDOUT, HILOG_TAG, format "<%d>\n", \
155 ##__VA_ARGS__, errno); \
156 } while (0)
157 #endif
158 #endif
159
160 class ScopeDebugLevel {
161 public:
162 explicit ScopeDebugLevel(DebugLevel level, bool mix = false);
163 ~ScopeDebugLevel();
164
165 private:
166 DebugLevel savedDebugLevel_;
167 bool savedMixOutput_ = false; // log mix to std
168 };
169
170 #define LOG_LEVEL(LEVEL) LOG_##LEVEL
171 #define LOG_LEVEL_MUCH "M:"
172 #define LOG_LEVEL_VERBOSE "V:"
173 #define LOG_LEVEL_DEBUG "D:"
174 #define LOG_LEVEL_INFO "I:"
175 #define LOG_LEVEL_WARNING "W:"
176 #define LOG_LEVEL_ERROR "E:"
177 #define LOG_LEVEL_FATAL "F:"
178
179 #ifndef HLOG
180 #ifdef IS_RELEASE_VERSION
181 #define HLOG(level, format, ...) \
182 do { \
183 if (__builtin_expect(!DebugLogger::logDisabled_, false)) { \
184 DebugLogger::GetInstance()->Log( \
185 level, HILOG_TAG, \
186 HILOG_TAG_NAME "/" LOG_LEVEL(level) "<%ld>%s:" format "\n", gettid(), \
187 __FUNCTION__, ##__VA_ARGS__); \
188 } \
189 } while (0)
190 #else
191 #define HLOG(level, format, ...) \
192 do { \
193 if (__builtin_expect(!DebugLogger::logDisabled_, false)) { \
194 DebugLogger::GetInstance()->Log( \
195 level, HILOG_TAG, \
196 HILOG_TAG_NAME "/" LOG_LEVEL(level) "<%ld>[%s:%d]%s:" format "\n", gettid(), \
197 __FILE_NAME__, __LINE__, __FUNCTION__, ##__VA_ARGS__); \
198 } \
199 } while (0)
200 #endif
201 #endif
202
203 // only log first n times
204 #ifndef HLOGV_FIRST
205 #define HLOGV_FIRST(first, format, ...) \
206 do { \
207 static int limit = first; \
208 if (limit > 0) { \
209 HLOG(LEVEL_VERBOSE, format, ##__VA_ARGS__); \
210 if (--limit == 0) { \
211 HLOG(LEVEL_VERBOSE, " nexttime log will be suppressed..."); \
212 } \
213 } \
214 } while (0)
215 #endif
216
217 #ifndef HLOGV_FIRST_LOCAL
218 #define HLOGV_FIRST_LOCAL(local_limit, format, ...) \
219 { \
220 if (local_limit != 0) { \
221 HLOG(LEVEL_VERBOSE, format, ##__VA_ARGS__); \
222 if (local_limit > 0 && --local_limit == 0) { \
223 HLOG(LEVEL_VERBOSE, " nexttime log will be suppressed..."); \
224 } \
225 } \
226 }
227 #endif
228
229 #ifndef HLOGV
230 #define HLOGV_IF(condition, format, ...) \
231 if (condition) { \
232 HLOG(LEVEL_VERBOSE, format, ##__VA_ARGS__) \
233 }
234 #define HLOGVVV HLOGV
235 #endif
236
237 #ifndef HLOGDUMMY
238 #define HLOGDUMMY(format, ...) while (0)
239 #endif
240
241 #ifndef HLOGM
242 #define HLOGM(format, ...) HLOG(LEVEL_MUCH, format, ##__VA_ARGS__)
243 #define HLOGMMM HLOGM
244 #endif
245
246 #ifndef HLOGV
247 #define HLOGV(format, ...) HLOG(LEVEL_VERBOSE, format, ##__VA_ARGS__)
248 #endif
249
250 #ifndef HLOGD
251 #define HLOGD(format, ...) HLOG(LEVEL_DEBUG, format, ##__VA_ARGS__)
252 #define HLOGDDD HLOGM
253 #endif
254
255 #ifndef HLOGI
256 #define HLOGI(format, ...) HLOG(LEVEL_INFO, format, ##__VA_ARGS__)
257 #endif
258
259 #ifndef HLOGW
260 #define HLOGW(format, ...) HLOG(LEVEL_WARNING, format, ##__VA_ARGS__)
261 #endif
262
263 #ifndef HLOGE
264 #define HLOGE(format, ...) HLOG(LEVEL_ERROR, format, ##__VA_ARGS__)
265 #endif
266
267 #ifndef HLOGEP
268 #define HLOGEP(format, ...) \
269 HLOG(LEVEL_ERROR, format "(errno %d)", ##__VA_ARGS__, errno)
270 #endif
271
272 #ifndef HLOGF
273 #ifdef IS_RELEASE_VERSION
274 #define HLOGF(format, ...) HLOG(LEVEL_FATAL, "FATAL error occured, " format, ##__VA_ARGS__)
275 #else
276 #define HLOGF(format, ...) \
277 HLOG(LEVEL_FATAL, "FATAL error at %s:%d " format, __FILE_NAME__, __LINE__, ##__VA_ARGS__)
278 #endif
279 #endif
280
281 #ifndef HLOG_ASSERT_MESSAGE
282 #define HLOG_ASSERT_MESSAGE(condition, format, ...) \
283 if (!(condition)) { \
284 HLOG(LEVEL_FATAL, " assert failed: '%s' " format, #condition, ##__VA_ARGS__); \
285 }
286 #endif
287
288 #ifndef HLOG_ASSERT
289 #define HLOG_ASSERT(condition) HLOG_ASSERT_MESSAGE(condition, "")
290 #endif
291
292 #ifndef HIPERF_ASSERT
293 #define HIPERF_ASSERT(condition, format, ...) \
294 if (!(condition)) [[unlikely]] { \
295 printf(format, ##__VA_ARGS__); \
296 exit(-1); \
297 }
298 #endif
299
300 #undef assert
301 #else
302 #define HLOGDUMMY(...) \
303 do { \
304 } while (0)
305 #define HLOGEP(...) \
306 do { \
307 } while (0)
308 #define HLOGM(...) \
309 do { \
310 } while (0)
311 #define HLOGMMM(...) \
312 do { \
313 } while (0)
314 #define HLOGV(...) \
315 do { \
316 } while (0)
317 #define HLOGVVV(...) \
318 do { \
319 } while (0)
320 #define HLOGD(...) \
321 do { \
322 } while (0)
323 #define HLOGDDD(...) \
324 do { \
325 } while (0)
326 #define HLOGI(...) \
327 do { \
328 } while (0)
329 #define HLOGW(...) \
330 do { \
331 } while (0)
332 #define HLOGE(...) \
333 do { \
334 } while (0)
335 #define HLOGF(...) \
336 do { \
337 } while (0)
338 #define HLOG_ASSERT_MESSAGE(...) \
339 do { \
340 } while (0)
341 #define HLOG_ASSERT(...) \
342 do { \
343 } while (0)
344
345 class ScopeDebugLevel {
346 public:
347 ScopeDebugLevel(DebugLevel level, bool mix = false) {}
348 };
349 #endif
350 } // namespace HiPerf
351 } // namespace Developtools
352 } // namespace OHOS
353 #endif // _HIPERF_DEBUG_H_
354