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