You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
232 lines
9.3 KiB
232 lines
9.3 KiB
// base/kaldi-error.h
|
|
|
|
// Copyright 2019 LAIX (Yi Sun)
|
|
// Copyright 2019 SmartAction LLC (kkm)
|
|
// Copyright 2016 Brno University of Technology (author: Karel Vesely)
|
|
// Copyright 2009-2011 Microsoft Corporation; Ondrej Glembek; Lukas Burget;
|
|
// Saarland University
|
|
|
|
// See ../../COPYING for clarification regarding multiple authors
|
|
//
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
// you may not use this file except in compliance with the License.
|
|
// You may obtain a copy of the License at
|
|
//
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
//
|
|
// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
|
// KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY IMPLIED
|
|
// WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE,
|
|
// MERCHANTABLITY OR NON-INFRINGEMENT.
|
|
// See the Apache 2 License for the specific language governing permissions and
|
|
// limitations under the License.
|
|
|
|
#ifndef KALDI_BASE_KALDI_ERROR_H_
|
|
#define KALDI_BASE_KALDI_ERROR_H_ 1
|
|
|
|
#include <cstdio>
|
|
#include <cstring>
|
|
#include <sstream>
|
|
#include <stdexcept>
|
|
#include <string>
|
|
#include <vector>
|
|
|
|
#include "base/kaldi-types.h"
|
|
#include "base/kaldi-utils.h"
|
|
/* Important that this file does not depend on any other kaldi headers. */
|
|
|
|
#ifdef _MSC_VER
|
|
#define __func__ __FUNCTION__
|
|
#endif
|
|
|
|
namespace kaldi {
|
|
|
|
/// \addtogroup error_group
|
|
/// @{
|
|
|
|
/***** PROGRAM NAME AND VERBOSITY LEVEL *****/
|
|
|
|
/// Called by ParseOptions to set base name (no directory) of the executing
|
|
/// program. The name is printed in logging code along with every message,
|
|
/// because in our scripts, we often mix together the stderr of many programs.
|
|
/// This function is very thread-unsafe.
|
|
void SetProgramName(const char *basename);
|
|
|
|
/// This is set by util/parse-options.{h,cc} if you set --verbose=? option.
|
|
/// Do not use directly, prefer {Get,Set}VerboseLevel().
|
|
extern int32 g_kaldi_verbose_level;
|
|
|
|
/// Get verbosity level, usually set via command line '--verbose=' switch.
|
|
inline int32 GetVerboseLevel() { return g_kaldi_verbose_level; }
|
|
|
|
/// This should be rarely used, except by programs using Kaldi as library;
|
|
/// command-line programs set the verbose level automatically from ParseOptions.
|
|
inline void SetVerboseLevel(int32 i) { g_kaldi_verbose_level = i; }
|
|
|
|
/***** KALDI LOGGING *****/
|
|
|
|
/// Log message severity and source location info.
|
|
struct LogMessageEnvelope {
|
|
/// Message severity. In addition to these levels, positive values (1 to 6)
|
|
/// specify verbose logging level. Verbose messages are produced only when
|
|
/// SetVerboseLevel() has been called to set logging level to at least the
|
|
/// corresponding value.
|
|
enum Severity {
|
|
kAssertFailed = -3, //!< Assertion failure. abort() will be called.
|
|
kError = -2, //!< Fatal error. KaldiFatalError will be thrown.
|
|
kWarning = -1, //!< Indicates a recoverable but abnormal condition.
|
|
kInfo = 0, //!< Informational message.
|
|
};
|
|
int severity; //!< A Severity value, or positive verbosity level.
|
|
const char *func; //!< Name of the function invoking the logging.
|
|
const char *file; //!< Source file name with up to 1 leading directory.
|
|
int32 line; //<! Line number in the source file.
|
|
};
|
|
|
|
/// Kaldi fatal runtime error exception. This exception is thrown from any use
|
|
/// of the KALDI_ERR logging macro after the logging function, either set by
|
|
/// SetLogHandler(), or the Kaldi's internal one, has returned.
|
|
class KaldiFatalError : public std::runtime_error {
|
|
public:
|
|
explicit KaldiFatalError(const std::string &message)
|
|
: std::runtime_error(message) {}
|
|
explicit KaldiFatalError(const char *message) : std::runtime_error(message) {}
|
|
|
|
/// Returns the exception name, "kaldi::KaldiFatalError".
|
|
virtual const char *what() const noexcept override {
|
|
return "kaldi::KaldiFatalError";
|
|
}
|
|
|
|
/// Returns the Kaldi error message logged by KALDI_ERR.
|
|
const char *KaldiMessage() const { return std::runtime_error::what(); }
|
|
};
|
|
|
|
// Class MessageLogger is the workhorse behind the KALDI_ASSERT, KALDI_ERR,
|
|
// KALDI_WARN, KALDI_LOG and KALDI_VLOG macros. It formats the message, then
|
|
// either prints it to stderr or passes to the custom logging handler if
|
|
// provided. Then, in case of the error, throws a KaldiFatalError exception, or
|
|
// in case of failed KALDI_ASSERT, calls std::abort().
|
|
class MessageLogger {
|
|
public:
|
|
/// The constructor stores the message's "envelope", a set of data which
|
|
// identifies the location in source which is sending the message to log.
|
|
// The pointers to strings are stored internally, and not owned or copied,
|
|
// so that their storage must outlive this object.
|
|
MessageLogger(LogMessageEnvelope::Severity severity, const char *func,
|
|
const char *file, int32 line);
|
|
|
|
// The stream insertion operator, used in e.g. 'KALDI_LOG << "Message"'.
|
|
template <typename T> MessageLogger &operator<<(const T &val) {
|
|
ss_ << val;
|
|
return *this;
|
|
}
|
|
|
|
// When assigned a MessageLogger, log its contents.
|
|
struct Log final {
|
|
void operator=(const MessageLogger &logger) { logger.LogMessage(); }
|
|
};
|
|
|
|
// When assigned a MessageLogger, log its contents and then throw
|
|
// a KaldiFatalError.
|
|
struct LogAndThrow final {
|
|
[[noreturn]] void operator=(const MessageLogger &logger) {
|
|
logger.LogMessage();
|
|
throw KaldiFatalError(logger.GetMessage());
|
|
}
|
|
};
|
|
|
|
private:
|
|
std::string GetMessage() const { return ss_.str(); }
|
|
void LogMessage() const;
|
|
|
|
LogMessageEnvelope envelope_;
|
|
std::ostringstream ss_;
|
|
};
|
|
|
|
// Logging macros.
|
|
#define KALDI_ERR \
|
|
::kaldi::MessageLogger::LogAndThrow() = ::kaldi::MessageLogger( \
|
|
::kaldi::LogMessageEnvelope::kError, __func__, __FILE__, __LINE__)
|
|
#define KALDI_WARN \
|
|
::kaldi::MessageLogger::Log() = ::kaldi::MessageLogger( \
|
|
::kaldi::LogMessageEnvelope::kWarning, __func__, __FILE__, __LINE__)
|
|
#define KALDI_LOG \
|
|
::kaldi::MessageLogger::Log() = ::kaldi::MessageLogger( \
|
|
::kaldi::LogMessageEnvelope::kInfo, __func__, __FILE__, __LINE__)
|
|
#define KALDI_VLOG(v) \
|
|
if ((v) <= ::kaldi::GetVerboseLevel()) \
|
|
::kaldi::MessageLogger::Log() = \
|
|
::kaldi::MessageLogger((::kaldi::LogMessageEnvelope::Severity)(v), \
|
|
__func__, __FILE__, __LINE__)
|
|
|
|
/***** KALDI ASSERTS *****/
|
|
|
|
[[noreturn]] void KaldiAssertFailure_(const char *func, const char *file,
|
|
int32 line, const char *cond_str);
|
|
|
|
// Note on KALDI_ASSERT and KALDI_PARANOID_ASSERT:
|
|
//
|
|
// A single block {} around if /else does not work, because it causes
|
|
// syntax error (unmatched else block) in the following code:
|
|
//
|
|
// if (condition)
|
|
// KALDI_ASSERT(condition2);
|
|
// else
|
|
// SomethingElse();
|
|
//
|
|
// do {} while(0) -- note there is no semicolon at the end! -- works nicely,
|
|
// and compilers will be able to optimize the loop away (as the condition
|
|
// is always false).
|
|
//
|
|
// Also see KALDI_COMPILE_TIME_ASSERT, defined in base/kaldi-utils.h, and
|
|
// KALDI_ASSERT_IS_INTEGER_TYPE and KALDI_ASSERT_IS_FLOATING_TYPE, also defined
|
|
// there.
|
|
#ifdef PPS_DEBUG
|
|
#define KALDI_ASSERT(cond) \
|
|
do { \
|
|
if (cond) \
|
|
(void)0; \
|
|
else \
|
|
::kaldi::KaldiAssertFailure_(__func__, __FILE__, __LINE__, #cond); \
|
|
} while (0)
|
|
#else
|
|
#define KALDI_ASSERT(cond) (void)0
|
|
#endif
|
|
|
|
// Some more expensive asserts only checked if this defined.
|
|
#ifdef KALDI_PARANOID
|
|
#define KALDI_PARANOID_ASSERT(cond) \
|
|
do { \
|
|
if (cond) \
|
|
(void)0; \
|
|
else \
|
|
::kaldi::KaldiAssertFailure_(__func__, __FILE__, __LINE__, #cond); \
|
|
} while (0)
|
|
#else
|
|
#define KALDI_PARANOID_ASSERT(cond) (void)0
|
|
#endif
|
|
|
|
/***** THIRD-PARTY LOG-HANDLER *****/
|
|
|
|
/// Type of third-party logging function.
|
|
typedef void (*LogHandler)(const LogMessageEnvelope &envelope,
|
|
const char *message);
|
|
|
|
/// Set logging handler. If called with a non-NULL function pointer, the
|
|
/// function pointed by it is called to send messages to a caller-provided log.
|
|
/// If called with a NULL pointer, restores default Kaldi error logging to
|
|
/// stderr. This function is obviously not thread safe; the log handler must be.
|
|
/// Returns a previously set logging handler pointer, or NULL.
|
|
LogHandler SetLogHandler(LogHandler);
|
|
|
|
/// @} end "addtogroup error_group"
|
|
|
|
// Functions within internal is exported for testing only, do not use.
|
|
namespace internal {
|
|
bool LocateSymbolRange(const std::string &trace_name, size_t *begin,
|
|
size_t *end);
|
|
} // namespace internal
|
|
} // namespace kaldi
|
|
|
|
#endif // KALDI_BASE_KALDI_ERROR_H_
|