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