• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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