log.h (11282B)
1 /** 2 * Copyright (c) 2022 Xiaomi Corporation (authors: Fangjun Kuang) 3 * 4 * See LICENSE for clarification regarding multiple authors 5 * 6 * Licensed under the Apache License, Version 2.0 (the "License"); 7 * you may not use this file except in compliance with the License. 8 * You may obtain a copy of the License at 9 * 10 * http://www.apache.org/licenses/LICENSE-2.0 11 * 12 * Unless required by applicable law or agreed to in writing, software 13 * distributed under the License is distributed on an "AS IS" BASIS, 14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 * See the License for the specific language governing permissions and 16 * limitations under the License. 17 */ 18 19 // The content in this file is copied/modified from 20 // https://github.com/k2-fsa/k2/blob/master/k2/csrc/log.h 21 #ifndef KALDI_NATIVE_FBANK_CSRC_LOG_H_ 22 #define KALDI_NATIVE_FBANK_CSRC_LOG_H_ 23 24 #include <stdio.h> 25 26 #include <mutex> // NOLINT 27 #include <sstream> 28 #include <string> 29 30 namespace knf { 31 32 #if KNF_ENABLE_CHECK 33 34 #if defined(NDEBUG) 35 constexpr bool kDisableDebug = true; 36 #else 37 constexpr bool kDisableDebug = false; 38 #endif 39 40 enum class LogLevel { 41 kTrace = 0, 42 kDebug = 1, 43 kInfo = 2, 44 kWarning = 3, 45 kError = 4, 46 kFatal = 5, // print message and abort the program 47 }; 48 49 // They are used in KNF_LOG(xxx), so their names 50 // do not follow the google c++ code style 51 // 52 // You can use them in the following way: 53 // 54 // KNF_LOG(TRACE) << "some message"; 55 // KNF_LOG(DEBUG) << "some message"; 56 #ifndef _MSC_VER 57 constexpr LogLevel TRACE = LogLevel::kTrace; 58 constexpr LogLevel DEBUG = LogLevel::kDebug; 59 constexpr LogLevel INFO = LogLevel::kInfo; 60 constexpr LogLevel WARNING = LogLevel::kWarning; 61 constexpr LogLevel ERROR = LogLevel::kError; 62 constexpr LogLevel FATAL = LogLevel::kFatal; 63 #else 64 #define TRACE LogLevel::kTrace 65 #define DEBUG LogLevel::kDebug 66 #define INFO LogLevel::kInfo 67 #define WARNING LogLevel::kWarning 68 #define ERROR LogLevel::kError 69 #define FATAL LogLevel::kFatal 70 #endif 71 72 std::string GetStackTrace(); 73 74 /* Return the current log level. 75 76 77 If the current log level is TRACE, then all logged messages are printed out. 78 79 If the current log level is DEBUG, log messages with "TRACE" level are not 80 shown and all other levels are printed out. 81 82 Similarly, if the current log level is INFO, log message with "TRACE" and 83 "DEBUG" are not shown and all other levels are printed out. 84 85 If it is FATAL, then only FATAL messages are shown. 86 */ 87 inline LogLevel GetCurrentLogLevel() { 88 static LogLevel log_level = INFO; 89 static std::once_flag init_flag; 90 std::call_once(init_flag, []() { 91 const char *env_log_level = std::getenv("KNF_LOG_LEVEL"); 92 if (env_log_level == nullptr) return; 93 94 std::string s = env_log_level; 95 if (s == "TRACE") 96 log_level = TRACE; 97 else if (s == "DEBUG") 98 log_level = DEBUG; 99 else if (s == "INFO") 100 log_level = INFO; 101 else if (s == "WARNING") 102 log_level = WARNING; 103 else if (s == "ERROR") 104 log_level = ERROR; 105 else if (s == "FATAL") 106 log_level = FATAL; 107 else 108 fprintf(stderr, 109 "Unknown KNF_LOG_LEVEL: %s" 110 "\nSupported values are: " 111 "TRACE, DEBUG, INFO, WARNING, ERROR, FATAL", 112 s.c_str()); 113 }); 114 return log_level; 115 } 116 117 inline bool EnableAbort() { 118 static std::once_flag init_flag; 119 static bool enable_abort = false; 120 std::call_once(init_flag, []() { 121 enable_abort = (std::getenv("KNF_ABORT") != nullptr); 122 }); 123 return enable_abort; 124 } 125 126 class Logger { 127 public: 128 Logger(const char *filename, const char *func_name, uint32_t line_num, 129 LogLevel level) 130 : filename_(filename), 131 func_name_(func_name), 132 line_num_(line_num), 133 level_(level) { 134 cur_level_ = GetCurrentLogLevel(); 135 fprintf(stderr, "here\n"); 136 switch (level) { 137 case TRACE: 138 if (cur_level_ <= TRACE) fprintf(stderr, "[T] "); 139 break; 140 case DEBUG: 141 if (cur_level_ <= DEBUG) fprintf(stderr, "[D] "); 142 break; 143 case INFO: 144 if (cur_level_ <= INFO) fprintf(stderr, "[I] "); 145 break; 146 case WARNING: 147 if (cur_level_ <= WARNING) fprintf(stderr, "[W] "); 148 break; 149 case ERROR: 150 if (cur_level_ <= ERROR) fprintf(stderr, "[E] "); 151 break; 152 case FATAL: 153 if (cur_level_ <= FATAL) fprintf(stderr, "[F] "); 154 break; 155 } 156 157 if (cur_level_ <= level_) { 158 fprintf(stderr, "%s:%u:%s ", filename, line_num, func_name); 159 } 160 } 161 162 ~Logger() noexcept(false) { 163 static constexpr const char *kErrMsg = R"( 164 Some bad things happened. Please read the above error messages and stack 165 trace. If you are using Python, the following command may be helpful: 166 167 gdb --args python /path/to/your/code.py 168 169 (You can use `gdb` to debug the code. Please consider compiling 170 a debug version of KNF.). 171 172 If you are unable to fix it, please open an issue at: 173 174 https://github.com/csukuangfj/kaldi-native-fbank/issues/new 175 )"; 176 fprintf(stderr, "\n"); 177 if (level_ == FATAL) { 178 std::string stack_trace = GetStackTrace(); 179 if (!stack_trace.empty()) { 180 fprintf(stderr, "\n\n%s\n", stack_trace.c_str()); 181 } 182 183 fflush(nullptr); 184 185 #ifndef __ANDROID_API__ 186 if (EnableAbort()) { 187 // NOTE: abort() will terminate the program immediately without 188 // printing the Python stack backtrace. 189 abort(); 190 } 191 192 throw std::runtime_error(kErrMsg); 193 #else 194 abort(); 195 #endif 196 } 197 } 198 199 const Logger &operator<<(bool b) const { 200 if (cur_level_ <= level_) { 201 fprintf(stderr, b ? "true" : "false"); 202 } 203 return *this; 204 } 205 206 const Logger &operator<<(int8_t i) const { 207 if (cur_level_ <= level_) fprintf(stderr, "%d", i); 208 return *this; 209 } 210 211 const Logger &operator<<(const char *s) const { 212 if (cur_level_ <= level_) fprintf(stderr, "%s", s); 213 return *this; 214 } 215 216 const Logger &operator<<(int32_t i) const { 217 if (cur_level_ <= level_) fprintf(stderr, "%d", i); 218 return *this; 219 } 220 221 const Logger &operator<<(uint32_t i) const { 222 if (cur_level_ <= level_) fprintf(stderr, "%u", i); 223 return *this; 224 } 225 226 const Logger &operator<<(uint64_t i) const { 227 if (cur_level_ <= level_) 228 fprintf(stderr, "%llu", (long long unsigned int)i); // NOLINT 229 return *this; 230 } 231 232 const Logger &operator<<(int64_t i) const { 233 if (cur_level_ <= level_) 234 fprintf(stderr, "%lli", (long long int)i); // NOLINT 235 return *this; 236 } 237 238 const Logger &operator<<(float f) const { 239 if (cur_level_ <= level_) fprintf(stderr, "%f", f); 240 return *this; 241 } 242 243 const Logger &operator<<(double d) const { 244 if (cur_level_ <= level_) fprintf(stderr, "%f", d); 245 return *this; 246 } 247 248 template <typename T> 249 const Logger &operator<<(const T &t) const { 250 // require T overloads operator<< 251 std::ostringstream os; 252 os << t; 253 return *this << os.str().c_str(); 254 } 255 256 // specialization to fix compile error: `stringstream << nullptr` is ambiguous 257 const Logger &operator<<(const std::nullptr_t &null) const { 258 if (cur_level_ <= level_) *this << "(null)"; 259 return *this; 260 } 261 262 private: 263 const char *filename_; 264 const char *func_name_; 265 uint32_t line_num_; 266 LogLevel level_; 267 LogLevel cur_level_; 268 }; 269 #endif // KNF_ENABLE_CHECK 270 271 class Voidifier { 272 public: 273 #if KNF_ENABLE_CHECK 274 void operator&(const Logger &) const {} 275 #endif 276 }; 277 #if !defined(KNF_ENABLE_CHECK) 278 template <typename T> 279 const Voidifier &operator<<(const Voidifier &v, T &&) { 280 return v; 281 } 282 #endif 283 284 } // namespace knf 285 286 #define KNF_STATIC_ASSERT(x) static_assert(x, "") 287 288 #ifdef KNF_ENABLE_CHECK 289 290 #if defined(__clang__) || defined(__GNUC__) || defined(__GNUG__) || \ 291 defined(__PRETTY_FUNCTION__) 292 // for clang and GCC 293 #define KNF_FUNC __PRETTY_FUNCTION__ 294 #else 295 // for other compilers 296 #define KNF_FUNC __func__ 297 #endif 298 299 #define KNF_CHECK(x) \ 300 (x) ? (void)0 \ 301 : ::knf::Voidifier() & \ 302 ::knf::Logger(__FILE__, KNF_FUNC, __LINE__, ::knf::FATAL) \ 303 << "Check failed: " << #x << " " 304 305 // WARNING: x and y may be evaluated multiple times, but this happens only 306 // when the check fails. Since the program aborts if it fails, we don't think 307 // the extra evaluation of x and y matters. 308 // 309 // CAUTION: we recommend the following use case: 310 // 311 // auto x = Foo(); 312 // auto y = Bar(); 313 // KNF_CHECK_EQ(x, y) << "Some message"; 314 // 315 // And please avoid 316 // 317 // KNF_CHECK_EQ(Foo(), Bar()); 318 // 319 // if `Foo()` or `Bar()` causes some side effects, e.g., changing some 320 // local static variables or global variables. 321 #define _KNF_CHECK_OP(x, y, op) \ 322 ((x)op(y)) ? (void)0 \ 323 : ::knf::Voidifier() & \ 324 ::knf::Logger(__FILE__, KNF_FUNC, __LINE__, ::knf::FATAL) \ 325 << "Check failed: " << #x << " " << #op << " " << #y \ 326 << " (" << (x) << " vs. " << (y) << ") " 327 328 #define KNF_CHECK_EQ(x, y) _KNF_CHECK_OP(x, y, ==) 329 #define KNF_CHECK_NE(x, y) _KNF_CHECK_OP(x, y, !=) 330 #define KNF_CHECK_LT(x, y) _KNF_CHECK_OP(x, y, <) 331 #define KNF_CHECK_LE(x, y) _KNF_CHECK_OP(x, y, <=) 332 #define KNF_CHECK_GT(x, y) _KNF_CHECK_OP(x, y, >) 333 #define KNF_CHECK_GE(x, y) _KNF_CHECK_OP(x, y, >=) 334 335 #define KNF_LOG(x) ::knf::Logger(__FILE__, KNF_FUNC, __LINE__, ::knf::x) 336 337 // ------------------------------------------------------------ 338 // For debug check 339 // ------------------------------------------------------------ 340 // If you define the macro "-D NDEBUG" while compiling kaldi-native-fbank, 341 // the following macros are in fact empty and does nothing. 342 343 #define KNF_DCHECK(x) ::knf::kDisableDebug ? (void)0 : KNF_CHECK(x) 344 345 #define KNF_DCHECK_EQ(x, y) ::knf::kDisableDebug ? (void)0 : KNF_CHECK_EQ(x, y) 346 347 #define KNF_DCHECK_NE(x, y) ::knf::kDisableDebug ? (void)0 : KNF_CHECK_NE(x, y) 348 349 #define KNF_DCHECK_LT(x, y) ::knf::kDisableDebug ? (void)0 : KNF_CHECK_LT(x, y) 350 351 #define KNF_DCHECK_LE(x, y) ::knf::kDisableDebug ? (void)0 : KNF_CHECK_LE(x, y) 352 353 #define KNF_DCHECK_GT(x, y) ::knf::kDisableDebug ? (void)0 : KNF_CHECK_GT(x, y) 354 355 #define KNF_DCHECK_GE(x, y) ::knf::kDisableDebug ? (void)0 : KNF_CHECK_GE(x, y) 356 357 #define KNF_DLOG(x) \ 358 ::knf::kDisableDebug ? (void)0 : ::knf::Voidifier() & KNF_LOG(x) 359 360 #else 361 362 #define KNF_CHECK(x) ::knf::Voidifier() 363 #define KNF_LOG(x) ::knf::Voidifier() 364 365 #define KNF_CHECK_EQ(x, y) ::knf::Voidifier() 366 #define KNF_CHECK_NE(x, y) ::knf::Voidifier() 367 #define KNF_CHECK_LT(x, y) ::knf::Voidifier() 368 #define KNF_CHECK_LE(x, y) ::knf::Voidifier() 369 #define KNF_CHECK_GT(x, y) ::knf::Voidifier() 370 #define KNF_CHECK_GE(x, y) ::knf::Voidifier() 371 372 #define KNF_DCHECK(x) ::knf::Voidifier() 373 #define KNF_DLOG(x) ::knf::Voidifier() 374 #define KNF_DCHECK_EQ(x, y) ::knf::Voidifier() 375 #define KNF_DCHECK_NE(x, y) ::knf::Voidifier() 376 #define KNF_DCHECK_LT(x, y) ::knf::Voidifier() 377 #define KNF_DCHECK_LE(x, y) ::knf::Voidifier() 378 #define KNF_DCHECK_GT(x, y) ::knf::Voidifier() 379 #define KNF_DCHECK_GE(x, y) ::knf::Voidifier() 380 381 #endif // KNF_CHECK_NE 382 383 #endif // KALDI_NATIVE_FBANK_CSRC_LOG_H_