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 <cstring>
21 #include <map>
22 #include <memory>
23 #include <mutex>
24 #include <sstream>
25 #include <stdio.h>
26 #include <string>
27 #include <unistd.h>
28
29 #include <gtest/gtest_prod.h>
30 #if !is_mingw
31 #include <sys/syscall.h>
32 #undef gettid
33 #define gettid() syscall(SYS_gettid)
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
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 #define SHORT_FILENAME \
79 (__builtin_strrchr(__FILE__, '/') ? __builtin_strrchr(__FILE__, '/') + 1 : __FILE__)
80
81 const std::map<DebugLevel, const std::string> DebugLevelMap = {
82 {LEVEL_MUCH, "M"}, {LEVEL_VERBOSE, "V"}, {LEVEL_DEBUG, "D"}, {LEVEL_INFO, "I"},
83 {LEVEL_WARNING, "W"}, {LEVEL_ERROR, "E"}, {LEVEL_FATAL, "F"},
84 };
85 constexpr const int LOG_BUFFER_SIZE = 4 * 1024 * 1024;
86
87 class DebugLogger {
88 public:
89 DebugLogger();
90 ~DebugLogger();
91
92 static DebugLogger *GetInstance();
93 DebugLevel SetLogLevel(DebugLevel debugLevel);
94 bool SetMixLogOutput(bool enable);
95 bool SetLogPath(const std::string &logPath);
96 void SetLogTags(const std::string &tags);
97
98 int Log(DebugLevel level, const std::string &logTag, const char *fmt, ...) const
99 __attribute__((format(printf, 4, 5)));
100 // for class, pointer need add 1 offset (first one is *this)
101
102 bool EnableHiLog(bool = true);
GetLogLevel()103 DebugLevel GetLogLevel() const
104 {
105 return debugLevel_;
106 };
107
108 void Disable(bool disable = true);
109 static bool logDisabled_;
110
111 #ifdef HIPERF_DEBUG_TIME
112 mutable size_t logCount_ = 0;
113 mutable std::chrono::microseconds logTimes_ = std::chrono::microseconds::zero();
114 mutable std::chrono::microseconds logWriteTimes_ = std::chrono::microseconds::zero();
115 mutable std::chrono::microseconds logSprintfTimes_ = std::chrono::microseconds::zero();
116 #endif
117
118 // used in UT
119 bool OpenLog(const std::string & = "", const std::string & = "w");
120 bool RestoreLog();
121 void Reset();
122
123 private:
124 bool ShouldLog(DebugLevel debugLevel, const std::string &logTag) const;
125 DebugLevel GetLogLevelByName(const std::string &) const;
126 DebugLevel GetLogLevelByTag(const std::string &) const;
127 const std::string GetLogLevelName(DebugLevel) const;
128
129 int HiLog(std::string &buffer) const;
130
131 static std::unique_ptr<DebugLogger> logInstance_;
132
133 mutable std::recursive_mutex logMutex_;
134 static DebugLevel debugLevel_;
135 const std::chrono::steady_clock::time_point timeStamp_;
136 FILE *file_ = nullptr;
137 bool mixLogOutput_ = false; // log mix to std
138 bool enableHilog_ = false;
139 bool exitOnFatal_ = true;
140 std::string logPath_;
141 std::map<std::string, DebugLevel> logTagLevelmap_;
142
143 friend class OptionDebugTest;
144 friend class DebugLoggerTest;
145 FRIEND_TEST(DebugLoggerTest, SetLogTags);
146 FRIEND_TEST(DebugLoggerTest, Disable);
147 };
148
149 #ifdef HIPERF_DEBUG_PRINTF
150 #ifndef printf
151 #define printf(format, ...) \
152 do { \
153 std::printf(format, ##__VA_ARGS__); \
154 DebugLogger::GetInstance()->Log(LEVEL_STDOUT, HILOG_TAG, format, ##__VA_ARGS__); \
155 } while (0)
156 #endif
157
158 #ifndef perror
159 #define perror(format, ...) \
160 do { \
161 std::perror(format); \
162 DebugLogger::GetInstance()->Log(LEVEL_STDOUT, HILOG_TAG, format "<%d>\n", \
163 ##__VA_ARGS__, errno); \
164 } while (0)
165 #endif
166 #endif
167
168 class ScopeDebugLevel {
169 public:
170 ScopeDebugLevel(DebugLevel level, bool mix = false);
171 ~ScopeDebugLevel();
172
173 private:
174 DebugLevel savedDebugLevel_;
175 bool savedMixOutput_ = false; // log mix to std
176 };
177 #define TempMixLogLevel(level) ScopeDebugLevel tempLogLevel(level, true)
178
179 #define LOG_LEVEL(LEVEL) LOG_##LEVEL
180 #define LOG_LEVEL_MUCH "M:"
181 #define LOG_LEVEL_VERBOSE "V:"
182 #define LOG_LEVEL_DEBUG "D:"
183 #define LOG_LEVEL_INFO "I:"
184 #define LOG_LEVEL_WARNING "W:"
185 #define LOG_LEVEL_ERROR "E:"
186 #define LOG_LEVEL_FATAL "F:"
187
188 #ifndef HLOG
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 SHORT_FILENAME, __LINE__, __FUNCTION__, ##__VA_ARGS__); \
196 } \
197 } while (0)
198 #endif
199
200 // only log first n times
201 #ifndef HLOGV_FIRST
202 #define HLOGV_FIRST(first, format, ...) \
203 do { \
204 static int limit = first; \
205 if (limit > 0) { \
206 HLOG(LEVEL_VERBOSE, format, ##__VA_ARGS__); \
207 if (--limit == 0) { \
208 HLOG(LEVEL_VERBOSE, " nexttime log will be suppressed..."); \
209 } \
210 } \
211 } while (0)
212 #endif
213
214 #ifndef HLOGV_FIRST_LOCAL
215 #define HLOGV_FIRST_LOCAL(local_limit, format, ...) \
216 { \
217 if (local_limit != 0) { \
218 HLOG(LEVEL_VERBOSE, format, ##__VA_ARGS__); \
219 if (local_limit > 0 && --local_limit == 0) { \
220 HLOG(LEVEL_VERBOSE, " nexttime log will be suppressed..."); \
221 } \
222 } \
223 }
224 #endif
225
226 #ifndef HLOGV
227 #define HLOGV_IF(condition, format, ...) \
228 if (condition) { \
229 HLOG(LEVEL_VERBOSE, format, ##__VA_ARGS__) \
230 }
231 #define HLOGVVV HLOGV
232 #endif
233
234 #ifndef HLOGDUMMY
235 #define HLOGDUMMY(format, ...) while (0)
236 #endif
237
238 #ifndef HLOGM
239 #define HLOGM(format, ...) HLOG(LEVEL_MUCH, format, ##__VA_ARGS__)
240 #define HLOGMMM HLOGM
241 #endif
242
243 #ifndef HLOGV
244 #define HLOGV(format, ...) HLOG(LEVEL_VERBOSE, format, ##__VA_ARGS__)
245 #endif
246
247 #ifndef HLOGD
248 #define HLOGD(format, ...) HLOG(LEVEL_DEBUG, format, ##__VA_ARGS__)
249 #define HLOGDDD HLOGM
250 #endif
251
252 #ifndef HLOGI
253 #define HLOGI(format, ...) HLOG(LEVEL_INFO, format, ##__VA_ARGS__)
254 #endif
255
256 #ifndef HLOGW
257 #define HLOGW(format, ...) HLOG(LEVEL_WARNING, format, ##__VA_ARGS__)
258 #endif
259
260 #ifndef HLOGE
261 #define HLOGE(format, ...) HLOG(LEVEL_ERROR, format, ##__VA_ARGS__)
262 #endif
263
264 #ifndef HLOGEP
265 #define HLOGEP(format, ...) \
266 HLOG(LEVEL_ERROR, format "(errno %d)", ##__VA_ARGS__, errno)
267 #endif
268
269 #ifndef HLOGF
270 #define HLOGF(format, ...) \
271 HLOG(LEVEL_FATAL, "FATAL error at %s:%d " format, __FILE__, __LINE__, ##__VA_ARGS__)
272 #endif
273
274 #ifndef HLOG_ASSERT_MESSAGE
275 #define HLOG_ASSERT_MESSAGE(condition, format, ...) \
276 if (!(condition)) { \
277 HLOG(LEVEL_FATAL, " assert failed: '%s' " format, #condition, ##__VA_ARGS__); \
278 }
279 #endif
280
281 #ifndef HLOG_ASSERT
282 #define HLOG_ASSERT(condition) HLOG_ASSERT_MESSAGE(condition, "")
283 #endif
284
285 #undef assert
286 #else
287 #define HLOGDUMMY(...) \
288 do { \
289 } while (0)
290 #define HLOGEP(...) \
291 do { \
292 } while (0)
293 #define HLOGM(...) \
294 do { \
295 } while (0)
296 #define HLOGMMM(...) \
297 do { \
298 } while (0)
299 #define HLOGV(...) \
300 do { \
301 } while (0)
302 #define HLOGVVV(...) \
303 do { \
304 } while (0)
305 #define HLOGD(...) \
306 do { \
307 } while (0)
308 #define HLOGDDD(...) \
309 do { \
310 } while (0)
311 #define HLOGI(...) \
312 do { \
313 } while (0)
314 #define HLOGW(...) \
315 do { \
316 } while (0)
317 #define HLOGE(...) \
318 do { \
319 } while (0)
320 #define HLOGF(...) \
321 do { \
322 } while (0)
323 #define HLOG_ASSERT_MESSAGE(...) \
324 do { \
325 } while (0)
326 #define HLOG_ASSERT(...) \
327 do { \
328 } while (0)
329
330 class ScopeDebugLevel {
331 public:
332 ScopeDebugLevel(DebugLevel level, bool mix = false) {}
333 };
334 #endif
335 } // namespace HiPerf
336 } // namespace Developtools
337 } // namespace OHOS
338 #endif // _HIPERF_DEBUG_H_
339