• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2023 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 MAPLE_UTIL_INCLUDE_MPL_LOGGING_H
17 #define MAPLE_UTIL_INCLUDE_MPL_LOGGING_H
18 
19 #include <string>
20 #include <cstdio>
21 #include <stdarg.h>
22 #include <sstream>
23 #include <iostream>
24 
25 // This file defines the APIs that govern all messaging-styled output from
26 // a running program under MAPLE, which can be a compiler or a runtime component.
27 //
28 // There are two overall classes of messages:
29 //
30 // (1) Those of interest only to developers, and thus should be suppressed in the
31 // production release version of the software.  The message content will include
32 // the source file and line number of the trigger point of the message.
33 //
34 // (2) Those intended to be visible to users of the software in general,  in
35 // addition to the developers.
36 //
37 // Messages are divided into 6 types, or levels, from 0 to 5.  Conceptually,
38 // the lower the level, the higher the frequency of occurrences, the larger the
39 // output volume, the smaller the audience of interest and the more often they need
40 // to be filtered out. In addition, the higher the level, the greater the severity.
41 //
42 // Level 0 (DBG) - These are messages for debugging purposes, used by the
43 // developer during development to debug his code.
44 //
45 // Level 1 (LOG) - These are log messages, also for helping the developer in
46 // debugging, but at a higher level of algorithmic operation.
47 //
48 // Level 2 (INFO) - These provide information that are of general usefulness in
49 // the normal operation of the SW.
50 //
51 // Level 3 (WARN) - These provide warning messages.
52 //
53 // Level 4 (ERR) - These provide error messages.
54 //
55 // Level 5 (FATAL) - These indicate errors of such severity that the program r
56 // execution cannot continue.
57 //
58 // DBG and LOG are only for developers' use.  INFO, WARN, ERR and FATAL are
59 // intended for general visibility.  There is an additional type of ERR that
60 // designate developer errors that arise out of checking code inserted by the
61 // developers, which has the following 4 usage patterns:
62 //
63 // CHECK - If the specified program condition is not satisfied, output the error
64 // message. The program will continue execution.
65 //
66 // DCHECK - Same as CHECK, but the check is suppressed in the release version of
67 // the SW.
68 //
69 // CHECK_FATAL - If the specified program condition is not satisfied, output the error
70 // message. The program will stop execution at that point.
71 //
72 // DEBUG_ASSERT - Same as CHECK_FATAL, but the check is suppressed in the release version of
73 // the SW.
74 //
75 // The macro setting DEBUG=1 picks developer and DEBUG=0 picks release builds.
76 //
77 // the macro PRINT_LEVEL_DEV is a filter for DBG messages in developer builds.
78 // When PRINT_LEVEL_DEV is set to kLlLog, DBG messages are not printed.
79 //
80 // Instantiated object c_logInfo, of class LogInfo, provides finer control of
81 // the logging behavior during execution.  Use emitLogDevice() to change the
82 // message destination.  Use setLogMode() to change the verbosity of the messages.
83 //
84 // In the case of DBG and LOG, the message needs to print the name of the SW
85 // component as the volume of messages can be huge.  Use enum LOG_TAGS to define
86 // the component ID and its name string.
87 //
88 // Since INFO, WARN, ERR and FATAL are for general consumption, each message
89 // should provide an number code under enum LogNumberCode.
90 //
91 // Following are usage of logging actions supported:
92 //
93 // GDB,LOG,INFO,WARN,ERR,FATAL can be invoked as method.
94 //   parameters:
95 //     TAG
96 //     formatted string
97 //     variadic list
98 //
99 // CHECK,DCHECK,CHECK_FATAL,DEBUG_ASSERT also can be invoked as method.
100 //   parameters:
101 //     condition
102 //     formatted string
103 //     variadic list
104 //
105 // Each of the above are mapped to one of the following 3 methods in class LogInfo:
106 //
107 // EmitLogForDev() - for DBG and LOG
108 //
109 // EmitLogForUser() - for INFO, WARN, ERR and FATAL
110 //
111 // EmitErrorMessage() - for CHECK, DCHECK, CHECK_FATAL and DEBUG_ASSERT
112 //
113 // DBG and LOG send their messages to stdout, and provide additional date and time
114 // information.  For the rest, the messages are sent to stderr.
115 //
116 // In debugging the program, the developer can set breakpoint in one of the above
117 // 3 methods depending on the type of message. For DEBUG_ASSERT, abort() is called
118 // instead of exit(1) so that the program will not completely exit, to allow the
119 // developer to print stack trace and peruse the program environment at the point
120 // of the assertion.
121 namespace maple {
122 extern class LogInfo logInfo;
123 extern class LogInfo &log;
124 
125 enum LogLevel { kLlDbg, kLlLog, kLlInfo, kLlWarn, kLlErr, kLlFatal, kLlMax };
126 
127 enum LogTags { kLtThread, kLtLooper, kLtAll };
128 
129 enum LogMode { kLmSimple, kLmComplex, kLmMax };
130 
131 enum LogNumberCode { kLncInfo = 0, kLncWarn = 20, kLncErr = 40, kLncFatal = 60, kLncMax = 99 };
132 
133 class LogInfo {
134 public:
LogInfo()135     LogInfo() : outStream(stdout), outMode(kLmComplex) {}
136     LogInfo(const LogInfo &p) = delete;
137     LogInfo &operator=(const LogInfo &p) = delete;
138 
~LogInfo()139     ~LogInfo()
140     {
141         (void)fclose(outStream);
142     }
143 
144     static std::ostream &MapleLogger(LogLevel level = kLlLog);
145     void EmitLogForUser(enum LogNumberCode num, enum LogLevel ll, const char *fmt, ...) const;
146     void EmitLogForUser(enum LogNumberCode num, enum LogLevel ll, const std::string &message) const;
147     void EmitErrorMessage(const std::string &cond, const std::string &file, unsigned int line, const char *fmt,
148                           ...) const;
149 
150 private:
SetLogDevice(FILE & stream)151     void SetLogDevice(FILE &stream)
152     {
153         outStream = &stream;
154     }
SetLogMode(LogMode lm)155     void SetLogMode(LogMode lm)
156     {
157         outMode = lm;
158     }
159     FILE *outStream;
160     LogMode outMode;
161 };
162 
163 #ifdef DEBUG // no debug in default
164 #define DEBUG_STMT(x) x
165 #define DEBUG_TEST 1
166 #define ENABLE_ASSERT 1
167 #else
168 #define DEBUG_STMT(x)
169 #define DEBUG_TEST 0
170 #define ENABLE_ASSERT 0
171 #endif  // DEBUG
172 
173 // for developer
174 #define PRINT_LEVEL_DEV kLlLog
175 
176 #ifndef IS_RELEASE_VERSION
177 #define DBG(tag, fmt, ...)                                                                                 \
178     do {                                                                                                   \
179         if (PRINT_LEVEL_DEV <= kLlLog) {                                                                   \
180             logInfo.EmitLogForDev(tag, kLlLog, __FILE_NAME__, __FUNCTION__, __LINE__, fmt, ##__VA_ARGS__); \
181         }                                                                                                  \
182     } while (0)
183 #else
184 #define DBG(tag, fmt, ...)
185 #endif // IS_RELEASE_VERSION
186 
187 #ifdef CHECK
188 #undef CHECK
189 #endif
190 
191 #ifndef IS_RELEASE_VERSION
192 #define CHECK(cond, fmt, ...)                                                                  \
193     do {                                                                                       \
194         if (!(cond)) {                                                                         \
195             logInfo.EmitErrorMessage(#cond, __FILE_NAME__, __LINE__, fmt "\n", ##__VA_ARGS__); \
196         }                                                                                      \
197     } while (0)
198 #else
199 #define CHECK(cond, fmt, ...)                                                                  \
200     do {                                                                                       \
201         if (!(cond)) {}                                                                        \
202     } while (0)
203 #endif // IS_RELEASE_VERSION
204 
205 #ifdef DCHECK
206 #undef DCHECK
207 #endif
208 #define DCHECK(cond, fmt, ...)                       \
209     do {                                             \
210         DEBUG_STMT(CHECK(cond, fmt, ##__VA_ARGS__)); \
211     } while (0)
212 
213 // To shut down the codecheck warning: boolean condition for 'if' always evaluates to 'true'
214 #ifndef IS_RELEASE_VERSION
215 #define CHECK_FATAL_FALSE(fmt, ...)                                                                 \
216     do {                                                                                            \
217         maple::logInfo.EmitErrorMessage("false", __FILE_NAME__, __LINE__, fmt "\n", ##__VA_ARGS__); \
218         exit(1);                                                                                    \
219     } while (0)
220 
221 #define CHECK_FATAL(cond, fmt, ...)                                                                   \
222     do {                                                                                              \
223         if (!(cond)) {                                                                                \
224             maple::logInfo.EmitErrorMessage(#cond, __FILE_NAME__, __LINE__, fmt "\n", ##__VA_ARGS__); \
225             if (DEBUG_TEST != 0) {                                                                    \
226                 abort();                                                                              \
227             } else {                                                                                  \
228                 exit(1);                                                                              \
229             }                                                                                         \
230         }                                                                                             \
231     } while (0)
232 #else
233 #define CHECK_FATAL_FALSE(fmt, ...)                                                            \
234     do {                                                                                       \
235         exit(1);                                                                               \
236     } while (0)
237 
238 #define CHECK_FATAL(cond, fmt, ...)                                                              \
239     do {                                                                                         \
240         if (!(cond)) {                                                                           \
241             if (DEBUG_TEST != 0) {                                                               \
242                 abort();                                                                         \
243             } else {                                                                             \
244                 exit(1);                                                                         \
245             }                                                                                    \
246         }                                                                                        \
247     } while (0)
248 #endif // IS_RELEASE_VERSION
249 
250 #define CHECK_NULL_FATAL(ptr) CHECK_FATAL((ptr) != nullptr, "Failed with nullptr.")
251 
252 #if ENABLE_ASSERT // assert not enabled in default
253 #define DEBUG_ASSERT(cond, fmt, ...)                                                                  \
254     do {                                                                                              \
255         if (!(cond)) {                                                                                \
256             maple::logInfo.EmitErrorMessage(#cond, __FILE_NAME__, __LINE__, fmt "\n", ##__VA_ARGS__); \
257             abort();                                                                                  \
258         }                                                                                             \
259     } while (0)
260 
261 #define ASSERT_NOT_NULL(ptr) DEBUG_ASSERT((ptr) != nullptr, "Failed with nullptr.")
262 #else
263 #define DEBUG_ASSERT(cond, fmt, ...)
264 #define ASSERT_NOT_NULL(ptr)
265 #endif  // ENABLE_ASSERT
266 
267 // for user
268 #define PRINT_LEVEL_USER kLlInfo
269 
270 #define INFO(num, fmt, ...)                                           \
271     do {                                                              \
272         if (PRINT_LEVEL_USER <= kLlInfo) {                            \
273             logInfo.EmitLogForUser(num, kLlInfo, fmt, ##__VA_ARGS__); \
274         }                                                             \
275     } while (0)
276 
277 #define INFO_V(verbose, num, fmt, ...)                                \
278     if (verbose) {                                                    \
279         if (PRINT_LEVEL_USER <= kLlInfo) {                            \
280             logInfo.EmitLogForUser(num, kLlInfo, fmt, ##__VA_ARGS__); \
281         }                                                             \
282     }
283 
284 #define WARN(num, fmt, ...)                                           \
285     do {                                                              \
286         if (PRINT_LEVEL_USER <= kLlWarn) {                            \
287             logInfo.EmitLogForUser(num, kLlWarn, fmt, ##__VA_ARGS__); \
288         }                                                             \
289     } while (0)
290 
291 #define ERR(num, fmt, ...)                                           \
292     do {                                                             \
293         if (PRINT_LEVEL_USER <= kLlErr) {                            \
294             logInfo.EmitLogForUser(num, kLlErr, fmt, ##__VA_ARGS__); \
295         }                                                            \
296     } while (0)
297 
298 #define FATAL(num, fmt, ...)                                           \
299     do {                                                               \
300         if (PRINT_LEVEL_USER <= kLlFatal) {                            \
301             logInfo.EmitLogForUser(num, kLlFatal, fmt, ##__VA_ARGS__); \
302         }                                                              \
303         if (DEBUG_TEST != 0) {                                         \
304             abort();                                                   \
305         } else {                                                       \
306             exit(1);                                                   \
307         }                                                              \
308     } while (0)
309 }  // namespace maple
310 #endif  // MAPLE_UTIL_INCLUDE_MPL_LOGGING_H
311