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