kaldi-error.h
9.35 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
// 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.
#ifndef NDEBUG
#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_