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