1 /** 2 * Copyright (c) 2024 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 LIBABCKIT_LOGGER 17 #define LIBABCKIT_LOGGER 18 19 #include <iostream> 20 #include <memory> 21 #include <string> 22 #include <vector> 23 #include <array> 24 #include <algorithm> 25 #include <map> 26 #include <cstdlib> 27 28 constexpr const char *LIBABCKIT_PREFIX = "[ LIBABCKIT ]"; 29 #define LIBABCKIT_FUNC_NAME __func__ 30 31 static constexpr std::array<const char *, 7> const TRUE_VALUES = {"ON", "on", "1", "true", "TRUE", "enable", "ENABLE"}; 32 33 namespace libabckit { 34 35 class NullBuffer : public std::streambuf { 36 public: overflow(int c)37 int overflow(int c) override 38 { 39 return c; 40 } 41 }; 42 extern thread_local NullBuffer g_nB; 43 extern thread_local std::ostream g_nullStream; 44 45 struct AbckitComponent { 46 private: 47 std::string name_; 48 std::string prefix_; 49 bool isEnabled_ = true; 50 51 public: 52 explicit AbckitComponent(const std::string &componentName, bool enabled = true) name_AbckitComponent53 : name_(componentName), isEnabled_(enabled) 54 { 55 prefix_ = "[" + componentName + "]\t"; 56 } AbckitComponentAbckitComponent57 explicit AbckitComponent(const std::string &componentName) : name_(componentName) 58 { 59 prefix_ = "[" + componentName + "]\t"; 60 isEnabled_ = true; 61 } DisableAbckitComponent62 void Disable() 63 { 64 isEnabled_ = false; 65 } EnableAbckitComponent66 void Enable() 67 { 68 isEnabled_ = true; 69 } CheckStatusAbckitComponent70 bool CheckStatus() 71 { 72 return isEnabled_; 73 } GetPrefixAbckitComponent74 std::string GetPrefix() 75 { 76 return prefix_; 77 } 78 }; 79 80 class Logger final { 81 public: 82 enum LogLevel { DEBUG = 1, WARNING, ERROR, FATAL, UNIMPLEMENTED, IMPLEMENTED, UNKNOWN, INCORRECT_LOG_LVL }; 83 84 // NOLINTNEXTLINE(fuchsia-statically-constructed-objects) 85 inline static std::map<std::string, const LogLevel> levelsSet_ = { 86 {"DEBUG", LogLevel::DEBUG}, 87 {"WARNING", LogLevel::WARNING}, 88 {"ERROR", LogLevel::ERROR}, 89 {"FATAL", LogLevel::FATAL}, 90 {"UNIMPLEMENTED", LogLevel::UNIMPLEMENTED}, 91 {"IMPLEMENTED", LogLevel::IMPLEMENTED}, 92 {"UNKNOWN", LogLevel::UNKNOWN}, 93 {"INCORRECT_LOG_LVL", LogLevel::INCORRECT_LOG_LVL}, 94 }; 95 enum MODE { DEBUG_MODE = 1, RELEASE_MODE, SILENCE_MODE }; 96 97 // NOLINTNEXTLINE(fuchsia-statically-constructed-objects) 98 inline static std::map<std::string, std::unique_ptr<AbckitComponent>> components_ = {}; 99 inline static bool isInitialized_ = false; 100 101 static Logger *logger_; 102 Initialize(MODE mode)103 static void Initialize(MODE mode) 104 { 105 if (isInitialized_) { 106 return; 107 } 108 if (const char *env = std::getenv("LIBABCKIT_DEBUG_MODE")) { 109 if ((std::find(TRUE_VALUES.begin(), TRUE_VALUES.end(), (std::string)env)) != TRUE_VALUES.end()) { 110 mode = MODE::DEBUG_MODE; 111 } 112 } 113 logger_ = new Logger(mode); 114 isInitialized_ = true; 115 } 116 Logger(MODE mode)117 explicit Logger(MODE mode) : loggerMode_(mode) {} 118 119 // NOLINTNEXTLINE(fuchsia-statically-constructed-objects) 120 inline static std::string msgPrefix_; 121 CheckLoggingMode()122 static bool CheckLoggingMode() 123 { 124 return !(logger_->loggerMode_ == MODE::SILENCE_MODE); 125 } 126 CheckLogLevel(const std::string & level)127 static bool CheckLogLevel(const std::string &level) 128 { 129 return (logger_->levelsSet_.find(level) != logger_->levelsSet_.end()); 130 } 131 CheckIfPermissible(LogLevel level)132 static bool CheckIfPermissible(LogLevel level) 133 { 134 if (logger_->loggerMode_ == MODE::DEBUG_MODE) { 135 return true; // permissible 136 } 137 if (logger_->loggerMode_ == MODE::RELEASE_MODE) { 138 return (level == LogLevel::FATAL || level == LogLevel::ERROR); 139 } 140 return false; // suppressed 141 } 142 CheckIfPermissible(const LogLevel level,const std::string & componentName)143 static bool CheckIfPermissible(const LogLevel level, const std::string &componentName) 144 { 145 if (!logger_->CheckIfEnable(componentName)) { 146 return false; 147 } 148 return logger_->CheckIfPermissible(level); 149 } 150 CheckIfInComponents(const std::string & sideName)151 static bool CheckIfInComponents(const std::string &sideName) 152 { 153 return (logger_->components_.find(sideName) != logger_->components_.end()); 154 } 155 SetCompOpt(std::string & sideName,bool enable)156 void SetCompOpt(std::string &sideName, bool enable) 157 { 158 if (!CheckIfInComponents(sideName)) { 159 logger_->components_[sideName] = std::make_unique<AbckitComponent>(sideName, enable); 160 return; 161 } 162 if (enable) { 163 logger_->components_[sideName]->Enable(); 164 } else { 165 logger_->components_[sideName]->Enable(); 166 } 167 } DisableComponent(std::string & sideName)168 void DisableComponent(std::string &sideName) 169 { 170 SetCompOpt(sideName, false); 171 } EnableComponent(std::string & sideName)172 void EnableComponent(std::string &sideName) 173 { 174 SetCompOpt(sideName, true); 175 } 176 CheckIfEnable(const std::string & sideName)177 static bool CheckIfEnable(const std::string &sideName) 178 { 179 if (!CheckIfInComponents(sideName)) { 180 return true; 181 } 182 return logger_->components_[sideName]->CheckStatus(); 183 } 184 MessageCompPrefix(const std::string & componentName)185 static std::string MessageCompPrefix(const std::string &componentName) 186 { 187 return "[ LIBABCKIT " + (std::string)componentName + " ] "; 188 } 189 CheckPermission(const std::string & levelName)190 static bool CheckPermission(const std::string &levelName) 191 { 192 if (!CheckLogLevel(levelName)) { 193 std::cout << '\n' << LIBABCKIT_PREFIX << " INCORRECT LOG LEVEL: " << levelName << '\n'; 194 return false; 195 } 196 LogLevel msgLevel = logger_->levelsSet_[levelName]; 197 if (!CheckLoggingMode() || !CheckIfPermissible(msgLevel)) { 198 return false; 199 } 200 if (msgLevel == LogLevel::INCORRECT_LOG_LVL) { 201 return false; 202 } 203 return true; 204 } 205 GetLoggerStream(const std::string & levelName)206 static std::ostream *GetLoggerStream(const std::string &levelName) 207 { 208 if (!CheckPermission(levelName)) { 209 return &g_nullStream; 210 } 211 return &std::cerr; 212 } 213 Message(const std::string & levelName)214 static std::ostream *Message(const std::string &levelName) 215 { 216 if (levelName == "FATAL") { 217 std::cout << "FATAL: " << LIBABCKIT_FUNC_NAME << '\n'; 218 std::abort(); // CC-OFF(G.FUU.08) fatal 219 } 220 logger_->msgPrefix_ = LIBABCKIT_PREFIX; 221 return GetLoggerStream(levelName); 222 } 223 Message(const std::string & levelName,const std::string & componentName)224 static std::ostream *Message(const std::string &levelName, const std::string &componentName) 225 { 226 if (!CheckIfPermissible(logger_->levelsSet_[levelName], componentName)) { 227 return &g_nullStream; 228 } 229 logger_->msgPrefix_ = MessageCompPrefix(componentName); 230 return GetLoggerStream(levelName); 231 } 232 233 private: 234 MODE loggerMode_ = MODE::RELEASE_MODE; // default 235 }; 236 } // namespace libabckit 237 238 // CC-OFFNXT(G.PRE.02) necessary macro 239 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage) 240 #define LIBABCKIT_LOG_STREAM(level) libabckit::Logger::Message(#level) 241 242 // CC-OFFNXT(G.PRE.02) necessary macro 243 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage) 244 #define LIBABCKIT_LOG(level) LIBABCKIT_LOG_(level) 245 246 // CC-OFFNXT(G.PRE.02) necessary macro 247 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage) 248 #define LIBABCKIT_LOG_NO_FUNC(level) LIBABCKIT_LOG_NO_FUNC_(level) 249 250 // CC-OFFNXT(G.DCL.01) public API 251 // CC-OFFNXT(G.PRE.02) necessary macro 252 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage) 253 #define LIBABCKIT_LOG_(level) \ 254 libabckit::Logger::Initialize(libabckit::Logger::MODE::RELEASE_MODE); \ 255 *LIBABCKIT_LOG_STREAM(level) << libabckit::Logger::msgPrefix_ << "[" << LIBABCKIT_FUNC_NAME << "] " 256 257 // CC-OFFNXT(G.DCL.01) public API 258 // CC-OFFNXT(G.PRE.02) necessary macro 259 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage) 260 #define LIBABCKIT_LOG_NO_FUNC_(level) \ 261 libabckit::Logger::Initialize(libabckit::Logger::MODE::RELEASE_MODE); \ 262 *LIBABCKIT_LOG_STREAM(level) << libabckit::Logger::msgPrefix_ 263 264 // CC-OFFNXT(G.PRE.02) necessary macro 265 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage) 266 #define LIBABCKIT_LOG_DUMP(dump, level) \ 267 do { \ 268 if (libabckit::Logger::CheckPermission(#level)) { \ 269 dump; \ 270 } \ 271 } while (0) 272 273 // CC-OFFNXT(G.PRE.09) code generation 274 // CC-OFFNXT(G.PRE.02) necessary macro 275 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage) 276 #define LIBABCKIT_LOG_FUNC LIBABCKIT_LOG(DEBUG) << '\n' 277 278 // CC-OFFNXT(G.PRE.09) code generation 279 // CC-OFFNXT(G.PRE.02) necessary macro 280 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage) 281 #define LIBABCKIT_IMPLEMENTED LIBABCKIT_LOG(DEBUG) << "implemented\n" 282 283 // CC-OFFNXT(G.PRE.09) code generation 284 // CC-OFFNXT(G.PRE.02) necessary macro 285 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage) 286 #define LIBABCKIT_UNIMPLEMENTED \ 287 LIBABCKIT_LOG(DEBUG) << "is not implemented yet!\n"; \ 288 abort() 289 290 // CC-OFFNXT(G.PRE.09) code generation 291 // CC-OFFNXT(G.PRE.02) necessary macro 292 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage) 293 #define LIBABCKIT_UNREACHABLE \ 294 LIBABCKIT_LOG(DEBUG) << "unreachable!\n"; \ 295 abort() 296 297 // CC-OFFNXT(G.PRE.02) necessary macro 298 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage) 299 #define LIBABCKIT_PREFIX_TEST "[ LIBABCKIT TEST ]" 300 301 // CC-OFFNXT(G.PRE.02) necessary macro 302 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage) 303 #define LIBABCKIT_LOG_TEST(level) \ 304 libabckit::Logger::Initialize(libabckit::Logger::MODE::RELEASE_MODE); \ 305 *LIBABCKIT_LOG_STREAM(level) << LIBABCKIT_PREFIX_TEST << "[" << LIBABCKIT_FUNC_NAME << "] " \ 306 << " " 307 308 // CC-OFFNXT(G.PRE.02) necessary macro 309 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage) 310 #define LIBABCKIT_UNREACHABLE_TEST(level) \ 311 LIBABCKIT_LOG_TEST(level) << "UNREACHABLE!\n"; \ 312 abort() 313 314 #endif 315