偷偷摘套内射激情视频,久久精品99国产国产精,中文字幕无线乱码人妻,中文在线中文a,性爽19p

通過 Inspector 收集 Node.js 的Trace Event 數(shù)據(jù)

開發(fā) 前端
除了通過 trace_events 模塊之外,Node.js 也實(shí)現(xiàn)了通過 Inspector 協(xié)議收集 trace event 數(shù)據(jù),本文介紹基于 inspector 協(xié)議收集 trace event 數(shù)據(jù)的實(shí)現(xiàn)。

前言

Node.js 提供了 trace event 的機(jī)制,在 Node.js 內(nèi)核代碼里,靜態(tài)地埋了一些點(diǎn),比如同步文件 IO 耗時(shí),DNS 解析耗時(shí)等。每次執(zhí)行這些代碼時(shí),Node.js 就會(huì)執(zhí)行這些點(diǎn)的鉤子,從而收集相應(yīng)的數(shù)據(jù)。不過這個(gè)能力默認(rèn)是關(guān)閉的,畢竟對性能會(huì)產(chǎn)生影響。我們可以通過 trace_events 模塊打開這個(gè)功能。trace_events 模塊會(huì)源源不斷地把數(shù)據(jù)寫到一個(gè)到多個(gè)文件中。除了通過 trace_events 模塊之外,Node.js 也實(shí)現(xiàn)了通過 Inspector 協(xié)議收集 trace event 數(shù)據(jù),本文介紹基于 inspector 協(xié)議收集 trace event 數(shù)據(jù)的實(shí)現(xiàn)。

首先看一下如何使用這種方式。

const { Session } = require('inspector');
const session = new Session();
session.connect();
function post(message, data) {
return new Promise((resolve, reject) => {
session.post(message, data, (err, result) => {
if (err)
reject(new Error(JSON.stringify(err)));
else
resolve(result);
});
});
}
async function test() {
session.on('NodeTracing.dataCollected', (data) => {
console.log(data.params.value);
});
session.on('NodeTracing.tracingComplete', () => {
console.log('done');
});
const { categories } = await post('NodeTracing.getCategories');
const traceConfig = { includedCategories: categories };
await post('NodeTracing.start', { traceConfig });
setTimeout(() => {
post('NodeTracing.stop');
}, 1000);
}
test();

使用方式比較固定,也比較簡單,trace event 是基于類型的,比如同步文件 IO,DNS 解析。所以第一步首先設(shè)置需要收集的模塊類型,也可以通過 NodeTracing.getCategories 命令獲取當(dāng)前支持的模塊類型。接著通過 NodeTracing.start 開啟數(shù)據(jù)收集,收集一段時(shí)間后,通過 NodeTracing.stop 停止數(shù)據(jù)的收集,在這個(gè)過程中,收集的數(shù)據(jù)會(huì)通過 NodeTracing.dataCollected 事件源源不斷地流向用戶側(cè),我們可以保存這些數(shù)據(jù)后續(xù)進(jìn)行分析,收集完畢后會(huì)觸發(fā) NodeTracing.tracingComplete 事件,從而完成整個(gè)過程。下面我們來看一下這些命令的實(shí)現(xiàn)。首先看一下整體的架構(gòu)。

之前介紹過 Node.js Inspector 的架構(gòu),本文就不再具體展開介紹。簡單來說,當(dāng)我們通過 js 層的 session 發(fā)送命令時(shí),代碼流程從圖的左邊到右邊,收集到數(shù)據(jù)時(shí),代碼流程從右往左回調(diào) js 層。首先來看一下 NodeTracing.start。Node.js 的 Inspector 框架采用兩級路由的機(jī)制,首先通過 NodeTracing 找到一級路由,在 inspetor 里叫 Domain,然后再通過 start 找到二級路由。 來看一下每個(gè)路由對應(yīng)的函數(shù)。

m_dispatchMap["NodeTracing.getCategories"] = &DispatcherImpl::getCategories;
m_dispatchMap["NodeTracing.start"] = &DispatcherImpl::start;
m_dispatchMap["NodeTracing.stop"] = &DispatcherImpl::stop;

我們只關(guān)注 start 和 stop 的邏輯。

void DispatcherImpl::start(int callId, const String& method, const ProtocolMessage& message, std::unique_ptr<DictionaryValue> requestMessageObject, ErrorSupport* errors){
protocol::DictionaryValue* object = DictionaryValue::cast(requestMessageObject->get("params"));
protocol::Value* traceConfigValue = object ? object->get("traceConfig") : nullptr;
std::unique_ptr<protocol::NodeTracing::TraceConfig> in_traceConfig = ValueConversions<protocol::NodeTracing::TraceConfig>::fromValue(traceConfigValue, errors);
std::unique_ptr<DispatcherBase::WeakPtr> weak = weakPtr();
DispatchResponse response = m_backend->start(std::move(in_traceConfig));
if (weak->get())
weak->get()->sendResponse(callId, response);
return;
}

start 里調(diào)用了 m_backend->start,根據(jù)架構(gòu)圖可知道 m_backend 的值是 TracingAgent 對象。

