日志文件主要是在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是日志等级会改变,不过这只是使用上的约定。
// 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;
}
#define RTC_LOG_V(sev) RTC_LOG_FILE_LINE(sev, __FILE__, __LINE__)
#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)
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()方法。
// 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()…);
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();