log.cc (4507B)
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 /* 20 * Stack trace related stuff is from kaldi. 21 * Refer to 22 * https://github.com/kaldi-asr/kaldi/blob/master/src/base/kaldi-error.cc 23 */ 24 25 #include "kaldi-native-fbank/csrc/log.h" 26 27 #ifdef KNF_HAVE_EXECINFO_H 28 #include <execinfo.h> // To get stack trace in error messages. 29 #ifdef KNF_HAVE_CXXABI_H 30 #include <cxxabi.h> // For name demangling. 31 // Useful to decode the stack trace, but only used if we have execinfo.h 32 #endif // KNF_HAVE_CXXABI_H 33 #endif // KNF_HAVE_EXECINFO_H 34 35 #include <stdlib.h> 36 37 #include <ctime> 38 #include <iomanip> 39 #include <string> 40 41 namespace knf { 42 43 std::string GetDateTimeStr() { 44 std::ostringstream os; 45 std::time_t t = std::time(nullptr); 46 std::tm tm = *std::localtime(&t); 47 os << std::put_time(&tm, "%F %T"); // yyyy-mm-dd hh:mm:ss 48 return os.str(); 49 } 50 51 static bool LocateSymbolRange(const std::string &trace_name, std::size_t *begin, 52 std::size_t *end) { 53 // Find the first '_' with leading ' ' or '('. 54 *begin = std::string::npos; 55 for (std::size_t i = 1; i < trace_name.size(); ++i) { 56 if (trace_name[i] != '_') { 57 continue; 58 } 59 if (trace_name[i - 1] == ' ' || trace_name[i - 1] == '(') { 60 *begin = i; 61 break; 62 } 63 } 64 if (*begin == std::string::npos) { 65 return false; 66 } 67 *end = trace_name.find_first_of(" +", *begin); 68 return *end != std::string::npos; 69 } 70 71 #ifdef KNF_HAVE_EXECINFO_H 72 static std::string Demangle(const std::string &trace_name) { 73 #ifndef KNF_HAVE_CXXABI_H 74 return trace_name; 75 #else // KNF_HAVE_CXXABI_H 76 // Try demangle the symbol. We are trying to support the following formats 77 // produced by different platforms: 78 // 79 // Linux: 80 // ./kaldi-error-test(_ZN5kaldi13UnitTestErrorEv+0xb) [0x804965d] 81 // 82 // Mac: 83 // 0 server 0x000000010f67614d _ZNK5kaldi13MessageLogger10LogMessageEv + 813 84 // 85 // We want to extract the name e.g., '_ZN5kaldi13UnitTestErrorEv' and 86 // demangle it info a readable name like kaldi::UnitTextError. 87 std::size_t begin, end; 88 if (!LocateSymbolRange(trace_name, &begin, &end)) { 89 return trace_name; 90 } 91 std::string symbol = trace_name.substr(begin, end - begin); 92 int status; 93 char *demangled_name = abi::__cxa_demangle(symbol.c_str(), 0, 0, &status); 94 if (status == 0 && demangled_name != nullptr) { 95 symbol = demangled_name; 96 free(demangled_name); 97 } 98 return trace_name.substr(0, begin) + symbol + 99 trace_name.substr(end, std::string::npos); 100 #endif // KNF_HAVE_CXXABI_H 101 } 102 #endif // KNF_HAVE_EXECINFO_H 103 104 std::string GetStackTrace() { 105 std::string ans; 106 #ifdef KNF_HAVE_EXECINFO_H 107 constexpr const std::size_t kMaxTraceSize = 50; 108 constexpr const std::size_t kMaxTracePrint = 50; // Must be even. 109 // Buffer for the trace. 110 void *trace[kMaxTraceSize]; 111 // Get the trace. 112 std::size_t size = backtrace(trace, kMaxTraceSize); 113 // Get the trace symbols. 114 char **trace_symbol = backtrace_symbols(trace, size); 115 if (trace_symbol == nullptr) return ans; 116 117 // Compose a human-readable backtrace string. 118 ans += "[ Stack-Trace: ]\n"; 119 if (size <= kMaxTracePrint) { 120 for (std::size_t i = 0; i < size; ++i) { 121 ans += Demangle(trace_symbol[i]) + "\n"; 122 } 123 } else { // Print out first+last (e.g.) 5. 124 for (std::size_t i = 0; i < kMaxTracePrint / 2; ++i) { 125 ans += Demangle(trace_symbol[i]) + "\n"; 126 } 127 ans += ".\n.\n.\n"; 128 for (std::size_t i = size - kMaxTracePrint / 2; i < size; ++i) { 129 ans += Demangle(trace_symbol[i]) + "\n"; 130 } 131 if (size == kMaxTraceSize) 132 ans += ".\n.\n.\n"; // Stack was too long, probably a bug. 133 } 134 135 // We must free the array of pointers allocated by backtrace_symbols(), 136 // but not the strings themselves. 137 free(trace_symbol); 138 #endif // KNF_HAVE_EXECINFO_H 139 return ans; 140 } 141 142 } // namespace knf