How to add log to log file in WebRTC library

Table of Contents
  1. 先写一个 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);
  1. 在想加 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|

Legend *) Required fields are marked
**) You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>
Category: WebRTC