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