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万+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章