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 #ifndef NET_LOG_NET_LOG_H_ 6 #define NET_LOG_NET_LOG_H_ 7 8 #include <stdint.h> 9 10 #include <string> 11 #include <vector> 12 13 #include "base/atomicops.h" 14 #include "base/compiler_specific.h" 15 #include "base/memory/raw_ptr.h" 16 #include "base/memory/raw_ref.h" 17 #include "base/synchronization/lock.h" 18 #include "base/time/time.h" 19 #include "base/types/pass_key.h" 20 #include "base/values.h" 21 #include "build/build_config.h" 22 #include "net/base/net_export.h" 23 #include "net/log/net_log_capture_mode.h" 24 #include "net/log/net_log_entry.h" 25 #include "net/log/net_log_event_type.h" 26 #include "net/log/net_log_source.h" 27 #include "net/log/net_log_source_type.h" 28 29 namespace net { 30 31 class NetLogWithSource; 32 33 // NetLog is the destination for log messages generated by the network stack. 34 // Each log message has a "source" field which identifies the specific entity 35 // that generated the message (for example, which URLRequest or which 36 // SpdySession). 37 // 38 // To avoid needing to pass in the "source ID" to the logging functions, NetLog 39 // is usually accessed through a NetLogWithSource, which will always pass in a 40 // specific source ID. 41 // 42 // All methods on NetLog are thread safe, with the exception that no NetLog or 43 // NetLog::ThreadSafeObserver functions may be called by an observer's 44 // OnAddEntry() method, as doing so will result in a deadlock. 45 // 46 // For a broader introduction see the design document: 47 // https://sites.google.com/a/chromium.org/dev/developers/design-documents/network-stack/netlog 48 // 49 // ================================== 50 // Materializing parameters 51 // ================================== 52 // 53 // Events can contain a JSON serializable base::Value [1] referred to as its 54 // "parameters". 55 // 56 // Functions for emitting events have overloads that take a |get_params| 57 // argument for this purpose. 58 // 59 // |get_params| is essentially a block of code to conditionally execute when 60 // the parameters need to be materialized. It is most easily specified as a C++ 61 // lambda. 62 // 63 // This idiom for specifying parameters avoids spending time building the 64 // base::Value when capturing is off. For instance when specified as a lambda 65 // that takes 0 arguments, the inlined code from template expansion roughly 66 // does: 67 // 68 // if (net_log->IsCapturing()) { 69 // base::Value params = get_params(); 70 // net_log->EmitEventToAllObsevers(type, source, phase, std::move(params)); 71 // } 72 // 73 // Alternately, the |get_params| argument could be an invocable that takes a 74 // NetLogCaptureMode parameter: 75 // 76 // base::Value params = get_params(capture_mode); 77 // 78 // In this case, |get_params| depends on the logging granularity and would be 79 // called once per observed NetLogCaptureMode. 80 // 81 // [1] Being "JSON serializable" means you cannot use 82 // base::Value::Type::BINARY. Instead use NetLogBinaryValue() to repackage 83 // it as a base::Value::Type::STRING. 84 class NET_EXPORT NetLog { 85 public: 86 87 // An observer that is notified of entries added to the NetLog. The 88 // "ThreadSafe" prefix of the name emphasizes that this observer may be 89 // called from different threads then the one which added it as an observer. 90 class NET_EXPORT ThreadSafeObserver { 91 public: 92 // Constructs an observer that wants to see network events, with 93 // the specified minimum event granularity. A ThreadSafeObserver can only 94 // observe a single NetLog at a time. 95 // 96 // Observers will be called on the same thread an entry is added on, 97 // and are responsible for ensuring their own thread safety. 98 // 99 // Observers must stop watching a NetLog before either the observer or the 100 // NetLog is destroyed. 101 ThreadSafeObserver(); 102 103 ThreadSafeObserver(const ThreadSafeObserver&) = delete; 104 ThreadSafeObserver& operator=(const ThreadSafeObserver&) = delete; 105 106 // Returns the capture mode for events this observer wants to 107 // receive. It is only valid to call this while observing a NetLog. 108 NetLogCaptureMode capture_mode() const; 109 110 // Returns the NetLog being watched, or nullptr if there is none. 111 NetLog* net_log() const; 112 113 // This method is called whenever an entry (event) was added to the NetLog 114 // being watched. 115 // 116 // OnAddEntry() is invoked on the thread which generated the NetLog entry, 117 // which may be different from the thread that added this observer. 118 // 119 // Whenever OnAddEntry() is invoked, the NetLog's mutex is held. The 120 // consequences of this are: 121 // 122 // * OnAddEntry() will never be called concurrently -- implementations 123 // can rely on this to avoid needing their own synchronization. 124 // 125 // * It is illegal for an observer to call back into the NetLog, or the 126 // observer itself, as this can result in deadlock or violating 127 // expectations of non re-entrancy into ThreadSafeObserver. 128 virtual void OnAddEntry(const NetLogEntry& entry) = 0; 129 130 protected: 131 virtual ~ThreadSafeObserver(); 132 133 private: 134 friend class NetLog; 135 136 // Both of these values are only modified by the NetLog. 137 NetLogCaptureMode capture_mode_ = NetLogCaptureMode::kDefault; 138 raw_ptr<NetLog> net_log_ = nullptr; 139 }; 140 141 // An observer that is notified of changes in the capture mode set, and has 142 // the ability to add NetLog entries with materialized params. 143 class NET_EXPORT ThreadSafeCaptureModeObserver { 144 public: 145 ThreadSafeCaptureModeObserver(); 146 147 ThreadSafeCaptureModeObserver(const ThreadSafeCaptureModeObserver&) = 148 delete; 149 ThreadSafeCaptureModeObserver& operator=( 150 const ThreadSafeCaptureModeObserver&) = delete; 151 152 virtual void OnCaptureModeUpdated(NetLogCaptureModeSet modes) = 0; 153 154 protected: 155 virtual ~ThreadSafeCaptureModeObserver(); 156 157 NetLogCaptureModeSet GetObserverCaptureModes() const; 158 159 // Add event to the observed NetLog. Must only be called while observing is 160 // active, and the caller is responsible for ensuring the materialized 161 // params are suitable for the current capture mode. 162 void AddEntryAtTimeWithMaterializedParams(NetLogEventType type, 163 const NetLogSource& source, 164 NetLogEventPhase phase, 165 base::TimeTicks time, 166 base::Value::Dict params); 167 168 private: 169 // Friend NetLog so that AddCaptureModeObserver/RemoveCaptureModeObserver 170 // can update the |net_log_| member. 171 friend class NetLog; 172 173 // This value is only modified by the NetLog. 174 raw_ptr<NetLog> net_log_ = nullptr; 175 }; 176 177 // Returns the singleton NetLog object, which is never destructed and which 178 // may be used on any thread. 179 static NetLog* Get(); 180 181 // NetLog should only be used through the singleton returned by Get(), the 182 // constructor takes a PassKey to ensure that additional NetLog objects 183 // cannot be created. 184 explicit NetLog(base::PassKey<NetLog>); 185 186 // NetLogWithSource creates a dummy NetLog as an internal optimization. 187 explicit NetLog(base::PassKey<NetLogWithSource>); 188 189 NetLog(const NetLog&) = delete; 190 NetLog& operator=(const NetLog&) = delete; 191 192 ~NetLog() = delete; 193 194 // Configure the source IDs returned by NextID() to use a different starting 195 // position, so that NetLog events generated by this process will not conflict 196 // with those generated by another NetLog in a different process. This 197 // should only be called once, before any NetLogSource could be created in 198 // the current process. 199 // 200 // Currently only a single additional source id partition is supported. 201 void InitializeSourceIdPartition(); 202 203 void AddEntry(NetLogEventType type, 204 const NetLogSource& source, 205 NetLogEventPhase phase); 206 207 // NetLog parameter generators (lambdas) come in two flavors -- those that 208 // take no arguments, and those that take a single NetLogCaptureMode. This 209 // code allows differentiating between the two. 210 template <typename T, typename = void> 211 struct ExpectsCaptureMode : std::false_type {}; 212 template <typename T> 213 struct ExpectsCaptureMode<T, 214 decltype(void(std::declval<T>()( 215 NetLogCaptureMode::kDefault)))> 216 : std::true_type {}; 217 218 // Adds an entry for the given source, phase, and type, whose parameters are 219 // obtained by invoking |get_params()| with no arguments. 220 // 221 // See "Materializing parameters" for details. 222 template <typename ParametersCallback> 223 inline typename std::enable_if<!ExpectsCaptureMode<ParametersCallback>::value, 224 void>::type 225 AddEntry(NetLogEventType type, 226 const NetLogSource& source, 227 NetLogEventPhase phase, 228 const ParametersCallback& get_params) { 229 if (LIKELY(!IsCapturing())) 230 return; 231 232 AddEntryWithMaterializedParams(type, source, phase, get_params()); 233 } 234 235 // Adds an entry for the given source, phase, and type, whose parameters are 236 // obtained by invoking |get_params(capture_mode)| with a NetLogCaptureMode. 237 // 238 // See "Materializing parameters" for details. 239 template <typename ParametersCallback> 240 inline typename std::enable_if<ExpectsCaptureMode<ParametersCallback>::value, 241 void>::type 242 AddEntry(NetLogEventType type, 243 const NetLogSource& source, 244 NetLogEventPhase phase, 245 const ParametersCallback& get_params) { 246 if (LIKELY(!IsCapturing())) 247 return; 248 249 // Indirect through virtual dispatch to reduce code bloat, as this is 250 // inlined in a number of places. 251 class GetParamsImpl : public GetParamsInterface { 252 public: 253 explicit GetParamsImpl(const ParametersCallback& get_params) 254 : get_params_(get_params) {} 255 base::Value::Dict GetParams(NetLogCaptureMode mode) const override { 256 return (*get_params_)(mode); 257 } 258 259 private: 260 const raw_ref<const ParametersCallback> get_params_; 261 }; 262 263 GetParamsImpl wrapper(get_params); 264 AddEntryInternal(type, source, phase, &wrapper); 265 } 266 267 // Emits a global event to the log stream, with its own unique source ID. 268 void AddGlobalEntry(NetLogEventType type); 269 270 // Overload of AddGlobalEntry() that includes parameters. 271 // 272 // See "Materializing parameters" for details on |get_params|. 273 template <typename ParametersCallback> 274 void AddGlobalEntry(NetLogEventType type, 275 const ParametersCallback& get_params) { 276 AddEntry(type, NetLogSource(NetLogSourceType::NONE, NextID()), 277 NetLogEventPhase::NONE, get_params); 278 } 279 280 void AddGlobalEntryWithStringParams(NetLogEventType type, 281 std::string_view name, 282 std::string_view value); 283 284 // Returns a unique ID which can be used as a source ID. All returned IDs 285 // will be unique and not equal to 0. 286 uint32_t NextID(); 287 288 // Returns true if there are any observers attached to the NetLog. 289 // 290 // TODO(eroman): Survey current callsites; most are probably not necessary, 291 // and may even be harmful. 292 bool IsCapturing() const { 293 return GetObserverCaptureModes() != 0; 294 } 295 296 // Adds an observer and sets its log capture mode. The observer must not be 297 // watching any NetLog, including this one, when this is called. 298 // 299 // CAUTION: Think carefully before introducing a dependency on the 300 // NetLog. The order, format, and parameters in NetLog events are NOT 301 // guaranteed to be stable. As such, building a production feature that works 302 // by observing the NetLog is likely inappropriate. Just as you wouldn't build 303 // a feature by scraping the text output from LOG(INFO), you shouldn't do 304 // the same by scraping the logging data emitted to NetLog. Support for 305 // observers is an internal detail mainly used for testing and to write events 306 // to a file. Please consult a //net OWNER before using this outside of 307 // testing or serialization. 308 void AddObserver(ThreadSafeObserver* observer, 309 NetLogCaptureMode capture_mode); 310 311 // Removes an observer. 312 // 313 // For thread safety reasons, it is recommended that this not be called in 314 // an object's destructor. 315 void RemoveObserver(ThreadSafeObserver* observer); 316 317 // Adds an observer that is notified of changes in the capture mode set. 318 void AddCaptureModeObserver(ThreadSafeCaptureModeObserver* observer); 319 320 // Removes a capture mode observer. 321 void RemoveCaptureModeObserver(ThreadSafeCaptureModeObserver* observer); 322 323 // Converts a time to the string format that the NetLog uses to represent 324 // times. Strings are used since integers may overflow. 325 // The resulting string contains the number of milliseconds since the origin 326 // or "zero" point of the TimeTicks class, which can vary each time the 327 // application is restarted. This number is related to an actual time via the 328 // timeTickOffset recorded in GetNetConstants(). 329 static std::string TickCountToString(const base::TimeTicks& time); 330 331 // Same as above but takes a base::Time. Should not be used if precise 332 // timestamps are desired, but is suitable for e.g. expiration times. 333 static std::string TimeToString(const base::Time& time); 334 335 // Returns a dictionary that maps event type symbolic names to their enum 336 // values. 337 static base::Value GetEventTypesAsValue(); 338 339 // Returns a C-String symbolic name for |source_type|. 340 static const char* SourceTypeToString(NetLogSourceType source_type); 341 342 // Returns a dictionary that maps source type symbolic names to their enum 343 // values. 344 static base::Value GetSourceTypesAsValue(); 345 346 // Returns a C-String symbolic name for |event_phase|. 347 static const char* EventPhaseToString(NetLogEventPhase event_phase); 348 349 private: 350 class GetParamsInterface { 351 public: 352 virtual base::Value::Dict GetParams(NetLogCaptureMode mode) const = 0; 353 virtual ~GetParamsInterface() = default; 354 }; 355 356 // Helper for implementing AddEntry() that indirects parameter getting through 357 // virtual dispatch. 358 void AddEntryInternal(NetLogEventType type, 359 const NetLogSource& source, 360 NetLogEventPhase phase, 361 const GetParamsInterface* get_params); 362 363 // Returns the set of all capture modes being observed. 364 NetLogCaptureModeSet GetObserverCaptureModes() const { 365 return base::subtle::NoBarrier_Load(&observer_capture_modes_); 366 } 367 368 // Adds an entry using already materialized parameters, when it is already 369 // known that the log is capturing (goes straight to acquiring observer lock). 370 // 371 // TODO(eroman): Drop the rvalue-ref on |params| unless can show it improves 372 // the generated code (initial testing suggests it makes no difference in 373 // clang). 374 void AddEntryWithMaterializedParams(NetLogEventType type, 375 const NetLogSource& source, 376 NetLogEventPhase phase, 377 base::Value::Dict params); 378 379 // Adds an entry at a certain time, using already materialized parameters, 380 // when it is already known that the log is capturing (goes straight to 381 // acquiring observer lock). 382 void AddEntryAtTimeWithMaterializedParams(NetLogEventType type, 383 const NetLogSource& source, 384 NetLogEventPhase phase, 385 base::TimeTicks time, 386 base::Value::Dict params); 387 388 // Called whenever an observer is added or removed, to update 389 // |observer_capture_modes_|. Must have acquired |lock_| prior to calling. 390 void UpdateObserverCaptureModes(); 391 392 // Returns true if |observer| is watching this NetLog. Must 393 // be called while |lock_| is already held. 394 bool HasObserver(ThreadSafeObserver* observer); 395 bool HasCaptureModeObserver(ThreadSafeCaptureModeObserver* observer); 396 397 // |lock_| protects access to |observers_|. 398 base::Lock lock_; 399 400 // Last assigned source ID. Incremented to get the next one. 401 base::subtle::Atomic32 last_id_ = 0; 402 403 // Holds the set of all capture modes that observers are watching the log at. 404 // 405 // Is 0 when there are no observers. Stored as an Atomic32 so it can be 406 // accessed and updated more efficiently. 407 base::subtle::Atomic32 observer_capture_modes_ = 0; 408 409 // |observers_| is a list of observers, ordered by when they were added. 410 // Pointers contained in |observers_| are non-owned, and must 411 // remain valid. 412 // 413 // |lock_| must be acquired whenever reading or writing to this. 414 // 415 // In practice |observers_| will be very small (<5) so O(n) 416 // operations on it are fine. 417 std::vector<raw_ptr<ThreadSafeObserver, VectorExperimental>> observers_; 418 419 std::vector<raw_ptr<ThreadSafeCaptureModeObserver, VectorExperimental>> 420 capture_mode_observers_; 421 }; 422 423 } // namespace net 424 425 #endif // NET_LOG_NET_LOG_H_ 426