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 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" 36inline long gettid() 37{ 38 return GetCurrentThreadId(); 39} 40#endif // !is_mingw 41 42namespace OHOS { 43namespace Developtools { 44namespace HiPerf { 45enum 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 59const std::string DEFAULT_UT_LOG_DIR = "/data/local/tmp/"; 60const std::string DEFAULT_LOG_PATH = "/data/local/tmp/hiperf_log.txt"; 61#elif is_mingw 62const std::string DEFAULT_LOG_PATH = ".\\hiperf_log.txt"; 63#elif is_linux 64const std::string DEFAULT_UT_LOG_DIR = "./"; 65const 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 78const 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}; 82constexpr const int LOG_BUFFER_SIZE = 4 * 1024 * 1024; 83 84class DebugLogger { 85public: 86 DebugLogger(); 87 ~DebugLogger(); 88 89 static DebugLogger *GetInstance(); 90 DebugLevel SetLogLevel(DebugLevel debugLevel); 91 bool SetMixLogOutput(bool enable); 92 bool SetLogPath(const std::string &logPath); 93 void SetLogTags(const std::string &tags); 94 95 int Log(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(bool enable = true); 100 DebugLevel GetLogLevel() const 101 { 102 return debugLevel_; 103 }; 104 105 void Disable(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 120private: 121 bool ShouldLog(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(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 friend class OptionDebugTest; 141 friend class DebugLoggerTest; 142 FRIEND_TEST(DebugLoggerTest, SetLogTags); 143 FRIEND_TEST(DebugLoggerTest, Disable); 144}; 145 146#ifdef HIPERF_DEBUG_PRINTF 147#ifndef printf 148#define printf(format, ...) \ 149 do { \ 150 std::printf(format, ##__VA_ARGS__); \ 151 DebugLogger::GetInstance()->Log(LEVEL_STDOUT, HILOG_TAG, format, ##__VA_ARGS__); \ 152 } while (0) 153#endif 154 155#ifndef perror 156#define perror(format, ...) \ 157 do { \ 158 std::perror(format); \ 159 DebugLogger::GetInstance()->Log(LEVEL_STDOUT, HILOG_TAG, format "<%d>\n", \ 160 ##__VA_ARGS__, errno); \ 161 } while (0) 162#endif 163#endif 164 165class ScopeDebugLevel { 166public: 167 explicit ScopeDebugLevel(DebugLevel level, bool mix = false); 168 ~ScopeDebugLevel(); 169 170private: 171 DebugLevel savedDebugLevel_; 172 bool savedMixOutput_ = false; // log mix to std 173}; 174 175#define LOG_LEVEL(LEVEL) LOG_##LEVEL 176#define LOG_LEVEL_MUCH "M:" 177#define LOG_LEVEL_VERBOSE "V:" 178#define LOG_LEVEL_DEBUG "D:" 179#define LOG_LEVEL_INFO "I:" 180#define LOG_LEVEL_WARNING "W:" 181#define LOG_LEVEL_ERROR "E:" 182#define LOG_LEVEL_FATAL "F:" 183 184#ifndef HLOG 185#ifdef IS_RELEASE_VERSION 186#define HLOG(level, format, ...) \ 187 do { \ 188 if (__builtin_expect(!DebugLogger::logDisabled_, false)) { \ 189 DebugLogger::GetInstance()->Log( \ 190 level, HILOG_TAG, \ 191 HILOG_TAG_NAME "/" LOG_LEVEL(level) "<%ld>%s:" format "\n", gettid(), \ 192 __FUNCTION__, ##__VA_ARGS__); \ 193 } \ 194 } while (0) 195#else 196#define HLOG(level, format, ...) \ 197 do { \ 198 if (__builtin_expect(!DebugLogger::logDisabled_, false)) { \ 199 DebugLogger::GetInstance()->Log( \ 200 level, HILOG_TAG, \ 201 HILOG_TAG_NAME "/" LOG_LEVEL(level) "<%ld>[%s:%d]%s:" format "\n", gettid(), \ 202 __FILE_NAME__, __LINE__, __FUNCTION__, ##__VA_ARGS__); \ 203 } \ 204 } while (0) 205#endif 206#endif 207 208// only log first n times 209#ifndef HLOGV_FIRST 210#define HLOGV_FIRST(first, format, ...) \ 211 do { \ 212 static int limit = first; \ 213 if (limit > 0) { \ 214 HLOG(LEVEL_VERBOSE, format, ##__VA_ARGS__); \ 215 if (--limit == 0) { \ 216 HLOG(LEVEL_VERBOSE, " nexttime log will be suppressed..."); \ 217 } \ 218 } \ 219 } while (0) 220#endif 221 222#ifndef HLOGV_FIRST_LOCAL 223#define HLOGV_FIRST_LOCAL(local_limit, format, ...) \ 224 { \ 225 if (local_limit != 0) { \ 226 HLOG(LEVEL_VERBOSE, format, ##__VA_ARGS__); \ 227 if (local_limit > 0 && --local_limit == 0) { \ 228 HLOG(LEVEL_VERBOSE, " nexttime log will be suppressed..."); \ 229 } \ 230 } \ 231 } 232#endif 233 234#ifndef HLOGV 235#define HLOGV_IF(condition, format, ...) \ 236 if (condition) { \ 237 HLOG(LEVEL_VERBOSE, format, ##__VA_ARGS__) \ 238 } 239#define HLOGVVV HLOGV 240#endif 241 242#ifndef HLOGDUMMY 243#define HLOGDUMMY(format, ...) while (0) 244#endif 245 246#ifndef HLOGM 247#define HLOGM(format, ...) HLOG(LEVEL_MUCH, format, ##__VA_ARGS__) 248#define HLOGMMM HLOGM 249#endif 250 251#ifndef HLOGV 252#define HLOGV(format, ...) HLOG(LEVEL_VERBOSE, format, ##__VA_ARGS__) 253#endif 254 255#ifndef HLOGD 256#define HLOGD(format, ...) HLOG(LEVEL_DEBUG, format, ##__VA_ARGS__) 257#define HLOGDDD HLOGM 258#endif 259 260#ifndef HLOGI 261#define HLOGI(format, ...) HLOG(LEVEL_INFO, format, ##__VA_ARGS__) 262#endif 263 264#ifndef HLOGW 265#define HLOGW(format, ...) HLOG(LEVEL_WARNING, format, ##__VA_ARGS__) 266#endif 267 268#ifndef HLOGE 269#define HLOGE(format, ...) HLOG(LEVEL_ERROR, format, ##__VA_ARGS__) 270#endif 271 272#ifndef HLOGEP 273#define HLOGEP(format, ...) \ 274 HLOG(LEVEL_ERROR, format "(errno %d)", ##__VA_ARGS__, errno) 275#endif 276 277#ifndef HLOGF 278#ifdef IS_RELEASE_VERSION 279#define HLOGF(format, ...) HLOG(LEVEL_FATAL, "FATAL error occured, " format, ##__VA_ARGS__) 280#else 281#define HLOGF(format, ...) \ 282 HLOG(LEVEL_FATAL, "FATAL error at %s:%d " format, __FILE_NAME__, __LINE__, ##__VA_ARGS__) 283#endif 284#endif 285 286#ifndef HLOG_ASSERT_MESSAGE 287#define HLOG_ASSERT_MESSAGE(condition, format, ...) \ 288 if (!(condition)) { \ 289 HLOG(LEVEL_FATAL, " assert failed: '%s' " format, #condition, ##__VA_ARGS__); \ 290 } 291#endif 292 293#ifndef HLOG_ASSERT 294#define HLOG_ASSERT(condition) HLOG_ASSERT_MESSAGE(condition, "") 295#endif 296 297#undef assert 298#else 299#define HLOGDUMMY(...) \ 300 do { \ 301 } while (0) 302#define HLOGEP(...) \ 303 do { \ 304 } while (0) 305#define HLOGM(...) \ 306 do { \ 307 } while (0) 308#define HLOGMMM(...) \ 309 do { \ 310 } while (0) 311#define HLOGV(...) \ 312 do { \ 313 } while (0) 314#define HLOGVVV(...) \ 315 do { \ 316 } while (0) 317#define HLOGD(...) \ 318 do { \ 319 } while (0) 320#define HLOGDDD(...) \ 321 do { \ 322 } while (0) 323#define HLOGI(...) \ 324 do { \ 325 } while (0) 326#define HLOGW(...) \ 327 do { \ 328 } while (0) 329#define HLOGE(...) \ 330 do { \ 331 } while (0) 332#define HLOGF(...) \ 333 do { \ 334 } while (0) 335#define HLOG_ASSERT_MESSAGE(...) \ 336 do { \ 337 } while (0) 338#define HLOG_ASSERT(...) \ 339 do { \ 340 } while (0) 341 342class ScopeDebugLevel { 343public: 344 ScopeDebugLevel(DebugLevel level, bool mix = false) {} 345}; 346#endif 347} // namespace HiPerf 348} // namespace Developtools 349} // namespace OHOS 350#endif // _HIPERF_DEBUG_H_ 351