1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "net/base/net_log.h"
6
7 #include "base/bind.h"
8 #include "base/logging.h"
9 #include "base/strings/string_number_conversions.h"
10 #include "base/strings/utf_string_conversions.h"
11 #include "base/time/time.h"
12 #include "base/values.h"
13 #include "net/base/net_errors.h"
14
15 namespace net {
16
17 namespace {
18
19 // Returns parameters for logging data transferred events. Includes number of
20 // bytes transferred and, if the log level indicates bytes should be logged and
21 // |byte_count| > 0, the bytes themselves. The bytes are hex-encoded, since
22 // base::StringValue only supports UTF-8.
BytesTransferredCallback(int byte_count,const char * bytes,NetLog::LogLevel log_level)23 base::Value* BytesTransferredCallback(int byte_count,
24 const char* bytes,
25 NetLog::LogLevel log_level) {
26 base::DictionaryValue* dict = new base::DictionaryValue();
27 dict->SetInteger("byte_count", byte_count);
28 if (NetLog::IsLoggingBytes(log_level) && byte_count > 0)
29 dict->SetString("hex_encoded_bytes", base::HexEncode(bytes, byte_count));
30 return dict;
31 }
32
SourceEventParametersCallback(const NetLog::Source source,NetLog::LogLevel)33 base::Value* SourceEventParametersCallback(const NetLog::Source source,
34 NetLog::LogLevel /* log_level */) {
35 if (!source.IsValid())
36 return NULL;
37 base::DictionaryValue* event_params = new base::DictionaryValue();
38 source.AddToEventParameters(event_params);
39 return event_params;
40 }
41
NetLogIntegerCallback(const char * name,int value,NetLog::LogLevel)42 base::Value* NetLogIntegerCallback(const char* name,
43 int value,
44 NetLog::LogLevel /* log_level */) {
45 base::DictionaryValue* event_params = new base::DictionaryValue();
46 event_params->SetInteger(name, value);
47 return event_params;
48 }
49
NetLogInt64Callback(const char * name,int64 value,NetLog::LogLevel)50 base::Value* NetLogInt64Callback(const char* name,
51 int64 value,
52 NetLog::LogLevel /* log_level */) {
53 base::DictionaryValue* event_params = new base::DictionaryValue();
54 event_params->SetString(name, base::Int64ToString(value));
55 return event_params;
56 }
57
NetLogStringCallback(const char * name,const std::string * value,NetLog::LogLevel)58 base::Value* NetLogStringCallback(const char* name,
59 const std::string* value,
60 NetLog::LogLevel /* log_level */) {
61 base::DictionaryValue* event_params = new base::DictionaryValue();
62 event_params->SetString(name, *value);
63 return event_params;
64 }
65
NetLogString16Callback(const char * name,const base::string16 * value,NetLog::LogLevel)66 base::Value* NetLogString16Callback(const char* name,
67 const base::string16* value,
68 NetLog::LogLevel /* log_level */) {
69 base::DictionaryValue* event_params = new base::DictionaryValue();
70 event_params->SetString(name, *value);
71 return event_params;
72 }
73
74 } // namespace
75
76 // LoadTimingInfo requires this be 0.
77 const uint32 NetLog::Source::kInvalidId = 0;
78
Source()79 NetLog::Source::Source() : type(SOURCE_NONE), id(kInvalidId) {
80 }
81
Source(SourceType type,uint32 id)82 NetLog::Source::Source(SourceType type, uint32 id) : type(type), id(id) {
83 }
84
IsValid() const85 bool NetLog::Source::IsValid() const {
86 return id != kInvalidId;
87 }
88
AddToEventParameters(base::DictionaryValue * event_params) const89 void NetLog::Source::AddToEventParameters(
90 base::DictionaryValue* event_params) const {
91 base::DictionaryValue* dict = new base::DictionaryValue();
92 dict->SetInteger("type", static_cast<int>(type));
93 dict->SetInteger("id", static_cast<int>(id));
94 event_params->Set("source_dependency", dict);
95 }
96
ToEventParametersCallback() const97 NetLog::ParametersCallback NetLog::Source::ToEventParametersCallback() const {
98 return base::Bind(&SourceEventParametersCallback, *this);
99 }
100
101 // static
FromEventParameters(base::Value * event_params,Source * source)102 bool NetLog::Source::FromEventParameters(base::Value* event_params,
103 Source* source) {
104 base::DictionaryValue* dict;
105 base::DictionaryValue* source_dict;
106 int source_id;
107 int source_type;
108 if (!event_params ||
109 !event_params->GetAsDictionary(&dict) ||
110 !dict->GetDictionary("source_dependency", &source_dict) ||
111 !source_dict->GetInteger("id", &source_id) ||
112 !source_dict->GetInteger("type", &source_type)) {
113 *source = Source();
114 return false;
115 }
116
117 DCHECK_LE(0, source_id);
118 DCHECK_LT(source_type, NetLog::SOURCE_COUNT);
119 *source = Source(static_cast<SourceType>(source_type), source_id);
120 return true;
121 }
122
ToValue() const123 base::Value* NetLog::Entry::ToValue() const {
124 base::DictionaryValue* entry_dict(new base::DictionaryValue());
125
126 entry_dict->SetString("time", TickCountToString(data_->time));
127
128 // Set the entry source.
129 base::DictionaryValue* source_dict = new base::DictionaryValue();
130 source_dict->SetInteger("id", data_->source.id);
131 source_dict->SetInteger("type", static_cast<int>(data_->source.type));
132 entry_dict->Set("source", source_dict);
133
134 // Set the event info.
135 entry_dict->SetInteger("type", static_cast<int>(data_->type));
136 entry_dict->SetInteger("phase", static_cast<int>(data_->phase));
137
138 // Set the event-specific parameters.
139 if (data_->parameters_callback) {
140 base::Value* value = data_->parameters_callback->Run(log_level_);
141 if (value)
142 entry_dict->Set("params", value);
143 }
144
145 return entry_dict;
146 }
147
ParametersToValue() const148 base::Value* NetLog::Entry::ParametersToValue() const {
149 if (data_->parameters_callback)
150 return data_->parameters_callback->Run(log_level_);
151 return NULL;
152 }
153
EntryData(EventType type,Source source,EventPhase phase,base::TimeTicks time,const ParametersCallback * parameters_callback)154 NetLog::EntryData::EntryData(
155 EventType type,
156 Source source,
157 EventPhase phase,
158 base::TimeTicks time,
159 const ParametersCallback* parameters_callback)
160 : type(type),
161 source(source),
162 phase(phase),
163 time(time),
164 parameters_callback(parameters_callback) {
165 }
166
~EntryData()167 NetLog::EntryData::~EntryData() {
168 }
169
Entry(const EntryData * data,LogLevel log_level)170 NetLog::Entry::Entry(const EntryData* data, LogLevel log_level)
171 : data_(data), log_level_(log_level) {
172 }
173
~Entry()174 NetLog::Entry::~Entry() {
175 }
176
ThreadSafeObserver()177 NetLog::ThreadSafeObserver::ThreadSafeObserver() : log_level_(LOG_NONE),
178 net_log_(NULL) {
179 }
180
~ThreadSafeObserver()181 NetLog::ThreadSafeObserver::~ThreadSafeObserver() {
182 // Make sure we aren't watching a NetLog on destruction. Because the NetLog
183 // may pass events to each observer on multiple threads, we cannot safely
184 // stop watching a NetLog automatically from a parent class.
185 DCHECK(!net_log_);
186 }
187
log_level() const188 NetLog::LogLevel NetLog::ThreadSafeObserver::log_level() const {
189 DCHECK(net_log_);
190 return log_level_;
191 }
192
net_log() const193 NetLog* NetLog::ThreadSafeObserver::net_log() const {
194 return net_log_;
195 }
196
OnAddEntryData(const EntryData & entry_data)197 void NetLog::ThreadSafeObserver::OnAddEntryData(const EntryData& entry_data) {
198 OnAddEntry(Entry(&entry_data, log_level()));
199 }
200
NetLog()201 NetLog::NetLog()
202 : last_id_(0),
203 base_log_level_(LOG_NONE),
204 effective_log_level_(LOG_NONE) {
205 }
206
~NetLog()207 NetLog::~NetLog() {
208 }
209
AddGlobalEntry(EventType type)210 void NetLog::AddGlobalEntry(EventType type) {
211 AddEntry(type,
212 Source(net::NetLog::SOURCE_NONE, NextID()),
213 net::NetLog::PHASE_NONE,
214 NULL);
215 }
216
AddGlobalEntry(EventType type,const NetLog::ParametersCallback & parameters_callback)217 void NetLog::AddGlobalEntry(
218 EventType type,
219 const NetLog::ParametersCallback& parameters_callback) {
220 AddEntry(type,
221 Source(net::NetLog::SOURCE_NONE, NextID()),
222 net::NetLog::PHASE_NONE,
223 ¶meters_callback);
224 }
225
NextID()226 uint32 NetLog::NextID() {
227 return base::subtle::NoBarrier_AtomicIncrement(&last_id_, 1);
228 }
229
SetBaseLogLevel(LogLevel log_level)230 void NetLog::SetBaseLogLevel(LogLevel log_level) {
231 base::AutoLock lock(lock_);
232 base_log_level_ = log_level;
233
234 UpdateLogLevel();
235 }
236
GetLogLevel() const237 NetLog::LogLevel NetLog::GetLogLevel() const {
238 base::subtle::Atomic32 log_level =
239 base::subtle::NoBarrier_Load(&effective_log_level_);
240 return static_cast<net::NetLog::LogLevel>(log_level);
241 }
242
AddThreadSafeObserver(net::NetLog::ThreadSafeObserver * observer,LogLevel log_level)243 void NetLog::AddThreadSafeObserver(
244 net::NetLog::ThreadSafeObserver* observer,
245 LogLevel log_level) {
246 DCHECK_NE(LOG_NONE, log_level);
247 base::AutoLock lock(lock_);
248
249 DCHECK(!observer->net_log_);
250 DCHECK_EQ(LOG_NONE, observer->log_level_);
251 observers_.AddObserver(observer);
252 observer->net_log_ = this;
253 observer->log_level_ = log_level;
254 UpdateLogLevel();
255 }
256
SetObserverLogLevel(net::NetLog::ThreadSafeObserver * observer,LogLevel log_level)257 void NetLog::SetObserverLogLevel(
258 net::NetLog::ThreadSafeObserver* observer,
259 LogLevel log_level) {
260 DCHECK_NE(LOG_NONE, log_level);
261 base::AutoLock lock(lock_);
262
263 DCHECK(observers_.HasObserver(observer));
264 DCHECK_EQ(this, observer->net_log_);
265 DCHECK_NE(LOG_NONE, observer->log_level_);
266 observer->log_level_ = log_level;
267 UpdateLogLevel();
268 }
269
RemoveThreadSafeObserver(net::NetLog::ThreadSafeObserver * observer)270 void NetLog::RemoveThreadSafeObserver(
271 net::NetLog::ThreadSafeObserver* observer) {
272 base::AutoLock lock(lock_);
273
274 DCHECK(observers_.HasObserver(observer));
275 DCHECK_EQ(this, observer->net_log_);
276 DCHECK_NE(LOG_NONE, observer->log_level_);
277 observers_.RemoveObserver(observer);
278 observer->net_log_ = NULL;
279 observer->log_level_ = LOG_NONE;
280 UpdateLogLevel();
281 }
282
UpdateLogLevel()283 void NetLog::UpdateLogLevel() {
284 lock_.AssertAcquired();
285
286 // Look through all the observers and find the finest granularity
287 // log level (higher values of the enum imply *lower* log levels).
288 LogLevel new_effective_log_level = base_log_level_;
289 ObserverListBase<ThreadSafeObserver>::Iterator it(observers_);
290 ThreadSafeObserver* observer;
291 while ((observer = it.GetNext()) != NULL) {
292 new_effective_log_level =
293 std::min(new_effective_log_level, observer->log_level());
294 }
295 base::subtle::NoBarrier_Store(&effective_log_level_,
296 new_effective_log_level);
297 }
298
299 // static
TickCountToString(const base::TimeTicks & time)300 std::string NetLog::TickCountToString(const base::TimeTicks& time) {
301 int64 delta_time = (time - base::TimeTicks()).InMilliseconds();
302 return base::Int64ToString(delta_time);
303 }
304
305 // static
EventTypeToString(EventType event)306 const char* NetLog::EventTypeToString(EventType event) {
307 switch (event) {
308 #define EVENT_TYPE(label) case TYPE_ ## label: return #label;
309 #include "net/base/net_log_event_type_list.h"
310 #undef EVENT_TYPE
311 default:
312 NOTREACHED();
313 return NULL;
314 }
315 }
316
317 // static
GetEventTypesAsValue()318 base::Value* NetLog::GetEventTypesAsValue() {
319 base::DictionaryValue* dict = new base::DictionaryValue();
320 for (int i = 0; i < EVENT_COUNT; ++i) {
321 dict->SetInteger(EventTypeToString(static_cast<EventType>(i)), i);
322 }
323 return dict;
324 }
325
326 // static
SourceTypeToString(SourceType source)327 const char* NetLog::SourceTypeToString(SourceType source) {
328 switch (source) {
329 #define SOURCE_TYPE(label) case SOURCE_ ## label: return #label;
330 #include "net/base/net_log_source_type_list.h"
331 #undef SOURCE_TYPE
332 default:
333 NOTREACHED();
334 return NULL;
335 }
336 }
337
338 // static
GetSourceTypesAsValue()339 base::Value* NetLog::GetSourceTypesAsValue() {
340 base::DictionaryValue* dict = new base::DictionaryValue();
341 for (int i = 0; i < SOURCE_COUNT; ++i) {
342 dict->SetInteger(SourceTypeToString(static_cast<SourceType>(i)), i);
343 }
344 return dict;
345 }
346
347 // static
EventPhaseToString(EventPhase phase)348 const char* NetLog::EventPhaseToString(EventPhase phase) {
349 switch (phase) {
350 case PHASE_BEGIN:
351 return "PHASE_BEGIN";
352 case PHASE_END:
353 return "PHASE_END";
354 case PHASE_NONE:
355 return "PHASE_NONE";
356 }
357 NOTREACHED();
358 return NULL;
359 }
360
361 // static
IsLoggingBytes(LogLevel log_level)362 bool NetLog::IsLoggingBytes(LogLevel log_level) {
363 return log_level == NetLog::LOG_ALL;
364 }
365
366 // static
IsLogging(LogLevel log_level)367 bool NetLog::IsLogging(LogLevel log_level) {
368 return log_level < NetLog::LOG_NONE;
369 }
370
371 // static
IntegerCallback(const char * name,int value)372 NetLog::ParametersCallback NetLog::IntegerCallback(const char* name,
373 int value) {
374 return base::Bind(&NetLogIntegerCallback, name, value);
375 }
376
377 // static
Int64Callback(const char * name,int64 value)378 NetLog::ParametersCallback NetLog::Int64Callback(const char* name,
379 int64 value) {
380 return base::Bind(&NetLogInt64Callback, name, value);
381 }
382
383 // static
StringCallback(const char * name,const std::string * value)384 NetLog::ParametersCallback NetLog::StringCallback(const char* name,
385 const std::string* value) {
386 DCHECK(value);
387 return base::Bind(&NetLogStringCallback, name, value);
388 }
389
390 // static
StringCallback(const char * name,const base::string16 * value)391 NetLog::ParametersCallback NetLog::StringCallback(const char* name,
392 const base::string16* value) {
393 DCHECK(value);
394 return base::Bind(&NetLogString16Callback, name, value);
395 }
396
AddEntry(EventType type,const Source & source,EventPhase phase,const NetLog::ParametersCallback * parameters_callback)397 void NetLog::AddEntry(EventType type,
398 const Source& source,
399 EventPhase phase,
400 const NetLog::ParametersCallback* parameters_callback) {
401 if (GetLogLevel() == LOG_NONE)
402 return;
403 EntryData entry_data(type, source, phase, base::TimeTicks::Now(),
404 parameters_callback);
405
406 // Notify all of the log observers.
407 base::AutoLock lock(lock_);
408 FOR_EACH_OBSERVER(ThreadSafeObserver, observers_, OnAddEntryData(entry_data));
409 }
410
AddEntry(NetLog::EventType type,NetLog::EventPhase phase) const411 void BoundNetLog::AddEntry(NetLog::EventType type,
412 NetLog::EventPhase phase) const {
413 if (!net_log_)
414 return;
415 net_log_->AddEntry(type, source_, phase, NULL);
416 }
417
AddEntry(NetLog::EventType type,NetLog::EventPhase phase,const NetLog::ParametersCallback & get_parameters) const418 void BoundNetLog::AddEntry(
419 NetLog::EventType type,
420 NetLog::EventPhase phase,
421 const NetLog::ParametersCallback& get_parameters) const {
422 if (!net_log_)
423 return;
424 net_log_->AddEntry(type, source_, phase, &get_parameters);
425 }
426
AddEvent(NetLog::EventType type) const427 void BoundNetLog::AddEvent(NetLog::EventType type) const {
428 AddEntry(type, NetLog::PHASE_NONE);
429 }
430
AddEvent(NetLog::EventType type,const NetLog::ParametersCallback & get_parameters) const431 void BoundNetLog::AddEvent(
432 NetLog::EventType type,
433 const NetLog::ParametersCallback& get_parameters) const {
434 AddEntry(type, NetLog::PHASE_NONE, get_parameters);
435 }
436
BeginEvent(NetLog::EventType type) const437 void BoundNetLog::BeginEvent(NetLog::EventType type) const {
438 AddEntry(type, NetLog::PHASE_BEGIN);
439 }
440
BeginEvent(NetLog::EventType type,const NetLog::ParametersCallback & get_parameters) const441 void BoundNetLog::BeginEvent(
442 NetLog::EventType type,
443 const NetLog::ParametersCallback& get_parameters) const {
444 AddEntry(type, NetLog::PHASE_BEGIN, get_parameters);
445 }
446
EndEvent(NetLog::EventType type) const447 void BoundNetLog::EndEvent(NetLog::EventType type) const {
448 AddEntry(type, NetLog::PHASE_END);
449 }
450
EndEvent(NetLog::EventType type,const NetLog::ParametersCallback & get_parameters) const451 void BoundNetLog::EndEvent(
452 NetLog::EventType type,
453 const NetLog::ParametersCallback& get_parameters) const {
454 AddEntry(type, NetLog::PHASE_END, get_parameters);
455 }
456
AddEventWithNetErrorCode(NetLog::EventType event_type,int net_error) const457 void BoundNetLog::AddEventWithNetErrorCode(NetLog::EventType event_type,
458 int net_error) const {
459 DCHECK_NE(ERR_IO_PENDING, net_error);
460 if (net_error >= 0) {
461 AddEvent(event_type);
462 } else {
463 AddEvent(event_type, NetLog::IntegerCallback("net_error", net_error));
464 }
465 }
466
EndEventWithNetErrorCode(NetLog::EventType event_type,int net_error) const467 void BoundNetLog::EndEventWithNetErrorCode(NetLog::EventType event_type,
468 int net_error) const {
469 DCHECK_NE(ERR_IO_PENDING, net_error);
470 if (net_error >= 0) {
471 EndEvent(event_type);
472 } else {
473 EndEvent(event_type, NetLog::IntegerCallback("net_error", net_error));
474 }
475 }
476
AddByteTransferEvent(NetLog::EventType event_type,int byte_count,const char * bytes) const477 void BoundNetLog::AddByteTransferEvent(NetLog::EventType event_type,
478 int byte_count,
479 const char* bytes) const {
480 AddEvent(event_type, base::Bind(BytesTransferredCallback, byte_count, bytes));
481 }
482
GetLogLevel() const483 NetLog::LogLevel BoundNetLog::GetLogLevel() const {
484 if (net_log_)
485 return net_log_->GetLogLevel();
486 return NetLog::LOG_NONE;
487 }
488
IsLoggingBytes() const489 bool BoundNetLog::IsLoggingBytes() const {
490 return NetLog::IsLoggingBytes(GetLogLevel());
491 }
492
IsLogging() const493 bool BoundNetLog::IsLogging() const {
494 return NetLog::IsLogging(GetLogLevel());
495 }
496
497 // static
Make(NetLog * net_log,NetLog::SourceType source_type)498 BoundNetLog BoundNetLog::Make(NetLog* net_log,
499 NetLog::SourceType source_type) {
500 if (!net_log)
501 return BoundNetLog();
502
503 NetLog::Source source(source_type, net_log->NextID());
504 return BoundNetLog(source, net_log);
505 }
506
507 } // namespace net
508