Chromium 网络栈之NetLog


发布于 2021-11-24


NetLog 是 Chromium 网络栈记录事件的机制,可用于辅助定位网络问题或者分析性能。

chrome://net-export/ 记录 NetLog

Chromium 浏览器提供一个可视化的界面来录制浏览器的NetLog。打开 chrome://net-export/ ,如下图所示:

chrome net export

我们点击 Start Logging to Disk 按钮,就开始录制 NetLog。然后我们打开一些网页,对浏览器做一些操作,再点击 Stop Logging 按钮,就可以把 NetLog 的数据保存到磁盘文件 chrome-net-export-log.json 中了,如下图所示:

chrome net export save net log

chrome://net-export/ 的功能实际上是代码中 NetLogExporter 类实现的。

NetLog 数据

可以看到 NetLog 保存的数据文件 chrome-net-export-log.json 是 json 的格式。

它主要有 3 部分:

  • constants,可选的,用于解码 log 里面一些常量值。
  • events,记录事件数据。
  • polledData,可选的,记录附加的网络栈信息。

NetLog 中的 events 数据,其实对应就是代码中的 NetLogEntryData 中保存的数据。

字段 类型 说明
time string 事件发生的毫秒值
type number 事件的类型id
source object 事件源信息
phase number 事件的阶段 BEGIN, END, NONE
params object 可选的字段,事件相关的数据

字段 source 的值是个对象,它的内部字段如下:

  • id,该事件数据源的唯一ID
  • type,事件源的类型
  • start_time,事件源的开始时间

查看 NetLog 数据

在之前 Chromium 版本里,浏览器打开 chrome://net-internals/ ,可以加载查看 NetLog 数据。较新版本的 Chromium 已经移除了 chrome://net-internals/ ,但是我们可以在网页 https://netlog-viewer.appspot.com/ 中查看。

加载一个已经录制好的 NetLog 数据文件,效果如下:

chrome netlog viewer

可以看到 NetLog 记录的数据是非常全面的。对应我们分析网络实际的工作情况非常有帮助。这个工具的使用并不复杂,就不赘述了。

FileNetLogObserver

我们实现一个 NetLogController 类 通过调用 FileNetLogObserver 的接口把 NetLog 中的数据写到文件中:

net_log_controller.h 文件内容:

#ifndef NET_LOG_CONTROLLER_H_
#define NET_LOG_CONTROLLER_H_

#include <memory>

#include "base/macros.h"
#include "base/memory/scoped_refptr.h"
#include "net/log/file_net_log_observer.h"
#include "net/log/net_log.h"
#include "net/url_request/url_request_context.h"

class NetLogController {
 public:
  NetLogController(net::URLRequestContext* url_request_context);
  virtual ~NetLogController();

  void Start();
  void Stop();

 private:
  net::URLRequestContext* url_request_context_ = nullptr;
  std::unique_ptr<net::FileNetLogObserver> file_net_log_observer_;
  DISALLOW_COPY_AND_ASSIGN(NetLogController);
};
#endif  // NET_LOG_CONTROLLER_H_

--------------------------------------------------------------------

net_log_controller.h 文件内容:

#include "net_log_controller.h"

#include "base/files/file_util.h"
#include "base/path_service.h"
#include "net/log/net_log_capture_mode.h"
#include "net/log/net_log_util.h"

NetLogController::NetLogController(net::URLRequestContext* url_request_context)
    : url_request_context_(url_request_context) {}

NetLogController::~NetLogController() {}

void NetLogController::Start() {
  base::FilePath log_path;
  base::PathService::Get(base::DIR_EXE, &log_path);
  log_path = log_path.AppendASCII("netlog.json");
  if (base::PathExists(log_path)) {
    base::DeleteFile(log_path, false);
  }

  std::unique_ptr<base::DictionaryValue> constants_dict =
      net::GetNetConstants();
  file_net_log_observer_ = net::FileNetLogObserver::CreateUnbounded(
      log_path, std::move(constants_dict));

  file_net_log_observer_->StartObserving(url_request_context_->net_log(),
                                         net::NetLogCaptureMode::Default());
}

void NetLogController::Stop() {
  if (!file_net_log_observer_)
    return;

  std::unique_ptr<base::DictionaryValue> net_info =
      net::GetNetInfo(url_request_context_, net::NET_INFO_ALL_SOURCES);
  file_net_log_observer_->StopObserving(std::move(net_info), base::Closure());
  file_net_log_observer_.reset();
}

创建 FileNetLogObserver 时, 通过 net::GetNetConstants() 拿到的数据其实就是 NetLog 数据文件中的 constants。

通过 NetLogCaptureMode 参数,我们可以控制记录数据的详细程序。

FileNetLogObserver StopObserving 时通过 net::GetNetInfo(url_request_context_, net::NET_INFO_ALL_SOURCES); 拿到的数据其实就是 NetLog 数据文件中的 polledData。

NetLogWithSource

NetLog中的事件数据都是有数据源的。数据源真正产生事件数据时,调用 NetLogWithSource 去写数据。

参考