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_