janitor

janitor
git clone https://git.prime8.dev/janitor.git
Log | Files | Refs | README | LICENSE

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_