WebRTC日志

  • 日志文件主要是在rtc_base/logging.h和rtc_base/logging.cc文件里。

  • webrtc有两种日志格式

#define RTC_LOG(sev) RTC_LOG_FILE_LINE(rtc::sev, __FILE__, __LINE__)

// The _V version is for when a variable is passed in.
#define RTC_LOG_V(sev) RTC_LOG_FILE_LINE(sev, __FILE__, __LINE__)

RTC_LOG一般是日志等级不改变,RTC_LOG_V是日志等级会改变,不过这只是使用上的约定。

  • 拿一条日志为例来说明
    • 文件p2p/base/port.cc里
  // Log at LS_INFO if we receive a ping response on an unwritable
  // connection.
  rtc::LoggingSeverity sev = !writable() ? rtc::LS_INFO : rtc::LS_VERBOSE;

  int rtt = request->Elapsed();

  if (RTC_LOG_CHECK_LEVEL_V(sev)) {
    std::string pings;
    PrintPingsSinceLastResponse(&pings, 5);
    RTC_LOG_V(sev) << ToString() << ": Received STUN ping response, id="
                   << rtc::hex_encode(request->id())
                   << ", code=0"  // Makes logging easier to parse.
                      ", rtt="
                   << rtt << ", pings_since_last_response=" << pings;
  }
  • 日志等级sev是根据条件writable()生成的。
  • RTC_LOG_V是一个宏,定义在rtc_base/logging.h里(文章开头已经写了)
    • 这里增加了文件名和行号
#define RTC_LOG_V(sev) RTC_LOG_FILE_LINE(sev, __FILE__, __LINE__)
  • RTC_LOG_FILE_LINE的定义也在rtc_base/logging.h里
#define RTC_LOG_FILE_LINE(sev, file, line)      \
  rtc::webrtc_logging_impl::LogCall() &         \
      rtc::webrtc_logging_impl::LogStreamer<>() \
          << rtc::webrtc_logging_impl::LogMetadata(file, line, sev)
  • 先看LogCall这个类
class LogCall final {
 public:
  // This can be any binary operator with precedence lower than <<.
  template <typename... Ts>
  inline void operator&(const LogStreamer<Ts...>& streamer) {
    streamer.Call();
  }
};

这是一个final,不允许被继承。
只有一个运算符重载&,具体的执行就是调用参数的Call()方法。

  • 再看rtc::webrtc_logging_impl::LogStreamer<>()
// Base case: Before the first << argument.
template <>
class LogStreamer<> final {
 public:
  template <
      typename U,
      typename std::enable_if<std::is_arithmetic<U>::value>::type* = nullptr>
  inline LogStreamer<decltype(MakeVal(std::declval<U>()))> operator<<(
      U arg) const {
    return LogStreamer<decltype(MakeVal(std::declval<U>()))>(MakeVal(arg),
                                                             this);
  }

  template <
      typename U,
      typename std::enable_if<!std::is_arithmetic<U>::value>::type* = nullptr>
  inline LogStreamer<decltype(MakeVal(std::declval<U>()))> operator<<(
      const U& arg) const {
    return LogStreamer<decltype(MakeVal(std::declval<U>()))>(MakeVal(arg),
                                                             this);
  }

  template <typename... Us>
  inline static void Call(const Us&... args) {
    static constexpr LogArgType t[] = {Us::Type()..., LogArgType::kEnd};
    Log(t, args.GetVal()...);
  }
};

调用的是Log(t, args.GetVal()…);

  • 最后看rtc::webrtc_logging_impl::LogMetadata(file, line, sev)
class LogMetadata {
 public:
  LogMetadata(const char* file, int line, LoggingSeverity severity)
      : file_(file),
        line_and_sev_(static_cast<uint32_t>(line) << 3 | severity) {}
  LogMetadata() = default;

  const char* File() const { return file_; }
  int Line() const { return line_and_sev_ >> 3; }
  LoggingSeverity Severity() const {
    return static_cast<LoggingSeverity>(line_and_sev_ & 0x7);
  }

 private:
  const char* file_;

  // Line number and severity, the former in the most significant 29 bits, the
  // latter in the least significant 3 bits. (This is an optimization; since
  // both numbers are usually compile-time constants, this way we can load them
  // both with a single instruction.)
  uint32_t line_and_sev_;
};

这里通过构造函数,把参数传人进来。

  • 回到开始我们要分析的日志
RTC_LOG_V(sev) << ToString() << ": Received STUN ping response, id="
                   << rtc::hex_encode(request->id())
                   << ", code=0"  // Makes logging easier to parse.
                      ", rtt="
                   << rtt << ", pings_since_last_response=" << pings;

从ToString开始后面的都是string格式,直接就输出了。
这里ToString()的内容是

  rtc::StringBuilder ss;
  ss << "Conn[" << ToDebugId() << ":" << port_->content_name() << ":"
     << port_->Network()->ToString() << ":" << local.id() << ":"
     << local.component() << ":" << local.generation() << ":" << local.type()
     << ":" << local.protocol() << ":" << local.address().ToSensitiveString()
     << "->" << remote.id() << ":" << remote.component() << ":"
     << remote.priority() << ":" << remote.type() << ":" << remote.protocol()
     << ":" << remote.address().ToSensitiveString() << "|"
     << CONNECT_STATE_ABBREV[connected()] << RECEIVE_STATE_ABBREV[receiving()]
     << WRITE_STATE_ABBREV[write_state()] << ICESTATE[static_cast<int>(state())]
     << "|" << SELECTED_STATE_ABBREV[selected()] << "|" << remote_nomination()
     << "|" << nomination() << "|" << priority() << "|";
  if (rtt_ < DEFAULT_RTT) {
    ss << rtt_ << "]";
  } else {
    ss << "-]";
  }
  return ss.Release();
  • 最后的输出结果是
    在这里插入图片描述

你可能感兴趣的:(WebRTC日志)