How to add log to log file in WebRTC library
Table of Contents
-
先写一个 LogSink
class BweTestLogSink : public rtc::LogSink { public: BweTestLogSink(const std::string& filepath) { m_stream.open(filepath, std::ios::app | std::ios::out | std::ios::in); } ~BweTestLogSink() { m_stream.close(); } void OnLogMessage(const std::string& message) override { //std::cout << message << std::endl; m_stream << message; } private: std::ofstream m_stream; };
2. 将这个 LogSink 加到 LogMessage 的输出流中
```cpp
//程序开始后
//add timestmap, thread into log
rtc::LogMessage::LogTimestamps(true);
rtc::LogMessage::LogThreads(true);
//enable verbose log
rtc::LogMessage::LogToDebug(rtc::LS_VERBOSE);
//add a file log
std::string str = "bwe_trace.log";
BweTestLogSink bweLogSink(&str);
LogMessage::AddLogToStream(&bweLogSink, LS_INFO);
//也可以用系统提供的文件日志
FileRotatingLogSink frls("C:\\Users\\study\\Desktop\\log","webrtc_log",1024,2);
frls.Init();
//将日志输出到日志文件中,接收WARNING及以上级别的日志
LogMessage::AddLogToStream(&frls, WARNING);
//...
//程序结束前
LogMessage::RemoveLogToStream(&bweLogSink);
- 在想加 log 的地方用 log macro 写 log
RTC_LOG(LS_INFO) << "log something";
log macro
#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)
#define RTC_LOG(sev) \
!rtc::LogMessage::IsNoop<::rtc::sev>() && \
RTC_LOG_FILE_LINE(::rtc::sev, __FILE__, __LINE__)
e.g.
void LogPacketResult(PacketResult& packetResult) {
RTC_LOG(LS_VERBOSE) << "[BWE_LOG] receive_time=" << packetResult.receive_time.ms()
<< "send_packet, send_time=" << packetResult.sent_packet.send_time.ms()
<< ", sequence_number=" << packetResult.sent_packet.sequence_number
<< ", size=" << ToString(packetResult.sent_packet.size)
<< ", data_in_flight=" << ToString(packetResult.sent_packet.data_in_flight)
<< ", pacing_info, probe_cluster_id=" << packetResult.sent_packet.pacing_info.probe_cluster_id
<< ", send_bitrate_bps=" << packetResult.sent_packet.pacing_info.send_bitrate_bps
<< ", probe_cluster_bytes_sent=" << packetResult.sent_packet.pacing_info.probe_cluster_bytes_sent;
}
log stream
// Base case: Before the first << argument.
template <>
class LogStreamer<> final {
public:
template <typename U,
typename V = decltype(MakeVal(std::declval<U>())),
absl::enable_if_t<std::is_arithmetic<U>::value ||
std::is_enum<U>::value>* = nullptr>
RTC_FORCE_INLINE LogStreamer<V> operator<<(U arg) const {
return LogStreamer<V>(MakeVal(arg), this);
}
template <typename U,
typename V = decltype(MakeVal(std::declval<U>())),
absl::enable_if_t<!std::is_arithmetic<U>::value &&
!std::is_enum<U>::value>* = nullptr>
RTC_FORCE_INLINE LogStreamer<V> operator<<(const U& arg) const {
return LogStreamer<V>(MakeVal(arg), this);
}
template <typename... Us>
RTC_FORCE_INLINE static void Call(const Us&... args) {
static constexpr LogArgType t[] = {Us::Type()..., LogArgType::kEnd};
Log(t, args.GetVal()...);
}
};
Log message
// Direct use of this class is deprecated; please use the logging macros
// instead.
// TODO(bugs.webrtc.org/9278): Move this class to an unnamed namespace in the
// .cc file.
class LogMessage {
public:
// Same as the above, but using a compile-time constant for the logging
// severity. This saves space at the call site, since passing an empty struct
// is generally the same as not passing an argument at all.
template <LoggingSeverity S>
RTC_NO_INLINE LogMessage(const char* file,
int line,
std::integral_constant<LoggingSeverity, S>)
: LogMessage(file, line, S) {}
#if RTC_LOG_ENABLED()
LogMessage(const char* file, int line, LoggingSeverity sev);
LogMessage(const char* file,
int line,
LoggingSeverity sev,
LogErrorContext err_ctx,
int err);
#if defined(WEBRTC_ANDROID)
LogMessage(const char* file, int line, LoggingSeverity sev, const char* tag);
#endif
// DEPRECATED - DO NOT USE - PLEASE USE THE MACROS INSTEAD OF THE CLASS.
// Android code should use the 'const char*' version since tags are static
// and we want to avoid allocating a std::string copy per log line.
ABSL_DEPRECATED("Use RTC_LOG macros instead of accessing this class directly")
LogMessage(const char* file,
int line,
LoggingSeverity sev,
const std::string& tag);
~LogMessage();
//...
// String data generated in the constructor, that should be appended to
// the message before output.
std::string extra_;
// The output streams and their associated severities
static LogSink* streams_;
// Holds true with high probability if `streams_` is empty, false with high
// probability otherwise. Operated on with std::memory_order_relaxed because
// it's ok to lose or log some additional statements near the instant streams
// are added/removed.
static std::atomic<bool> streams_empty_;
// Flags for formatting options
static bool thread_, timestamp_;
//...
// The stringbuilder that buffers the formatted message before output
rtc::StringBuilder print_stream_;
}
Log function
void Log(const LogArgType* fmt, ...) {
va_list args;
va_start(args, fmt);
LogMetadataErr meta;
const char* tag = nullptr;
switch (*fmt) {
case LogArgType::kLogMetadata: {
meta = {va_arg(args, LogMetadata), ERRCTX_NONE, 0};
break;
}
case LogArgType::kLogMetadataErr: {
meta = va_arg(args, LogMetadataErr);
break;
}
#ifdef WEBRTC_ANDROID
case LogArgType::kLogMetadataTag: {
const LogMetadataTag tag_meta = va_arg(args, LogMetadataTag);
meta = {{nullptr, 0, tag_meta.severity}, ERRCTX_NONE, 0};
tag = tag_meta.tag;
break;
}
#endif
default: {
RTC_DCHECK_NOTREACHED();
va_end(args);
return;
}
}
LogMessage log_message(meta.meta.File(), meta.meta.Line(),
meta.meta.Severity(), meta.err_ctx, meta.err);
if (tag) {
log_message.AddTag(tag);
}
for (++fmt; *fmt != LogArgType::kEnd; ++fmt) {
switch (*fmt) {
case LogArgType::kInt:
log_message.stream() << va_arg(args, int);
break;
case LogArgType::kLong:
log_message.stream() << va_arg(args, long);
break;
case LogArgType::kLongLong:
log_message.stream() << va_arg(args, long long);
break;
case LogArgType::kUInt:
log_message.stream() << va_arg(args, unsigned);
break;
case LogArgType::kULong:
log_message.stream() << va_arg(args, unsigned long);
break;
case LogArgType::kULongLong:
log_message.stream() << va_arg(args, unsigned long long);
break;
case LogArgType::kDouble:
log_message.stream() << va_arg(args, double);
break;
case LogArgType::kLongDouble:
log_message.stream() << va_arg(args, long double);
break;
case LogArgType::kCharP: {
const char* s = va_arg(args, const char*);
log_message.stream() << (s ? s : "(null)");
break;
}
case LogArgType::kStdString:
log_message.stream() << *va_arg(args, const std::string*);
break;
case LogArgType::kStringView:
log_message.stream() << *va_arg(args, const absl::string_view*);
break;
case LogArgType::kVoidP:
log_message.stream() << rtc::ToHex(
reinterpret_cast<uintptr_t>(va_arg(args, const void*)));
break;
default:
RTC_DCHECK_NOTREACHED();
va_end(args);
return;
}
}
va_end(args);
}
Comments |0|
Category: WebRTC