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,base::StringPiece name,base::StringPiece value)78 void NetLog::AddGlobalEntryWithStringParams(NetLogEventType type,
79 base::StringPiece name,
80 base::StringPiece 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 auto* observer : observers_)
148 NetLogCaptureModeSetAdd(observer->capture_mode_, &capture_mode_set);
149
150 base::subtle::NoBarrier_Store(&observer_capture_modes_, capture_mode_set);
151
152 // Notify any capture mode observers with the new |capture_mode_set|.
153 for (auto* capture_mode_observer : capture_mode_observers_)
154 capture_mode_observer->OnCaptureModeUpdated(capture_mode_set);
155 }
156
HasObserver(ThreadSafeObserver * observer)157 bool NetLog::HasObserver(ThreadSafeObserver* observer) {
158 lock_.AssertAcquired();
159 return base::Contains(observers_, observer);
160 }
161
HasCaptureModeObserver(ThreadSafeCaptureModeObserver * observer)162 bool NetLog::HasCaptureModeObserver(ThreadSafeCaptureModeObserver* observer) {
163 lock_.AssertAcquired();
164 return base::Contains(capture_mode_observers_, observer);
165 }
166
167 // static
TickCountToString(const base::TimeTicks & time)168 std::string NetLog::TickCountToString(const base::TimeTicks& time) {
169 int64_t delta_time = time.since_origin().InMilliseconds();
170 // TODO(https://crbug.com/915391): Use NetLogNumberValue().
171 return base::NumberToString(delta_time);
172 }
173
174 // static
TimeToString(const base::Time & time)175 std::string NetLog::TimeToString(const base::Time& time) {
176 // Convert the base::Time to its (approximate) equivalent in base::TimeTicks.
177 base::TimeTicks time_ticks =
178 base::TimeTicks::UnixEpoch() + (time - base::Time::UnixEpoch());
179 return TickCountToString(time_ticks);
180 }
181
182 // static
GetEventTypesAsValue()183 base::Value NetLog::GetEventTypesAsValue() {
184 base::Value::Dict dict;
185 for (int i = 0; i < static_cast<int>(NetLogEventType::COUNT); ++i) {
186 dict.Set(NetLogEventTypeToString(static_cast<NetLogEventType>(i)), i);
187 }
188 return base::Value(std::move(dict));
189 }
190
191 // static
SourceTypeToString(NetLogSourceType source)192 const char* NetLog::SourceTypeToString(NetLogSourceType source) {
193 switch (source) {
194 #define SOURCE_TYPE(label) \
195 case NetLogSourceType::label: \
196 return #label;
197 #include "net/log/net_log_source_type_list.h"
198 #undef SOURCE_TYPE
199 default:
200 NOTREACHED();
201 return nullptr;
202 }
203 }
204
205 // static
GetSourceTypesAsValue()206 base::Value NetLog::GetSourceTypesAsValue() {
207 base::Value::Dict dict;
208 for (int i = 0; i < static_cast<int>(NetLogSourceType::COUNT); ++i) {
209 dict.Set(SourceTypeToString(static_cast<NetLogSourceType>(i)), i);
210 }
211 return base::Value(std::move(dict));
212 }
213
214 // static
EventPhaseToString(NetLogEventPhase phase)215 const char* NetLog::EventPhaseToString(NetLogEventPhase phase) {
216 switch (phase) {
217 case NetLogEventPhase::BEGIN:
218 return "PHASE_BEGIN";
219 case NetLogEventPhase::END:
220 return "PHASE_END";
221 case NetLogEventPhase::NONE:
222 return "PHASE_NONE";
223 }
224 NOTREACHED();
225 return nullptr;
226 }
227
InitializeSourceIdPartition()228 void NetLog::InitializeSourceIdPartition() {
229 int32_t old_value = base::subtle::NoBarrier_AtomicExchange(
230 &last_id_, std::numeric_limits<base::subtle::Atomic32>::min());
231 DCHECK_EQ(old_value, 0) << " NetLog::InitializeSourceIdPartition() called "
232 "after NextID() or called multiple times";
233 }
234
AddEntryInternal(NetLogEventType type,const NetLogSource & source,NetLogEventPhase phase,const GetParamsInterface * get_params)235 void NetLog::AddEntryInternal(NetLogEventType type,
236 const NetLogSource& source,
237 NetLogEventPhase phase,
238 const GetParamsInterface* get_params) {
239 NetLogCaptureModeSet observer_capture_modes = GetObserverCaptureModes();
240
241 for (int i = 0; i <= static_cast<int>(NetLogCaptureMode::kLast); ++i) {
242 NetLogCaptureMode capture_mode = static_cast<NetLogCaptureMode>(i);
243 if (!NetLogCaptureModeSetContains(capture_mode, observer_capture_modes))
244 continue;
245
246 NetLogEntry entry(type, source, phase, base::TimeTicks::Now(),
247 get_params->GetParams(capture_mode));
248
249 // Notify all of the log observers with |capture_mode|.
250 base::AutoLock lock(lock_);
251 for (auto* observer : observers_) {
252 if (observer->capture_mode() == capture_mode)
253 observer->OnAddEntry(entry);
254 }
255 }
256 }
257
AddEntryWithMaterializedParams(NetLogEventType type,const NetLogSource & source,NetLogEventPhase phase,base::Value::Dict params)258 void NetLog::AddEntryWithMaterializedParams(NetLogEventType type,
259 const NetLogSource& source,
260 NetLogEventPhase phase,
261 base::Value::Dict params) {
262 AddEntryAtTimeWithMaterializedParams(
263 type, source, phase, base::TimeTicks::Now(), std::move(params));
264 }
265
AddEntryAtTimeWithMaterializedParams(NetLogEventType type,const NetLogSource & source,NetLogEventPhase phase,base::TimeTicks time,base::Value::Dict params)266 void NetLog::AddEntryAtTimeWithMaterializedParams(NetLogEventType type,
267 const NetLogSource& source,
268 NetLogEventPhase phase,
269 base::TimeTicks time,
270 base::Value::Dict params) {
271 NetLogEntry entry(type, source, phase, time, std::move(params));
272
273 // Notify all of the log observers, regardless of capture mode.
274 base::AutoLock lock(lock_);
275 for (auto* observer : observers_) {
276 observer->OnAddEntry(entry);
277 }
278 }
279
280 } // namespace net
281