| // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "net/log/net_log.h" |
| |
| #include <utility> |
| |
| #include "base/bind.h" |
| #include "base/debug/alias.h" |
| #include "base/logging.h" |
| #include "base/strings/string_number_conversions.h" |
| #include "base/strings/utf_string_conversions.h" |
| #include "base/time/time.h" |
| #include "base/values.h" |
| #include "net/base/net_errors.h" |
| |
| namespace net { |
| |
| namespace { |
| |
| // Returns parameters for logging data transferred events. At a minimum includes |
| // the number of bytes transferred. If the capture mode allows logging byte |
| // contents and |byte_count| > 0, then will include the actual bytes. The |
| // bytes are hex-encoded, since base::StringValue only supports UTF-8. |
| std::unique_ptr<base::Value> BytesTransferredCallback( |
| int byte_count, |
| const char* bytes, |
| NetLogCaptureMode capture_mode) { |
| std::unique_ptr<base::DictionaryValue> dict(new base::DictionaryValue()); |
| dict->SetInteger("byte_count", byte_count); |
| if (capture_mode.include_socket_bytes() && byte_count > 0) |
| dict->SetString("hex_encoded_bytes", base::HexEncode(bytes, byte_count)); |
| return std::move(dict); |
| } |
| |
| std::unique_ptr<base::Value> SourceEventParametersCallback( |
| const NetLog::Source source, |
| NetLogCaptureMode /* capture_mode */) { |
| if (!source.IsValid()) |
| return std::unique_ptr<base::Value>(); |
| std::unique_ptr<base::DictionaryValue> event_params( |
| new base::DictionaryValue()); |
| source.AddToEventParameters(event_params.get()); |
| return std::move(event_params); |
| } |
| |
| std::unique_ptr<base::Value> NetLogBoolCallback( |
| const char* name, |
| bool value, |
| NetLogCaptureMode /* capture_mode */) { |
| std::unique_ptr<base::DictionaryValue> event_params( |
| new base::DictionaryValue()); |
| event_params->SetBoolean(name, value); |
| return std::move(event_params); |
| } |
| |
| std::unique_ptr<base::Value> NetLogIntCallback( |
| const char* name, |
| int value, |
| NetLogCaptureMode /* capture_mode */) { |
| std::unique_ptr<base::DictionaryValue> event_params( |
| new base::DictionaryValue()); |
| event_params->SetInteger(name, value); |
| return std::move(event_params); |
| } |
| |
| std::unique_ptr<base::Value> NetLogInt64Callback( |
| const char* name, |
| int64_t value, |
| NetLogCaptureMode /* capture_mode */) { |
| std::unique_ptr<base::DictionaryValue> event_params( |
| new base::DictionaryValue()); |
| event_params->SetString(name, base::Int64ToString(value)); |
| return std::move(event_params); |
| } |
| |
| std::unique_ptr<base::Value> NetLogStringCallback( |
| const char* name, |
| const std::string* value, |
| NetLogCaptureMode /* capture_mode */) { |
| std::unique_ptr<base::DictionaryValue> event_params( |
| new base::DictionaryValue()); |
| event_params->SetString(name, *value); |
| return std::move(event_params); |
| } |
| |
| std::unique_ptr<base::Value> NetLogCharStringCallback( |
| const char* name, |
| const char* value, |
| NetLogCaptureMode /* capture_mode */) { |
| std::unique_ptr<base::DictionaryValue> event_params( |
| new base::DictionaryValue()); |
| event_params->SetString(name, value); |
| return std::move(event_params); |
| } |
| |
| std::unique_ptr<base::Value> NetLogString16Callback( |
| const char* name, |
| const base::string16* value, |
| NetLogCaptureMode /* capture_mode */) { |
| std::unique_ptr<base::DictionaryValue> event_params( |
| new base::DictionaryValue()); |
| event_params->SetString(name, *value); |
| return std::move(event_params); |
| } |
| |
| } // namespace |
| |
| // LoadTimingInfo requires this be 0. |
| const uint32_t NetLog::Source::kInvalidId = 0; |
| |
| NetLog::Source::Source() : type(SOURCE_NONE), id(kInvalidId) { |
| } |
| |
| NetLog::Source::Source(SourceType type, uint32_t id) : type(type), id(id) {} |
| |
| bool NetLog::Source::IsValid() const { |
| return id != kInvalidId; |
| } |
| |
| void NetLog::Source::AddToEventParameters( |
| base::DictionaryValue* event_params) const { |
| std::unique_ptr<base::DictionaryValue> dict(new base::DictionaryValue()); |
| dict->SetInteger("type", static_cast<int>(type)); |
| dict->SetInteger("id", static_cast<int>(id)); |
| event_params->Set("source_dependency", std::move(dict)); |
| } |
| |
| NetLog::ParametersCallback NetLog::Source::ToEventParametersCallback() const { |
| return base::Bind(&SourceEventParametersCallback, *this); |
| } |
| |
| // static |
| bool NetLog::Source::FromEventParameters(base::Value* event_params, |
| Source* source) { |
| base::DictionaryValue* dict = NULL; |
| base::DictionaryValue* source_dict = NULL; |
| int source_id = -1; |
| int source_type = NetLog::SOURCE_COUNT; |
| if (!event_params || !event_params->GetAsDictionary(&dict) || |
| !dict->GetDictionary("source_dependency", &source_dict) || |
| !source_dict->GetInteger("id", &source_id) || |
| !source_dict->GetInteger("type", &source_type)) { |
| *source = Source(); |
| return false; |
| } |
| |
| DCHECK_GE(source_id, 0); |
| DCHECK_LT(source_type, NetLog::SOURCE_COUNT); |
| *source = Source(static_cast<SourceType>(source_type), source_id); |
| return true; |
| } |
| |
| std::unique_ptr<base::Value> NetLog::Entry::ToValue() const { |
| std::unique_ptr<base::DictionaryValue> entry_dict( |
| new base::DictionaryValue()); |
| |
| entry_dict->SetString("time", TickCountToString(data_->time)); |
| |
| // Set the entry source. |
| std::unique_ptr<base::DictionaryValue> source_dict( |
| new base::DictionaryValue()); |
| source_dict->SetInteger("id", data_->source.id); |
| source_dict->SetInteger("type", static_cast<int>(data_->source.type)); |
| entry_dict->Set("source", std::move(source_dict)); |
| |
| // Set the event info. |
| entry_dict->SetInteger("type", static_cast<int>(data_->type)); |
| entry_dict->SetInteger("phase", static_cast<int>(data_->phase)); |
| |
| // Set the event-specific parameters. |
| if (data_->parameters_callback) { |
| std::unique_ptr<base::Value> value( |
| data_->parameters_callback->Run(capture_mode_)); |
| if (value) |
| entry_dict->Set("params", std::move(value)); |
| } |
| |
| return std::move(entry_dict); |
| } |
| |
| std::unique_ptr<base::Value> NetLog::Entry::ParametersToValue() const { |
| if (data_->parameters_callback) |
| return data_->parameters_callback->Run(capture_mode_); |
| return nullptr; |
| } |
| |
| NetLog::EntryData::EntryData(EventType type, |
| Source source, |
| EventPhase phase, |
| base::TimeTicks time, |
| const ParametersCallback* parameters_callback) |
| : type(type), |
| source(source), |
| phase(phase), |
| time(time), |
| parameters_callback(parameters_callback) { |
| } |
| |
| NetLog::EntryData::~EntryData() { |
| } |
| |
| NetLog::Entry::Entry(const EntryData* data, NetLogCaptureMode capture_mode) |
| : data_(data), capture_mode_(capture_mode) { |
| } |
| |
| NetLog::Entry::~Entry() { |
| } |
| |
| NetLog::ThreadSafeObserver::ThreadSafeObserver() : net_log_(NULL) { |
| } |
| |
| NetLog::ThreadSafeObserver::~ThreadSafeObserver() { |
| // Make sure we aren't watching a NetLog on destruction. Because the NetLog |
| // may pass events to each observer on multiple threads, we cannot safely |
| // stop watching a NetLog automatically from a parent class. |
| DCHECK(!net_log_); |
| } |
| |
| NetLogCaptureMode NetLog::ThreadSafeObserver::capture_mode() const { |
| DCHECK(net_log_); |
| return capture_mode_; |
| } |
| |
| NetLog* NetLog::ThreadSafeObserver::net_log() const { |
| return net_log_; |
| } |
| |
| void NetLog::ThreadSafeObserver::OnAddEntryData(const EntryData& entry_data) { |
| OnAddEntry(Entry(&entry_data, capture_mode())); |
| } |
| |
| NetLog::NetLog() : last_id_(0), is_capturing_(0) { |
| } |
| |
| NetLog::~NetLog() { |
| } |
| |
| void NetLog::AddGlobalEntry(EventType type) { |
| AddEntry(type, Source(NetLog::SOURCE_NONE, NextID()), NetLog::PHASE_NONE, |
| NULL); |
| } |
| |
| void NetLog::AddGlobalEntry( |
| EventType type, |
| const NetLog::ParametersCallback& parameters_callback) { |
| AddEntry(type, Source(NetLog::SOURCE_NONE, NextID()), NetLog::PHASE_NONE, |
| ¶meters_callback); |
| } |
| |
| uint32_t NetLog::NextID() { |
| return base::subtle::NoBarrier_AtomicIncrement(&last_id_, 1); |
| } |
| |
| bool NetLog::IsCapturing() const { |
| return base::subtle::NoBarrier_Load(&is_capturing_) != 0; |
| } |
| |
| void NetLog::DeprecatedAddObserver(NetLog::ThreadSafeObserver* observer, |
| NetLogCaptureMode capture_mode) { |
| base::AutoLock lock(lock_); |
| |
| DCHECK(!observer->net_log_); |
| observers_.AddObserver(observer); |
| observer->net_log_ = this; |
| observer->capture_mode_ = capture_mode; |
| UpdateIsCapturing(); |
| } |
| |
| void NetLog::SetObserverCaptureMode(NetLog::ThreadSafeObserver* observer, |
| NetLogCaptureMode capture_mode) { |
| base::AutoLock lock(lock_); |
| |
| DCHECK(observers_.HasObserver(observer)); |
| DCHECK_EQ(this, observer->net_log_); |
| observer->capture_mode_ = capture_mode; |
| } |
| |
| void NetLog::DeprecatedRemoveObserver(NetLog::ThreadSafeObserver* observer) { |
| base::AutoLock lock(lock_); |
| |
| DCHECK(observers_.HasObserver(observer)); |
| DCHECK_EQ(this, observer->net_log_); |
| observers_.RemoveObserver(observer); |
| observer->net_log_ = NULL; |
| observer->capture_mode_ = NetLogCaptureMode(); |
| UpdateIsCapturing(); |
| } |
| |
| void NetLog::UpdateIsCapturing() { |
| lock_.AssertAcquired(); |
| base::subtle::NoBarrier_Store(&is_capturing_, |
| observers_.might_have_observers() ? 1 : 0); |
| } |
| |
| // static |
| std::string NetLog::TickCountToString(const base::TimeTicks& time) { |
| int64_t delta_time = (time - base::TimeTicks()).InMilliseconds(); |
| return base::Int64ToString(delta_time); |
| } |
| |
| // static |
| const char* NetLog::EventTypeToString(EventType event) { |
| switch (event) { |
| #define EVENT_TYPE(label) \ |
| case TYPE_##label: \ |
| return #label; |
| #include "net/log/net_log_event_type_list.h" |
| #undef EVENT_TYPE |
| default: |
| NOTREACHED(); |
| return NULL; |
| } |
| } |
| |
| // static |
| base::Value* NetLog::GetEventTypesAsValue() { |
| std::unique_ptr<base::DictionaryValue> dict(new base::DictionaryValue()); |
| for (int i = 0; i < EVENT_COUNT; ++i) { |
| dict->SetInteger(EventTypeToString(static_cast<EventType>(i)), i); |
| } |
| return dict.release(); |
| } |
| |
| // static |
| const char* NetLog::SourceTypeToString(SourceType source) { |
| switch (source) { |
| #define SOURCE_TYPE(label) \ |
| case SOURCE_##label: \ |
| return #label; |
| #include "net/log/net_log_source_type_list.h" |
| #undef SOURCE_TYPE |
| default: |
| NOTREACHED(); |
| return NULL; |
| } |
| } |
| |
| // static |
| base::Value* NetLog::GetSourceTypesAsValue() { |
| std::unique_ptr<base::DictionaryValue> dict(new base::DictionaryValue()); |
| for (int i = 0; i < SOURCE_COUNT; ++i) { |
| dict->SetInteger(SourceTypeToString(static_cast<SourceType>(i)), i); |
| } |
| return dict.release(); |
| } |
| |
| // static |
| const char* NetLog::EventPhaseToString(EventPhase phase) { |
| switch (phase) { |
| case PHASE_BEGIN: |
| return "PHASE_BEGIN"; |
| case PHASE_END: |
| return "PHASE_END"; |
| case PHASE_NONE: |
| return "PHASE_NONE"; |
| } |
| NOTREACHED(); |
| return NULL; |
| } |
| |
| // static |
| NetLog::ParametersCallback NetLog::BoolCallback(const char* name, bool value) { |
| return base::Bind(&NetLogBoolCallback, name, value); |
| } |
| |
| // static |
| NetLog::ParametersCallback NetLog::IntCallback(const char* name, int value) { |
| return base::Bind(&NetLogIntCallback, name, value); |
| } |
| |
| // static |
| NetLog::ParametersCallback NetLog::Int64Callback(const char* name, |
| int64_t value) { |
| return base::Bind(&NetLogInt64Callback, name, value); |
| } |
| |
| // static |
| NetLog::ParametersCallback NetLog::StringCallback(const char* name, |
| const std::string* value) { |
| DCHECK(value); |
| return base::Bind(&NetLogStringCallback, name, value); |
| } |
| |
| // static |
| NetLog::ParametersCallback NetLog::StringCallback(const char* name, |
| const char* value) { |
| DCHECK(value); |
| return base::Bind(&NetLogCharStringCallback, name, value); |
| } |
| |
| // static |
| NetLog::ParametersCallback NetLog::StringCallback(const char* name, |
| const base::string16* value) { |
| DCHECK(value); |
| return base::Bind(&NetLogString16Callback, name, value); |
| } |
| |
| void NetLog::AddEntry(EventType type, |
| const Source& source, |
| EventPhase phase, |
| const NetLog::ParametersCallback* parameters_callback) { |
| if (!IsCapturing()) |
| return; |
| EntryData entry_data(type, source, phase, base::TimeTicks::Now(), |
| parameters_callback); |
| |
| // Notify all of the log observers. |
| base::AutoLock lock(lock_); |
| FOR_EACH_OBSERVER(ThreadSafeObserver, observers_, OnAddEntryData(entry_data)); |
| } |
| |
| BoundNetLog::~BoundNetLog() { |
| liveness_ = DEAD; |
| } |
| |
| void BoundNetLog::AddEntry(NetLog::EventType type, |
| NetLog::EventPhase phase) const { |
| CrashIfInvalid(); |
| |
| if (!net_log_) |
| return; |
| net_log_->AddEntry(type, source_, phase, NULL); |
| } |
| |
| void BoundNetLog::AddEntry( |
| NetLog::EventType type, |
| NetLog::EventPhase phase, |
| const NetLog::ParametersCallback& get_parameters) const { |
| CrashIfInvalid(); |
| |
| if (!net_log_) |
| return; |
| net_log_->AddEntry(type, source_, phase, &get_parameters); |
| } |
| |
| void BoundNetLog::AddEvent(NetLog::EventType type) const { |
| AddEntry(type, NetLog::PHASE_NONE); |
| } |
| |
| void BoundNetLog::AddEvent( |
| NetLog::EventType type, |
| const NetLog::ParametersCallback& get_parameters) const { |
| AddEntry(type, NetLog::PHASE_NONE, get_parameters); |
| } |
| |
| void BoundNetLog::BeginEvent(NetLog::EventType type) const { |
| AddEntry(type, NetLog::PHASE_BEGIN); |
| } |
| |
| void BoundNetLog::BeginEvent( |
| NetLog::EventType type, |
| const NetLog::ParametersCallback& get_parameters) const { |
| AddEntry(type, NetLog::PHASE_BEGIN, get_parameters); |
| } |
| |
| void BoundNetLog::EndEvent(NetLog::EventType type) const { |
| AddEntry(type, NetLog::PHASE_END); |
| } |
| |
| void BoundNetLog::EndEvent( |
| NetLog::EventType type, |
| const NetLog::ParametersCallback& get_parameters) const { |
| AddEntry(type, NetLog::PHASE_END, get_parameters); |
| } |
| |
| void BoundNetLog::AddEventWithNetErrorCode(NetLog::EventType event_type, |
| int net_error) const { |
| DCHECK_NE(ERR_IO_PENDING, net_error); |
| if (net_error >= 0) { |
| AddEvent(event_type); |
| } else { |
| AddEvent(event_type, NetLog::IntCallback("net_error", net_error)); |
| } |
| } |
| |
| void BoundNetLog::EndEventWithNetErrorCode(NetLog::EventType event_type, |
| int net_error) const { |
| DCHECK_NE(ERR_IO_PENDING, net_error); |
| if (net_error >= 0) { |
| EndEvent(event_type); |
| } else { |
| EndEvent(event_type, NetLog::IntCallback("net_error", net_error)); |
| } |
| } |
| |
| void BoundNetLog::AddByteTransferEvent(NetLog::EventType event_type, |
| int byte_count, |
| const char* bytes) const { |
| AddEvent(event_type, base::Bind(BytesTransferredCallback, byte_count, bytes)); |
| } |
| |
| bool BoundNetLog::IsCapturing() const { |
| CrashIfInvalid(); |
| return net_log_ && net_log_->IsCapturing(); |
| } |
| |
| // static |
| BoundNetLog BoundNetLog::Make(NetLog* net_log, NetLog::SourceType source_type) { |
| if (!net_log) |
| return BoundNetLog(); |
| |
| NetLog::Source source(source_type, net_log->NextID()); |
| return BoundNetLog(source, net_log); |
| } |
| |
| void BoundNetLog::CrashIfInvalid() const { |
| Liveness liveness = liveness_; |
| |
| if (liveness == ALIVE) |
| return; |
| |
| base::debug::Alias(&liveness); |
| CHECK_EQ(ALIVE, liveness); |
| } |
| |
| } // namespace net |