All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
kaldi-error.cc
Go to the documentation of this file.
1 // base/kaldi-error.cc
2 
3 // Copyright 2016 Brno University of Technology (author: Karel Vesely)
4 // Copyright 2009-2011 Microsoft Corporation; Lukas Burget; Ondrej Glembek
5 
6 // See ../../COPYING for clarification regarding multiple authors
7 //
8 // Licensed under the Apache License, Version 2.0 (the "License");
9 // you may not use this file except in compliance with the License.
10 // You may obtain a copy of the License at
11 //
12 // http://www.apache.org/licenses/LICENSE-2.0
13 //
14 // THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 // KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY IMPLIED
16 // WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE,
17 // MERCHANTABLITY OR NON-INFRINGEMENT.
18 // See the Apache 2 License for the specific language governing permissions and
19 // limitations under the License.
20 
21 #ifdef HAVE_EXECINFO_H
22 #include <execinfo.h> // To get stack trace in error messages.
23 // If this #include fails there is an error in the Makefile, it does not
24 // support your platform well. Make sure HAVE_EXECINFO_H is undefined,
25 // and the code will compile.
26 #ifdef HAVE_CXXABI_H
27 #include <cxxabi.h> // For name demangling.
28 // Useful to decode the stack trace, but only used if we have execinfo.h
29 #endif // HAVE_CXXABI_H
30 #endif // HAVE_EXECINFO_H
31 
32 #include "base/kaldi-common.h"
33 #include "base/kaldi-error.h"
34 #include "base/version.h"
35 
36 namespace kaldi {
37 
38 /***** GLOBAL VARIABLES FOR LOGGING *****/
39 
41 const char *g_program_name = NULL;
42 static LogHandler g_log_handler = NULL;
43 
44 // If the program name was set (g_program_name != ""), GetProgramName
45 // returns the program name (without the path), e.g. "gmm-align".
46 // Otherwise it returns the empty string "".
47 const char *GetProgramName() {
48  return g_program_name == NULL ? "" : g_program_name;
49 }
50 
51 /***** HELPER FUNCTIONS *****/
52 
53 // Given a filename like "/a/b/c/d/e/f.cc", GetShortFileName
54 // returns "e/f.cc". Does not currently work if backslash is
55 // the filename separator.
56 static const char *GetShortFileName(const char *filename) {
57  const char *last_slash = strrchr(filename, '/');
58  if (!last_slash) {
59  return filename;
60  } else {
61  while (last_slash > filename && last_slash[-1] != '/')
62  last_slash--;
63  return last_slash;
64  }
65 }
66 
67 
68 /***** STACKTRACE *****/
69 
70 static std::string Demangle(std::string trace_name) {
71 #if defined(HAVE_CXXABI_H) && defined(HAVE_EXECINFO_H)
72  // at input the string looks like:
73  // ./kaldi-error-test(_ZN5kaldi13UnitTestErrorEv+0xb) [0x804965d]
74  // We want to extract the name e.g. '_ZN5kaldi13UnitTestErrorEv",
75  // demangle it and return it.
76 
77  // try to locate '(' and '+', take the string in between,
78  size_t begin(trace_name.find("(")),
79  end(trace_name.rfind("+"));
80  if (begin != std::string::npos && end != std::string::npos && begin < end) {
81  trace_name = trace_name.substr(begin+1,end-(begin+1));
82  }
83  // demangle,
84  int status;
85  char *demangled_name = abi::__cxa_demangle(trace_name.c_str(), 0, 0, &status);
86  std::string ans;
87  if (status == 0) {
88  ans = demangled_name;
89  free(demangled_name);
90  } else {
91  ans = trace_name;
92  }
93  // return,
94  return ans;
95 #else
96  return trace_name;
97 #endif
98 }
99 
100 
101 static std::string KaldiGetStackTrace() {
102  std::string ans;
103 #ifdef HAVE_EXECINFO_H
104 #define KALDI_MAX_TRACE_SIZE 50
105 #define KALDI_MAX_TRACE_PRINT 20 // must be even.
106  // buffer for the trace,
107  void *trace[KALDI_MAX_TRACE_SIZE];
108  // get the trace,
109  size_t size = backtrace(trace, KALDI_MAX_TRACE_SIZE);
110  // get the trace symbols,
111  char **trace_symbol = backtrace_symbols(trace, size);
112 
113  // Compose the 'string',
114  ans += "[ Stack-Trace: ]\n";
115  if (size <= KALDI_MAX_TRACE_PRINT) {
116  for (size_t i = 0; i < size; i++) {
117  ans += Demangle(trace_symbol[i]) + "\n";
118  }
119  } else { // print out first+last (e.g.) 5.
120  for (size_t i = 0; i < KALDI_MAX_TRACE_PRINT/2; i++) {
121  ans += Demangle(trace_symbol[i]) + "\n";
122  }
123  ans += ".\n.\n.\n";
124  for (size_t i = size - KALDI_MAX_TRACE_PRINT/2; i < size; i++) {
125  ans += Demangle(trace_symbol[i]) + "\n";
126  }
127  if (size == KALDI_MAX_TRACE_SIZE)
128  ans += ".\n.\n.\n"; // stack was too long, probably a bug.
129  }
130 
131  // cleanup,
132  free(trace_symbol); // it's okay, just the pointers, not the strings.
133 #endif // HAVE_EXECINFO_H
134  return ans;
135 }
136 
137 
138 /***** KALDI LOGGING *****/
139 
141  const char *func, const char *file, int32 line) {
142  // Obviously, we assume the strings survive the destruction of this object.
143  envelope_.severity = severity;
144  envelope_.func = func;
145  envelope_.file = GetShortFileName(file); // Pointer inside 'file'.
146  envelope_.line = line;
147 }
148 
149 
151  // remove trailing '\n',
152  std::string str = ss_.str();
153  while (!str.empty() && str[str.length() - 1] == '\n')
154  str.resize(str.length() - 1);
155 
156  // print the mesage (or send to logging handler),
158 }
159 
160 
162  const char *message) {
163  // Send to a logging handler if provided.
164  if (g_log_handler != NULL) {
165  g_log_handler(envelope, message);
166  } else {
167  // Otherwise, we use the default Kaldi logging.
168  // Build the log-message 'header',
169  std::stringstream header;
170  if (envelope.severity > LogMessageEnvelope::kInfo) {
171  header << "VLOG[" << envelope.severity << "] (";
172  } else {
173  switch (envelope.severity) {
175  header << "LOG (";
176  break;
178  header << "WARNING (";
179  break;
181  header << "ERROR (";
182  break;
184  header << "ASSERTION_FAILED (";
185  break;
186  default:
187  abort(); // coding error (unknown 'severity'),
188  }
189  }
190  // fill the other info from the envelope,
191  header << GetProgramName() << "[" KALDI_VERSION "]" << ':'
192  << envelope.func << "():" << envelope.file << ':' << envelope.line
193  << ")";
194 
195  // Printing the message,
196  if (envelope.severity >= LogMessageEnvelope::kWarning) {
197  // VLOG, LOG, WARNING:
198  fprintf(stderr, "%s %s\n", header.str().c_str(), message);
199  } else {
200  // ERROR, ASSERT_FAILED (print with stack-trace):
201  fprintf(stderr, "%s %s\n\n%s\n", header.str().c_str(), message,
202  KaldiGetStackTrace().c_str());
203  }
204  }
205 
206  // Should we throw exception, or abort?
207  switch (envelope.severity) {
209  abort(); // ASSERT_FAILED,
210  break;
212  if (!std::uncaught_exception()) {
213  // throw exception with empty message,
214  throw std::runtime_error(""); // KALDI_ERR,
215  } else {
216  // If we got here, this thread has already thrown exception,
217  // and this exception has not yet arrived to its 'catch' clause...
218  // Throwing a new exception would be unsafe!
219  // (can happen during 'stack unwinding', if we have 'KALDI_ERR << msg'
220  // in a destructor of some local object).
221  abort();
222  }
223  break;
224  }
225 }
226 
227 
228 /***** KALDI ASSERTS *****/
229 
230 void KaldiAssertFailure_(const char *func, const char *file,
231  int32 line, const char *cond_str) {
232  MessageLogger ml(LogMessageEnvelope::kAssertFailed, func, file, line);
233  ml.stream() << ": '" << cond_str << "' ";
234 }
235 
236 
237 /***** THIRD-PARTY LOG-HANDLER *****/
238 
240  LogHandler old_handler = g_log_handler;
241  g_log_handler = new_handler;
242  return old_handler;
243 }
244 
245 } // end namespace kaldi
Relabels neural network egs with the read pdf-id alignments.
Definition: chain.dox:20
void(* LogHandler)(const LogMessageEnvelope &envelope, const char *message)
Type of third-party logging function,.
Definition: kaldi-error.h:189
MessageLogger(LogMessageEnvelope::Severity severity, const char *func, const char *file, int32 line)
Constructor stores the info,.
Definition: kaldi-error.cc:140
std::ostringstream ss_
Definition: kaldi-error.h:123
void KaldiAssertFailure_(const char *func, const char *file, int32 line, const char *cond_str)
Definition: kaldi-error.cc:230
static std::string KaldiGetStackTrace()
Definition: kaldi-error.cc:101
LogMessageEnvelope envelope_
Definition: kaldi-error.h:122
static const char * GetShortFileName(const char *filename)
Definition: kaldi-error.cc:56
#define KALDI_NOEXCEPT(Predicate)
Definition: kaldi-error.h:45
const char * g_program_name
This is set by util/parse-options.
Definition: kaldi-error.cc:41
static void HandleMessage(const LogMessageEnvelope &env, const char *msg)
The logging function,.
Definition: kaldi-error.cc:161
static std::string Demangle(std::string trace_name)
Definition: kaldi-error.cc:70
LogHandler SetLogHandler(LogHandler new_handler)
Set logging handler.
Definition: kaldi-error.cc:239
std::ostream & stream()
The hook for the 'insertion operator', e.g.
Definition: kaldi-error.h:115
#define KALDI_VERSION
Definition: version.h:3
int32 g_kaldi_verbose_level
This is set by util/parse-options.{h, cc} if you set –verbose=? option.
Definition: kaldi-error.cc:40
~MessageLogger() KALDI_NOEXCEPT(false)
Destructor, calls 'HandleMessage' which prints the message, (since C++11 a 'throwing' destructor must...
Definition: kaldi-error.cc:150
Log message severity and source location info.
Definition: kaldi-error.h:79
const char * GetProgramName()
Definition: kaldi-error.cc:47
static LogHandler g_log_handler
Definition: kaldi-error.cc:42