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