DispatchResponse TracingAgent::start(std::unique_ptr<protocol::NodeTracing::TraceConfig> traceConfig) {
std::set<std::string> categories_set;
protocol::Array<std::string>* categories = traceConfig->getIncludedCategories();
for (size_t i = 0; i < categories->length(); i++)
categories_set.insert(categories->get(i));
tracing::AgentWriterHandle* writer = GetTracingAgentWriter();
if (writer != nullptr) {
trace_writer_ =
writer->agent()->AddClient(categories_set,
std::make_unique<InspectorTraceWriter>(
frontend_object_id_, main_thread_),
tracing::Agent::kIgnoreDefaultCategories);
}
return DispatchResponse::OK();
}

最終通過 AddClient 往 tracing 系統(tǒng)注冊了一個(gè)消費(fèi)者。當(dāng)tracing 系統(tǒng)產(chǎn)生數(shù)據(jù)時(shí),就會(huì)通過 InspectorTraceWriter 進(jìn)行消費(fèi),看一下這個(gè) InspectorTraceWriter 對象的核心邏輯。

 void AppendTraceEvent(
v8::platform::tracing::TraceObject* trace_event) override {
if (!json_writer_)
json_writer_.reset(TraceWriter::CreateJSONTraceWriter(stream_, "value"));
json_writer_->AppendTraceEvent(trace_event);
}
void Flush(bool) override {
if (!json_writer_)
return;
json_writer_.reset();
std::ostringstream result(
"{\"method\":\"NodeTracing.dataCollected\",\"params\":",
std::ostringstream::ate);
result << stream_.str();
result << "}";
main_thread_->Post(std::make_unique<SendMessageRequest>(frontend_object_id_, result.str()));
stream_.str("");
}

tracing 系統(tǒng)調(diào)用 AppendTraceEvent 進(jìn)行數(shù)據(jù)的消費(fèi),不過這些數(shù)據(jù)會(huì)先緩存到內(nèi)存,然后再調(diào)用 Flush 通知真正的消費(fèi)者,在 Flush 函數(shù)里我們可以看到,通過發(fā)送一個(gè) SendMessageRequest 觸發(fā)了 NodeTracing.dataCollected 事件。接著看一下 SendMessageRequest 的邏輯。

void Call(MainThreadInterface* thread) override {
DeletableFrontendWrapper* frontend_wrapper = static_cast<DeletableFrontendWrapper*>(thread->GetObjectIfExists(object_id_));
if (frontend_wrapper == nullptr) return;
auto frontend = frontend_wrapper->get();
if (frontend != nullptr) {
frontend->sendRawJSONNotification(message_);
}
}
void Frontend::sendRawJSONNotification(String notification){
m_frontendChannel->sendProtocolNotification(InternalRawNotification::fromJSON(std::move(notification)));
}

Call 又調(diào)用了 m_frontendChannel->sendRawJSONNotification,根據(jù)架構(gòu)圖,m_frontendChannel 的值是 ChannelImpl。最后通過 ChannelImpl 通知用戶側(cè)。接著看 stop 的邏輯。

DispatchResponse TracingAgent::stop() {
trace_writer_.reset();
frontend_->tracingComplete();
return DispatchResponse::OK();
}

首先看一下 trace_writer_.reset()。

void AgentWriterHandle::reset() {
if (agent_ != nullptr)
agent_->Disconnect(id_);
agent_ = nullptr;}void Agent::Disconnect(int client) {
if (client == kDefaultHandleId) return;
{
Mutex::ScopedLock lock(initialize_writer_mutex_);
to_be_initialized_.erase(writers_[client].get());
}
ScopedSuspendTracing suspend(tracing_controller_.get(), this);
writers_.erase(client);
categories_.erase(client);

}

接著看 ScopedSuspendTracing。

ScopedSuspendTracing(TracingController* controller, Agent* agent,
bool do_suspend = true)
: controller_(controller), agent_(do_suspend ? agent : nullptr) {
if (do_suspend) {
CHECK(agent_->started_);
controller->StopTracing();
}
}
void TracingController::StopTracing() {
base::MutexGuard lock(mutex_.get());
trace_buffer_->Flush();
}

把所有數(shù)據(jù) Flush 到用戶側(cè)后觸發(fā) tracingComplete 事件。

void Frontend::tracingComplete(){
if (!m_frontendChannel)
return;
m_frontendChannel->sendProtocolNotification(InternalResponse::createNotification("NodeTracing.tracingComplete"));
}

時(shí)間關(guān)系,大概介紹到這。

責(zé)任編輯:姜華 來源: 編程雜技
相關(guān)推薦

2021-08-05 05:46:06

Node.jsInspector工具

2022-03-26 16:51:27

Node.jstrace架構(gòu)

2022-08-29 18:15:25

Node.js多線程模型

2021-08-07 07:56:59

Node邏輯對象

2022-04-02 06:04:03

Node.js代碼緩存V8

2022-04-01 08:02:32

Node.js快照加速hooks

2013-11-01 09:34:56

Node.js技術(shù)

2015-03-10 10:59:18

Node.js開發(fā)指南基礎(chǔ)介紹

2021-12-25 22:29:57

Node.js 微任務(wù)處理事件循環(huán)

2012-02-03 09:25:39

Node.js

2020-05-29 15:33:28

Node.js框架JavaScript

2011-09-08 13:46:14

node.js

2011-11-01 10:30:36

Node.js

2011-09-02 14:47:48

Node

2011-09-09 14:23:13

Node.js

2011-11-10 08:55:00

Node.js

2012-10-24 14:56:30

IBMdw

2017-04-24 08:31:26

Node.jsExpress.jsHTTP

2021-09-26 05:06:04

Node.js模塊機(jī)制

2021-11-06 18:40:27

js底層模塊
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號