• 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     static std::ostream &Info();
138     static std::ostream &Err();
139     LogInfo &operator=(const LogInfo &p) = delete;
140 
~LogInfo()141     ~LogInfo()
142     {
143         fclose(outStream);
144     }
145 
146     static std::ostream &MapleLogger(LogLevel level = kLlLog);
147     static std::ios::fmtflags Flags();
148     void EmitLogForUser(enum LogNumberCode num, enum LogLevel ll, const char *fmt, ...) const;
149     void EmitLogForUser(enum LogNumberCode num, enum LogLevel ll, const std::string &message) const;
150     void EmitErrorMessage(const std::string &cond, const std::string &file, unsigned int line, const char *fmt,
151                           ...) const;
152 
153 private:
SetLogDevice(FILE & stream)154     void SetLogDevice(FILE &stream)
155     {
156         outStream = &stream;
157     }
SetLogMode(LogMode lm)158     void SetLogMode(LogMode lm)
159     {
160         outMode = lm;
161     }
162     void EmitLogForDevelop(enum LogTags tag, enum LogLevel ll, const std::string &file, const std::string &func,
163                            int line, const char *fmt, ...);
164     FILE *outStream;
165     LogMode outMode;
166 };
167 
168 #ifdef DEBUG
169 #define DEBUG_STMT(x) x
170 #define DEBUG_TEST 1
171 #define ENABLE_ASSERT 1
172 #else
173 #define DEBUG_STMT(x)
174 #define DEBUG_TEST 0
175 #define ENABLE_ASSERT 0
176 #endif  // DEBUG
177 
178 // for developer
179 #define PRINT_LEVEL_DEV kLlLog
180 
181 #define DBG(tag, fmt, ...)                                                                            \
182     do {                                                                                              \
183         if (PRINT_LEVEL_DEV <= kLlLog) {                                                              \
184             logInfo.EmitLogForDev(tag, kLlLog, __FILE__, __FUNCTION__, __LINE__, fmt, ##__VA_ARGS__); \
185         }                                                                                             \
186     } while (0)
187 
188 // #ifdef LOG
189 // #undef LOG
190 // #endif
191 // #define LOG(tag, fmt, ...)                                                                      \
192 //   do {                                                                                          \
193 //     if (PRINT_LEVEL_DEV <= kLlLog) {                                                            \
194 //       logInfo.EmitLogForDev(tag, kLlLog, __FILE__, __FUNCTION__, __LINE__, fmt, ##__VA_ARGS__); \
195 //     }                                                                                                \
196 //   } while (0)
197 
198 #ifdef CHECK
199 #undef CHECK
200 #endif
201 #define CHECK(cond, fmt, ...)                                                             \
202     do {                                                                                  \
203         if (!(cond)) {                                                                    \
204             logInfo.EmitErrorMessage(#cond, __FILE__, __LINE__, fmt "\n", ##__VA_ARGS__); \
205         }                                                                                 \
206     } while (0)
207 
208 #ifdef DCHECK
209 #undef DCHECK
210 #endif
211 #define DCHECK(cond, fmt, ...)                       \
212     do {                                             \
213         DEBUG_STMT(CHECK(cond, fmt, ##__VA_ARGS__)); \
214     } while (0)
215 
216 #define CHECK_FATAL(cond, fmt, ...)                                                              \
217     do {                                                                                         \
218         if (!(cond)) {                                                                           \
219             maple::logInfo.EmitErrorMessage(#cond, __FILE__, __LINE__, fmt "\n", ##__VA_ARGS__); \
220             if (DEBUG_TEST != 0) {                                                               \
221                 abort();                                                                         \
222             } else {                                                                             \
223                 exit(1);                                                                         \
224             }                                                                                    \
225         }                                                                                        \
226     } while (0)
227 
228 #define CHECK_NULL_FATAL(ptr) CHECK_FATAL((ptr) != nullptr, "Failed with nullptr.")
229 
230 #if ENABLE_ASSERT
231 #define DEBUG_ASSERT(cond, fmt, ...)                                                             \
232     do {                                                                                         \
233         if (!(cond)) {                                                                           \
234             maple::logInfo.EmitErrorMessage(#cond, __FILE__, __LINE__, fmt "\n", ##__VA_ARGS__); \
235             abort();                                                                             \
236         }                                                                                        \
237     } while (0)
238 
239 #define ASSERT_NOT_NULL(ptr) DEBUG_ASSERT((ptr) != nullptr, "Failed with nullptr.")
240 #else
241 #define DEBUG_ASSERT(cond, fmt, ...)
242 #define ASSERT_NOT_NULL(ptr)
243 #endif  // ENABLE_ASSERT
244 
245 // for user
246 #define PRINT_LEVEL_USER kLlInfo
247 
248 #define INFO(num, fmt, ...)                                           \
249     do {                                                              \
250         if (PRINT_LEVEL_USER <= kLlInfo) {                            \
251             logInfo.EmitLogForUser(num, kLlInfo, fmt, ##__VA_ARGS__); \
252         }                                                             \
253     } while (0)
254 
255 #define INFO_V(verbose, num, fmt, ...)                                \
256     if (verbose) {                                                    \
257         if (PRINT_LEVEL_USER <= kLlInfo) {                            \
258             logInfo.EmitLogForUser(num, kLlInfo, fmt, ##__VA_ARGS__); \
259         }                                                             \
260     }
261 
262 #define WARN(num, fmt, ...)                                           \
263     do {                                                              \
264         if (PRINT_LEVEL_USER <= kLlWarn) {                            \
265             logInfo.EmitLogForUser(num, kLlWarn, fmt, ##__VA_ARGS__); \
266         }                                                             \
267     } while (0)
268 
269 #define ERR(num, fmt, ...)                                           \
270     do {                                                             \
271         if (PRINT_LEVEL_USER <= kLlErr) {                            \
272             logInfo.EmitLogForUser(num, kLlErr, fmt, ##__VA_ARGS__); \
273         }                                                            \
274     } while (0)
275 
276 #define FATAL(num, fmt, ...)                                           \
277     do {                                                               \
278         if (PRINT_LEVEL_USER <= kLlFatal) {                            \
279             logInfo.EmitLogForUser(num, kLlFatal, fmt, ##__VA_ARGS__); \
280         }                                                              \
281         if (DEBUG_TEST != 0) {                                         \
282             abort();                                                   \
283         } else {                                                       \
284             exit(1);                                                   \
285         }                                                              \
286     } while (0)
287 }  // namespace maple
288 #endif  // MAPLE_UTIL_INCLUDE_MPL_LOGGING_H
289