• 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 
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