This document describes the design and use of logging through NetLog.
[TOC]
Adding information to the NetLog helps debugging. However, logging also requires careful review as it can impact performance, privacy, and security.
Please add a net/log/OWNERS reviewer when adding new NetLog parameters, or adding information to existing ones.
The high level objectives when adding net logging code are:
kDefault
are safe to
upload and share publicly.kDefault
has a low
performance impact.kDefault
are small
enough to upload to bug reports.To avoid doing work when logging is off, logging code should generally be
conditional on NetLog::IsCapturing()
. Note that when specifying parameters
via a lambda, the lambda is already conditional on IsCapturing()
.
NetLog parameters are specified as a JSON serializable base::Value
. This has
some subtle implications:
base::Value::Type::STRING
with non-UTF-8 data.base::Value::Type::BINARY
(the JSON serializer can’t handle it)Instead:
NetLogStringValue()
.NetLogBinaryValue()
.base::Value::Type::STRING
Also consider the maximum size of any string parameters:
kEverything
capture mode.NetLog parameters are specified as a JSON serializable base::Value
which does
not support 64-bit integers.
Be careful when using base::Value::SetIntKey()
as it will truncate 64-bit
values to 32-bits.
Instead use NetLogNumberValue()
.
There is no backwards compatibility requirement for NetLog events and their parameters, so you are free to change their structure/value as needed.
That said, changing core events may have consequences for external consumers of NetLogs, which rely on the structure and parameters to events for pretty printing and log analysis.
The NetLog viewer for instance pretty prints certain parameters based on their names, and the event name that added them.
Add an PROXY_RESOLUTION_SERVICE
event without any parameters, at all capture
modes.
net_log.BeginEvent(NetLogEventType::PROXY_RESOLUTION_SERVICE);
Analysis:
BeginEvent
), and then a branch (test on IsCapturing()
).Add a FTP_COMMAND_SENT
event, at all capture modes, along with parameters
that describe the FTP command.
if (net_log.IsCapturing()) {
std::string command = BuildCommandForLog();
net_log.AddEventWithStringParams(NetLogEventType::FTP_COMMAND_SENT,
"command", command);
}
Analysis:
BuildCommandForString()
should additionally best-effort strip any identity information, as this is
being logged at all capture modes.BuildCommandForString()
is only executed when capturing.BuildCommandForLog()
needn’t strictly bound the
string length. If a huge FTP command makes it to a NetLog, there is a good
chance that is the problem being debugged.Add a SSL_CERTIFICATES_RECEIVED
event, along with the full certificate chain,
at all capture modes.
net_log.AddEvent(NetLogEventType::SSL_CERTIFICATES_RECEIVED, [&] {
base::Value::Dict dict;
base::Value certs(base::Value::Type::LIST);
std::vector<std::string> encoded_chain;
server_cert_->GetPEMEncodedChain(&encoded_chain);
for (auto& pem : encoded_chain)
certs.Append(std::move(pem));
dict.Set("certificates", std::move(certs));
return base::Value(std::move(dict));
});
Analysis:
base::Value
parameters is only
executed when capturing.kDefault
capture mode, however justified based on how
useful the data is.Add a COOKIE_STORE_COOKIE_ADDED
event at all capture modes. Moreover, if the
capture mode is kIncludeSensitive
or kEverything
, also logs the cookie’s
name and value.
net_log.AddEvent(NetLogEventType::COOKIE_STORE_COOKIE_ADDED,
[&](NetLogCaptureMode capture_mode) {
if (!NetLogCaptureIncludesSensitive(capture_mode))
return base::Value();
base::Value::Dict dict;
dict.Set("name", cookie->Name());
dict.Set("value", cookie->Value());
return base::Value(std::move(dict));
});
Analysis:
kDefault
capture
mode, so only cookie counts and timing information is revealed.base::Value
parameters is only
executed when capturing.kDefault
than to log
a parameterless event, as the parameterless event is not broadly useful.