1 // Copyright 2012 The Chromium Authors
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/log/net_log.h"
6
7 #include "base/check_op.h"
8 #include "base/containers/contains.h"
9 #include "base/no_destructor.h"
10 #include "base/notreached.h"
11 #include "base/ranges/algorithm.h"
12 #include "base/strings/string_number_conversions.h"
13 #include "base/values.h"
14 #include "net/log/net_log_values.h"
15
16 namespace net {
17
18 NetLog::ThreadSafeObserver::ThreadSafeObserver() = default;
19
~ThreadSafeObserver()20 NetLog::ThreadSafeObserver::~ThreadSafeObserver() {
21 // Make sure we aren't watching a NetLog on destruction. Because the NetLog
22 // may pass events to each observer on multiple threads, we cannot safely
23 // stop watching a NetLog automatically from a parent class.
24 DCHECK(!net_log_);
25 }
26
capture_mode() const27 NetLogCaptureMode NetLog::ThreadSafeObserver::capture_mode() const {
28 DCHECK(net_log_);
29 return capture_mode_;
30 }
31
net_log() const32 NetLog* NetLog::ThreadSafeObserver::net_log() const {
33 return net_log_;
34 }
35
36 NetLog::ThreadSafeCaptureModeObserver::ThreadSafeCaptureModeObserver() =
37 default;
38 NetLog::ThreadSafeCaptureModeObserver::~ThreadSafeCaptureModeObserver() =
39 default;
40
41 NetLogCaptureModeSet
GetObserverCaptureModes() const42 NetLog::ThreadSafeCaptureModeObserver::GetObserverCaptureModes() const {
43 DCHECK(net_log_);
44 return net_log_->GetObserverCaptureModes();
45 }
46
47 void NetLog::ThreadSafeCaptureModeObserver::
AddEntryAtTimeWithMaterializedParams(NetLogEventType type,const NetLogSource & source,NetLogEventPhase phase,base::TimeTicks time,base::Value::Dict params)48 AddEntryAtTimeWithMaterializedParams(NetLogEventType type,
49 const NetLogSource& source,
50 NetLogEventPhase phase,
51 base::TimeTicks time,
52 base::Value::Dict params) {
53 DCHECK(net_log_);
54 net_log_->AddEntryAtTimeWithMaterializedParams(type, source, phase, time,
55 std::move(params));
56 }
57
58 // static
Get()59 NetLog* NetLog::Get() {
60 static base::NoDestructor<NetLog> instance{base::PassKey<NetLog>()};
61 return instance.get();
62 }
63
NetLog(base::PassKey<NetLog>)64 NetLog::NetLog(base::PassKey<NetLog>) {}
NetLog(base::PassKey<NetLogWithSource>)65 NetLog::NetLog(base::PassKey<NetLogWithSource>) {}
66
AddEntry(NetLogEventType type,const NetLogSource & source,NetLogEventPhase phase)67 void NetLog::AddEntry(NetLogEventType type,
68 const NetLogSource& source,
69 NetLogEventPhase phase) {
70 AddEntry(type, source, phase, [] { return base::Value::Dict(); });
71 }
72
AddGlobalEntry(NetLogEventType type)73 void NetLog::AddGlobalEntry(NetLogEventType type) {
74 AddEntry(type, NetLogSource(NetLogSourceType::NONE, NextID()),
75 NetLogEventPhase::NONE);
76 }
77
AddGlobalEntryWithStringParams(NetLogEventType type,std::string_view name,std::string_view value)78 void NetLog::AddGlobalEntryWithStringParams(NetLogEventType type,
79 std::string_view name,
80 std::string_view value) {
81 AddGlobalEntry(type, [&] { return NetLogParamsWithString(name, value); });
82 }
83
NextID()84 uint32_t NetLog::NextID() {
85 return base::subtle::NoBarrier_AtomicIncrement(&last_id_, 1);
86 }
87
AddObserver(NetLog::ThreadSafeObserver * observer,NetLogCaptureMode capture_mode)88 void NetLog::AddObserver(NetLog::ThreadSafeObserver* observer,
89 NetLogCaptureMode capture_mode) {
90 base::AutoLock lock(lock_);
91
92 DCHECK(!observer->net_log_);
93 DCHECK(!HasObserver(observer));
94 DCHECK_LT(observers_.size(), 20u); // Performance sanity check.
95
96 observers_.push_back(observer);
97
98 observer->net_log_ = this;
99 observer->capture_mode_ = capture_mode;
100 UpdateObserverCaptureModes();
101 }
102
RemoveObserver(NetLog::ThreadSafeObserver * observer)103 void NetLog::RemoveObserver(NetLog::ThreadSafeObserver* observer) {
104 base::AutoLock lock(lock_);
105
106 DCHECK_EQ(this, observer->net_log_);
107
108 auto it = base::ranges::find(observers_, observer);
109 DCHECK(it != observers_.end());
110 observers_.erase(it);
111
112 observer->net_log_ = nullptr;
113 observer->capture_mode_ = NetLogCaptureMode::kDefault;
114 UpdateObserverCaptureModes();
115 }
116
AddCaptureModeObserver(NetLog::ThreadSafeCaptureModeObserver * observer)117 void NetLog::AddCaptureModeObserver(
118 NetLog::ThreadSafeCaptureModeObserver* observer) {
119 base::AutoLock lock(lock_);
120
121 DCHECK(!observer->net_log_);
122 DCHECK(!HasCaptureModeObserver(observer));
123 DCHECK_LT(capture_mode_observers_.size(), 20u); // Performance sanity check.
124
125 observer->net_log_ = this;
126 capture_mode_observers_.push_back(observer);
127 }
128
RemoveCaptureModeObserver(NetLog::ThreadSafeCaptureModeObserver * observer)129 void NetLog::RemoveCaptureModeObserver(
130 NetLog::ThreadSafeCaptureModeObserver* observer) {
131 base::AutoLock lock(lock_);
132
133 DCHECK_EQ(this, observer->net_log_);
134 DCHECK(HasCaptureModeObserver(observer));
135
136 auto it = base::ranges::find(capture_mode_observers_, observer);
137 DCHECK(it != capture_mode_observers_.end());
138 capture_mode_observers_.erase(it);
139
140 observer->net_log_ = nullptr;
141 }
142
UpdateObserverCaptureModes()143 void NetLog::UpdateObserverCaptureModes() {
144 lock_.AssertAcquired();
145
146 NetLogCaptureModeSet capture_mode_set = 0;
147 for (const net::NetLog::ThreadSafeObserver* observer : observers_) {
148 NetLogCaptureModeSetAdd(observer->capture_mode_, &capture_mode_set);
149 }
150
151 base::subtle::NoBarrier_Store(&observer_capture_modes_, capture_mode_set);
152
153 // Notify any capture mode observers with the new |capture_mode_set|.
154 for (net::NetLog::ThreadSafeCaptureModeObserver* capture_mode_observer :
155 capture_mode_observers_) {
156 capture_mode_observer->OnCaptureModeUpdated(capture_mode_set);
157 }
158 }
159
HasObserver(ThreadSafeObserver * observer)160 bool NetLog::HasObserver(ThreadSafeObserver* observer) {
161 lock_.AssertAcquired();
162 return base::Contains(observers_, observer);
163 }
164
HasCaptureModeObserver(ThreadSafeCaptureModeObserver * observer)165 bool NetLog::HasCaptureModeObserver(ThreadSafeCaptureModeObserver* observer) {
166 lock_.AssertAcquired();
167 return base::Contains(capture_mode_observers_, observer);
168 }
169
170 // static
TickCountToString(const base::TimeTicks & time)171 std::string NetLog::TickCountToString(const base::TimeTicks& time) {
172 int64_t delta_time = time.since_origin().InMilliseconds();
173 // TODO(https://crbug.com/915391): Use NetLogNumberValue().
174 return base::NumberToString(delta_time);
175 }
176
177 // static
TimeToString(const base::Time & time)178 std::string NetLog::TimeToString(const base::Time& time) {
179 // Convert the base::Time to its (approximate) equivalent in base::TimeTicks.
180 base::TimeTicks time_ticks =
181 base::TimeTicks::UnixEpoch() + (time - base::Time::UnixEpoch());
182 return TickCountToString(time_ticks);
183 }
184
185 // static
GetEventTypesAsValue()186 base::Value NetLog::GetEventTypesAsValue() {
187 base::Value::Dict dict;
188 for (int i = 0; i < static_cast<int>(NetLogEventType::COUNT); ++i) {
189 dict.Set(NetLogEventTypeToString(static_cast<NetLogEventType>(i)), i);
190 }
191 return base::Value(std::move(dict));
192 }
193
194 // static
SourceTypeToString(NetLogSourceType source)195 const char* NetLog::SourceTypeToString(NetLogSourceType source) {
196 switch (source) {
197 #define SOURCE_TYPE(label) \
198 case NetLogSourceType::label: \
199 return #label;
200 #include "net/log/net_log_source_type_list.h"
201 #undef SOURCE_TYPE
202 default:
203 NOTREACHED();
204 return nullptr;
205 }
206 }
207
208 // static
GetSourceTypesAsValue()209 base::Value NetLog::GetSourceTypesAsValue() {
210 base::Value::Dict dict;
211 for (int i = 0; i < static_cast<int>(NetLogSourceType::COUNT); ++i) {
212 dict.Set(SourceTypeToString(static_cast<NetLogSourceType>(i)), i);
213 }
214 return base::Value(std::move(dict));
215 }
216
217 // static
EventPhaseToString(NetLogEventPhase phase)218 const char* NetLog::EventPhaseToString(NetLogEventPhase phase) {
219 switch (phase) {
220 case NetLogEventPhase::BEGIN:
221 return "PHASE_BEGIN";
222 case NetLogEventPhase::END:
223 return "PHASE_END";
224 case NetLogEventPhase::NONE:
225 return "PHASE_NONE";
226 }
227 NOTREACHED();
228 return nullptr;
229 }
230
InitializeSourceIdPartition()231 void NetLog::InitializeSourceIdPartition() {
232 int32_t old_value = base::subtle::NoBarrier_AtomicExchange(
233 &last_id_, std::numeric_limits<base::subtle::Atomic32>::min());
234 DCHECK_EQ(old_value, 0) << " NetLog::InitializeSourceIdPartition() called "
235 "after NextID() or called multiple times";
236 }
237
AddEntryInternal(NetLogEventType type,const NetLogSource & source,NetLogEventPhase phase,const GetParamsInterface * get_params)238 void NetLog::AddEntryInternal(NetLogEventType type,
239 const NetLogSource& source,
240 NetLogEventPhase phase,
241 const GetParamsInterface* get_params) {
242 NetLogCaptureModeSet observer_capture_modes = GetObserverCaptureModes();
243
244 for (int i = 0; i <= static_cast<int>(NetLogCaptureMode::kLast); ++i) {
245 NetLogCaptureMode capture_mode = static_cast<NetLogCaptureMode>(i);
246 if (!NetLogCaptureModeSetContains(capture_mode, observer_capture_modes))
247 continue;
248
249 NetLogEntry entry(type, source, phase, base::TimeTicks::Now(),
250 get_params->GetParams(capture_mode));
251
252 // Notify all of the log observers with |capture_mode|.
253 base::AutoLock lock(lock_);
254 for (net::NetLog::ThreadSafeObserver* observer : observers_) {
255 if (observer->capture_mode() == capture_mode)
256 observer->OnAddEntry(entry);
257 }
258 }
259 }
260
AddEntryWithMaterializedParams(NetLogEventType type,const NetLogSource & source,NetLogEventPhase phase,base::Value::Dict params)261 void NetLog::AddEntryWithMaterializedParams(NetLogEventType type,
262 const NetLogSource& source,
263 NetLogEventPhase phase,
264 base::Value::Dict params) {
265 AddEntryAtTimeWithMaterializedParams(
266 type, source, phase, base::TimeTicks::Now(), std::move(params));
267 }
268
AddEntryAtTimeWithMaterializedParams(NetLogEventType type,const NetLogSource & source,NetLogEventPhase phase,base::TimeTicks time,base::Value::Dict params)269 void NetLog::AddEntryAtTimeWithMaterializedParams(NetLogEventType type,
270 const NetLogSource& source,
271 NetLogEventPhase phase,
272 base::TimeTicks time,
273 base::Value::Dict params) {
274 NetLogEntry entry(type, source, phase, time, std::move(params));
275
276 // Notify all of the log observers, regardless of capture mode.
277 base::AutoLock lock(lock_);
278 for (net::NetLog::ThreadSafeObserver* observer : observers_) {
279 observer->OnAddEntry(entry);
280 }
281 }
282
283 } // namespace net
284