| // Copyright 2012 The Chromium Authors |
| // 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 "base/check_op.h" |
| #include "base/containers/contains.h" |
| #include "base/no_destructor.h" |
| #include "base/notreached.h" |
| #include "base/ranges/algorithm.h" |
| #include "base/strings/string_number_conversions.h" |
| #include "base/values.h" |
| #include "net/log/net_log_values.h" |
| |
| namespace net { |
| |
| NetLog::ThreadSafeObserver::ThreadSafeObserver() = default; |
| |
| 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_; |
| } |
| |
| NetLog::ThreadSafeCaptureModeObserver::ThreadSafeCaptureModeObserver() = |
| default; |
| NetLog::ThreadSafeCaptureModeObserver::~ThreadSafeCaptureModeObserver() = |
| default; |
| |
| NetLogCaptureModeSet |
| NetLog::ThreadSafeCaptureModeObserver::GetObserverCaptureModes() const { |
| DCHECK(net_log_); |
| return net_log_->GetObserverCaptureModes(); |
| } |
| |
| void NetLog::ThreadSafeCaptureModeObserver:: |
| AddEntryAtTimeWithMaterializedParams(NetLogEventType type, |
| const NetLogSource& source, |
| NetLogEventPhase phase, |
| base::TimeTicks time, |
| base::Value::Dict params) { |
| DCHECK(net_log_); |
| net_log_->AddEntryAtTimeWithMaterializedParams(type, source, phase, time, |
| std::move(params)); |
| } |
| |
| // static |
| NetLog* NetLog::Get() { |
| static base::NoDestructor<NetLog> instance{base::PassKey<NetLog>()}; |
| return instance.get(); |
| } |
| |
| NetLog::NetLog(base::PassKey<NetLog>) {} |
| NetLog::NetLog(base::PassKey<NetLogWithSource>) {} |
| |
| void NetLog::AddEntry(NetLogEventType type, |
| const NetLogSource& source, |
| NetLogEventPhase phase) { |
| AddEntry(type, source, phase, [] { return base::Value::Dict(); }); |
| } |
| |
| void NetLog::AddGlobalEntry(NetLogEventType type) { |
| AddEntry(type, NetLogSource(NetLogSourceType::NONE, NextID()), |
| NetLogEventPhase::NONE); |
| } |
| |
| void NetLog::AddGlobalEntryWithStringParams(NetLogEventType type, |
| base::StringPiece name, |
| base::StringPiece value) { |
| AddGlobalEntry(type, [&] { return NetLogParamsWithString(name, value); }); |
| } |
| |
| uint32_t NetLog::NextID() { |
| return base::subtle::NoBarrier_AtomicIncrement(&last_id_, 1); |
| } |
| |
| void NetLog::AddObserver(NetLog::ThreadSafeObserver* observer, |
| NetLogCaptureMode capture_mode) { |
| base::AutoLock lock(lock_); |
| |
| DCHECK(!observer->net_log_); |
| DCHECK(!HasObserver(observer)); |
| DCHECK_LT(observers_.size(), 20u); // Performance sanity check. |
| |
| observers_.push_back(observer); |
| |
| observer->net_log_ = this; |
| observer->capture_mode_ = capture_mode; |
| UpdateObserverCaptureModes(); |
| } |
| |
| void NetLog::RemoveObserver(NetLog::ThreadSafeObserver* observer) { |
| base::AutoLock lock(lock_); |
| |
| DCHECK_EQ(this, observer->net_log_); |
| |
| auto it = base::ranges::find(observers_, observer); |
| DCHECK(it != observers_.end()); |
| observers_.erase(it); |
| |
| observer->net_log_ = nullptr; |
| observer->capture_mode_ = NetLogCaptureMode::kDefault; |
| UpdateObserverCaptureModes(); |
| } |
| |
| void NetLog::AddCaptureModeObserver( |
| NetLog::ThreadSafeCaptureModeObserver* observer) { |
| base::AutoLock lock(lock_); |
| |
| DCHECK(!observer->net_log_); |
| DCHECK(!HasCaptureModeObserver(observer)); |
| DCHECK_LT(capture_mode_observers_.size(), 20u); // Performance sanity check. |
| |
| observer->net_log_ = this; |
| capture_mode_observers_.push_back(observer); |
| } |
| |
| void NetLog::RemoveCaptureModeObserver( |
| NetLog::ThreadSafeCaptureModeObserver* observer) { |
| base::AutoLock lock(lock_); |
| |
| DCHECK_EQ(this, observer->net_log_); |
| DCHECK(HasCaptureModeObserver(observer)); |
| |
| auto it = base::ranges::find(capture_mode_observers_, observer); |
| DCHECK(it != capture_mode_observers_.end()); |
| capture_mode_observers_.erase(it); |
| |
| observer->net_log_ = nullptr; |
| } |
| |
| void NetLog::UpdateObserverCaptureModes() { |
| lock_.AssertAcquired(); |
| |
| NetLogCaptureModeSet capture_mode_set = 0; |
| for (const auto* observer : observers_) |
| NetLogCaptureModeSetAdd(observer->capture_mode_, &capture_mode_set); |
| |
| base::subtle::NoBarrier_Store(&observer_capture_modes_, capture_mode_set); |
| |
| // Notify any capture mode observers with the new |capture_mode_set|. |
| for (auto* capture_mode_observer : capture_mode_observers_) |
| capture_mode_observer->OnCaptureModeUpdated(capture_mode_set); |
| } |
| |
| bool NetLog::HasObserver(ThreadSafeObserver* observer) { |
| lock_.AssertAcquired(); |
| return base::Contains(observers_, observer); |
| } |
| |
| bool NetLog::HasCaptureModeObserver(ThreadSafeCaptureModeObserver* observer) { |
| lock_.AssertAcquired(); |
| return base::Contains(capture_mode_observers_, observer); |
| } |
| |
| // static |
| std::string NetLog::TickCountToString(const base::TimeTicks& time) { |
| int64_t delta_time = time.since_origin().InMilliseconds(); |
| // TODO(https://crbug.com/915391): Use NetLogNumberValue(). |
| return base::NumberToString(delta_time); |
| } |
| |
| // static |
| std::string NetLog::TimeToString(const base::Time& time) { |
| // Convert the base::Time to its (approximate) equivalent in base::TimeTicks. |
| base::TimeTicks time_ticks = |
| base::TimeTicks::UnixEpoch() + (time - base::Time::UnixEpoch()); |
| return TickCountToString(time_ticks); |
| } |
| |
| // static |
| base::Value NetLog::GetEventTypesAsValue() { |
| base::Value::Dict dict; |
| for (int i = 0; i < static_cast<int>(NetLogEventType::COUNT); ++i) { |
| dict.Set(NetLogEventTypeToString(static_cast<NetLogEventType>(i)), i); |
| } |
| return base::Value(std::move(dict)); |
| } |
| |
| // static |
| const char* NetLog::SourceTypeToString(NetLogSourceType source) { |
| switch (source) { |
| #define SOURCE_TYPE(label) \ |
| case NetLogSourceType::label: \ |
| return #label; |
| #include "net/log/net_log_source_type_list.h" |
| #undef SOURCE_TYPE |
| default: |
| NOTREACHED(); |
| return nullptr; |
| } |
| } |
| |
| // static |
| base::Value NetLog::GetSourceTypesAsValue() { |
| base::Value::Dict dict; |
| for (int i = 0; i < static_cast<int>(NetLogSourceType::COUNT); ++i) { |
| dict.Set(SourceTypeToString(static_cast<NetLogSourceType>(i)), i); |
| } |
| return base::Value(std::move(dict)); |
| } |
| |
| // static |
| const char* NetLog::EventPhaseToString(NetLogEventPhase phase) { |
| switch (phase) { |
| case NetLogEventPhase::BEGIN: |
| return "PHASE_BEGIN"; |
| case NetLogEventPhase::END: |
| return "PHASE_END"; |
| case NetLogEventPhase::NONE: |
| return "PHASE_NONE"; |
| } |
| NOTREACHED(); |
| return nullptr; |
| } |
| |
| void NetLog::InitializeSourceIdPartition() { |
| int32_t old_value = base::subtle::NoBarrier_AtomicExchange( |
| &last_id_, std::numeric_limits<base::subtle::Atomic32>::min()); |
| DCHECK_EQ(old_value, 0) << " NetLog::InitializeSourceIdPartition() called " |
| "after NextID() or called multiple times"; |
| } |
| |
| void NetLog::AddEntryInternal(NetLogEventType type, |
| const NetLogSource& source, |
| NetLogEventPhase phase, |
| const GetParamsInterface* get_params) { |
| NetLogCaptureModeSet observer_capture_modes = GetObserverCaptureModes(); |
| |
| for (int i = 0; i <= static_cast<int>(NetLogCaptureMode::kLast); ++i) { |
| NetLogCaptureMode capture_mode = static_cast<NetLogCaptureMode>(i); |
| if (!NetLogCaptureModeSetContains(capture_mode, observer_capture_modes)) |
| continue; |
| |
| NetLogEntry entry(type, source, phase, base::TimeTicks::Now(), |
| get_params->GetParams(capture_mode)); |
| |
| // Notify all of the log observers with |capture_mode|. |
| base::AutoLock lock(lock_); |
| for (auto* observer : observers_) { |
| if (observer->capture_mode() == capture_mode) |
| observer->OnAddEntry(entry); |
| } |
| } |
| } |
| |
| void NetLog::AddEntryWithMaterializedParams(NetLogEventType type, |
| const NetLogSource& source, |
| NetLogEventPhase phase, |
| base::Value::Dict params) { |
| AddEntryAtTimeWithMaterializedParams( |
| type, source, phase, base::TimeTicks::Now(), std::move(params)); |
| } |
| |
| void NetLog::AddEntryAtTimeWithMaterializedParams(NetLogEventType type, |
| const NetLogSource& source, |
| NetLogEventPhase phase, |
| base::TimeTicks time, |
| base::Value::Dict params) { |
| NetLogEntry entry(type, source, phase, time, std::move(params)); |
| |
| // Notify all of the log observers, regardless of capture mode. |
| base::AutoLock lock(lock_); |
| for (auto* observer : observers_) { |
| observer->OnAddEntry(entry); |
| } |
| } |
| |
| } // namespace net |