kaldi中log文件生成邏輯

日誌源文件在:kaldi/src/base 中,kaldi-error.h ,kaldi-error.cc

使用時調用:

KALDI_ASSERT(num_chan > 0);

KALDI_WARN << "..." ;

KALDI_ERR <<"..."; 

KALDI_LOG <<"..."

KALDI_VLOG(2) <<"..."     有個全局變量:extern int32 g_kaldi_verbose_level; 在腳本中是用--verbose=2設置的


我看的過程就是順着調用理清源碼

在頭文件kaldi-error.h中定義了宏:

// The definition of the logging macros,
#define KALDI_ERR \
  ::kaldi::MessageLogger(::kaldi::LogMessageEnvelope::kError, \
                         __func__, __FILE__, __LINE__).stream()
#define KALDI_WARN \
  ::kaldi::MessageLogger(::kaldi::LogMessageEnvelope::kWarning, \
                         __func__, __FILE__, __LINE__).stream()
#define KALDI_LOG \
  ::kaldi::MessageLogger(::kaldi::LogMessageEnvelope::kInfo, \
                         __func__, __FILE__, __LINE__).stream()
#define KALDI_VLOG(v) if ((v) <= ::kaldi::g_kaldi_verbose_level)     \
  ::kaldi::MessageLogger((::kaldi::LogMessageEnvelope::Severity)(v), \
                         __func__, __FILE__, __LINE__).stream()

其中:__func__, __FILE__, __LINE__ 分別是函數,文件,行。e.g. CalMfcc():recognition.cc:148

宏實際上創建了對象,並返回了ostringstream類型的ss_,所以在源碼中找不到重載"<<"的地方

inline std::ostream &stream() { return ss_; }

std::ostringstream ss_;

類對象:

struct LogMessageEnvelope {
  enum Severity {
    kAssertFailed = -3,
    kError = -2,
    kWarning = -1,
    kInfo = 0,
  };
  // An 'enum Severity' value, or a positive number indicating verbosity level.
  int severity;
  const char *func;
  const char *file;
  int32 line;
};

class MessageLogger {
public:
  /// Constructor stores the info,
  MessageLogger(LogMessageEnvelope::Severity severity,
                const char *func,
                const char *file,
                int32 line);

  /// Destructor, calls 'HandleMessage' which prints the message,
  /// (since C++11 a 'throwing' destructor must be declared 'noexcept(false)')
  ~MessageLogger() KALDI_NOEXCEPT(false);

  /// The hook for the 'insertion operator', e.g.
  /// 'KALDI_LOG << "Message,"',
  inline std::ostream &stream() { return ss_; }

private:
  /// The logging function,
  static void HandleMessage(const LogMessageEnvelope &env, const char *msg);

private:
  LogMessageEnvelope envelope_;
  std::ostringstream ss_;
};

對象析構時,會調用HandleMessage()函數,輸出打印的內容:

MessageLogger::~MessageLogger() KALDI_NOEXCEPT(false) {
  // remove trailing '\n',
  std::string str = ss_.str();
  while (!str.empty() && str[str.length() - 1] == '\n')
    str.resize(str.length() - 1);

  // print the mesage (or send to logging handler),
  MessageLogger::HandleMessage(envelope_, str.c_str());
}

void MessageLogger::HandleMessage(const LogMessageEnvelope &envelope,
                                  const char *message) {
  // Send to a logging handler if provided.
  if (g_log_handler != NULL) {
    g_log_handler(envelope, message);
  } else {
    // Otherwise, we use the default Kaldi logging.
    // Build the log-message 'header',
    std::stringstream header;
    if (envelope.severity > LogMessageEnvelope::kInfo) {
      header << "VLOG[" << envelope.severity << "] (";
    } else {
      switch (envelope.severity) {
        case LogMessageEnvelope::kInfo :
          header << "LOG (";
          break;
        case LogMessageEnvelope::kWarning :
          header << "WARNING (";
          break;
        case LogMessageEnvelope::kError :
          header << "ERROR (";
          break;
        case LogMessageEnvelope::kAssertFailed :
          header << "ASSERTION_FAILED (";
          break;
        default:
          abort();  // coding error (unknown 'severity'),
       }
    }
    // fill the other info from the envelope,
    header << GetProgramName() << "[" KALDI_VERSION "]" << ':'
           << envelope.func << "():" << envelope.file << ':' << envelope.line
           << ")";

    // Printing the message,
    if (envelope.severity >= LogMessageEnvelope::kWarning) {
      // VLOG, LOG, WARNING:
      fprintf(stderr, "%s %s\n", header.str().c_str(), message);
    } else {
      // ERROR, ASSERT_FAILED (print with stack-trace):
      fprintf(stderr, "%s %s\n\n%s\n", header.str().c_str(), message,
              KaldiGetStackTrace().c_str());
    }
  }

在整個源碼中我們也沒有找到log文件路徑的配置,實際上是在腳本中設置的,會看到類型下面的腳本:

$cmd JOB=1:$nj $logdir/make_mfcc_${name}.JOB.log ...

cmd 沒用到集羣時是run.pl,在其中有這樣的代碼段:

system("mkdir -p `dirname $logfile` 2>/dev/null");
open(F, ">$logfile") || die "run.pl: Error opening log file $logfile";
print F "# " . $cmd . "\n";
print F "# Started at " . `date`;
$starttime = `date +'%s'`;
print F "#\n";
close(F);
...
open(F, ">>$logfile") || die "run.pl: Error opening log file $logfile (again)";
$enddate = `date`;
chop $enddate;
print F "# Accounting: time=" . ($endtime - $starttime) . " threads=1\n";
print F "# Ended ($return_str) at " . $enddate . ", elapsed time " . ($endtime-$starttime) . " seconds\n";
close(F);
...

是在peal中重定向到指定文件中的。

我們自己調用的時候直接 ">> xxx.log"時,會發現沒輸出。需要改成”2>>xxx.log“

爲什麼是2----Linux中有三種標準輸入輸出,分別是 STDIN,STDOUT,STDERR,對應的數字是 0,1,2

到這裏,基本整個邏輯沒太大的問題了,就是一些細節弄明白就行了


發佈了55 篇原創文章 · 獲贊 18 · 訪問量 8萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章