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 (!IsCapturing()) [[likely]] { 230 return; 231 } 232 233 AddEntryWithMaterializedParams(type, source, phase, get_params()); 234 } 235 236 // Adds an entry for the given source, phase, and type, whose parameters are 237 // obtained by invoking |get_params(capture_mode)| with a NetLogCaptureMode. 238 // 239 // See "Materializing parameters" for details. 240 template <typename ParametersCallback> 241 inline typename std::enable_if<ExpectsCaptureMode<ParametersCallback>::value, 242 void>::type 243 AddEntry(NetLogEventType type, 244 const NetLogSource& source, 245 NetLogEventPhase phase, 246 const ParametersCallback& get_params) { 247 if (!IsCapturing()) [[likely]] { 248 return; 249 } 250 251 // Indirect through virtual dispatch to reduce code bloat, as this is 252 // inlined in a number of places. 253 class GetParamsImpl : public GetParamsInterface { 254 public: 255 explicit GetParamsImpl(const ParametersCallback& get_params) 256 : get_params_(get_params) {} 257 base::Value::Dict GetParams(NetLogCaptureMode mode) const override { 258 return (*get_params_)(mode); 259 } 260 261 private: 262 const raw_ref<const ParametersCallback> get_params_; 263 }; 264 265 GetParamsImpl wrapper(get_params); 266 AddEntryInternal(type, source, phase, &wrapper); 267 } 268 269 // Emits a global event to the log stream, with its own unique source ID. 270 void AddGlobalEntry(NetLogEventType type); 271 272 // Overload of AddGlobalEntry() that includes parameters. 273 // 274 // See "Materializing parameters" for details on |get_params|. 275 template <typename ParametersCallback> 276 void AddGlobalEntry(NetLogEventType type, 277 const ParametersCallback& get_params) { 278 AddEntry(type, NetLogSource(NetLogSourceType::NONE, NextID()), 279 NetLogEventPhase::NONE, get_params); 280 } 281 282 void AddGlobalEntryWithStringParams(NetLogEventType type, 283 std::string_view name, 284 std::string_view value); 285 286 // Returns a unique ID which can be used as a source ID. All returned IDs 287 // will be unique and not equal to 0. 288 uint32_t NextID(); 289 290 // Returns true if there are any observers attached to the NetLog. 291 // 292 // TODO(eroman): Survey current callsites; most are probably not necessary, 293 // and may even be harmful. 294 bool IsCapturing() const { 295 return GetObserverCaptureModes() != 0; 296 } 297 298 // Adds an observer and sets its log capture mode. The observer must not be 299 // watching any NetLog, including this one, when this is called. 300 // 301 // CAUTION: Think carefully before introducing a dependency on the 302 // NetLog. The order, format, and parameters in NetLog events are NOT 303 // guaranteed to be stable. As such, building a production feature that works 304 // by observing the NetLog is likely inappropriate. Just as you wouldn't build 305 // a feature by scraping the text output from LOG(INFO), you shouldn't do 306 // the same by scraping the logging data emitted to NetLog. Support for 307 // observers is an internal detail mainly used for testing and to write events 308 // to a file. Please consult a //net OWNER before using this outside of 309 // testing or serialization. 310 void AddObserver(ThreadSafeObserver* observer, 311 NetLogCaptureMode capture_mode); 312 313 // Removes an observer. 314 // 315 // For thread safety reasons, it is recommended that this not be called in 316 // an object's destructor. 317 void RemoveObserver(ThreadSafeObserver* observer); 318 319 // Adds an observer that is notified of changes in the capture mode set. 320 void AddCaptureModeObserver(ThreadSafeCaptureModeObserver* observer); 321 322 // Removes a capture mode observer. 323 void RemoveCaptureModeObserver(ThreadSafeCaptureModeObserver* observer); 324 325 // Converts a time to the string format that the NetLog uses to represent 326 // times. Strings are used since integers may overflow. 327 // The resulting string contains the number of milliseconds since the origin 328 // or "zero" point of the TimeTicks class, which can vary each time the 329 // application is restarted. This number is related to an actual time via the 330 // timeTickOffset recorded in GetNetConstants(). 331 static std::string TickCountToString(const base::TimeTicks& time); 332 333 // Same as above but takes a base::Time. Should not be used if precise 334 // timestamps are desired, but is suitable for e.g. expiration times. 335 static std::string TimeToString(const base::Time& time); 336 337 // Returns a dictionary that maps event type symbolic names to their enum 338 // values. 339 static base::Value GetEventTypesAsValue(); 340 341 // Returns a C-String symbolic name for |source_type|. 342 static const char* SourceTypeToString(NetLogSourceType source_type); 343 344 // Returns a dictionary that maps source type symbolic names to their enum 345 // values. 346 static base::Value GetSourceTypesAsValue(); 347 348 // Returns a C-String symbolic name for |event_phase|. 349 static const char* EventPhaseToString(NetLogEventPhase event_phase); 350 351 private: 352 class GetParamsInterface { 353 public: 354 virtual base::Value::Dict GetParams(NetLogCaptureMode mode) const = 0; 355 virtual ~GetParamsInterface() = default; 356 }; 357 358 // Helper for implementing AddEntry() that indirects parameter getting through 359 // virtual dispatch. 360 void AddEntryInternal(NetLogEventType type, 361 const NetLogSource& source, 362 NetLogEventPhase phase, 363 const GetParamsInterface* get_params); 364 365 // Returns the set of all capture modes being observed. 366 NetLogCaptureModeSet GetObserverCaptureModes() const { 367 return base::subtle::NoBarrier_Load(&observer_capture_modes_); 368 } 369 370 // Adds an entry using already materialized parameters, when it is already 371 // known that the log is capturing (goes straight to acquiring observer lock). 372 // 373 // TODO(eroman): Drop the rvalue-ref on |params| unless can show it improves 374 // the generated code (initial testing suggests it makes no difference in 375 // clang). 376 void AddEntryWithMaterializedParams(NetLogEventType type, 377 const NetLogSource& source, 378 NetLogEventPhase phase, 379 base::Value::Dict params); 380 381 // Adds an entry at a certain time, using already materialized parameters, 382 // when it is already known that the log is capturing (goes straight to 383 // acquiring observer lock). 384 void AddEntryAtTimeWithMaterializedParams(NetLogEventType type, 385 const NetLogSource& source, 386 NetLogEventPhase phase, 387 base::TimeTicks time, 388 base::Value::Dict params); 389 390 // Called whenever an observer is added or removed, to update 391 // |observer_capture_modes_|. Must have acquired |lock_| prior to calling. 392 void UpdateObserverCaptureModes(); 393 394 // Returns true if |observer| is watching this NetLog. Must 395 // be called while |lock_| is already held. 396 bool HasObserver(ThreadSafeObserver* observer); 397 bool HasCaptureModeObserver(ThreadSafeCaptureModeObserver* observer); 398 399 // |lock_| protects access to |observers_|. 400 base::Lock lock_; 401 402 // Last assigned source ID. Incremented to get the next one. 403 base::subtle::Atomic32 last_id_ = 0; 404 405 // Holds the set of all capture modes that observers are watching the log at. 406 // 407 // Is 0 when there are no observers. Stored as an Atomic32 so it can be 408 // accessed and updated more efficiently. 409 base::subtle::Atomic32 observer_capture_modes_ = 0; 410 411 // |observers_| is a list of observers, ordered by when they were added. 412 // Pointers contained in |observers_| are non-owned, and must 413 // remain valid. 414 // 415 // |lock_| must be acquired whenever reading or writing to this. 416 // 417 // In practice |observers_| will be very small (<5) so O(n) 418 // operations on it are fine. 419 std::vector<raw_ptr<ThreadSafeObserver, VectorExperimental>> observers_; 420 421 std::vector<raw_ptr<ThreadSafeCaptureModeObserver, VectorExperimental>> 422 capture_mode_observers_; 423 }; 424 425 } // namespace net 426 427 #endif // NET_LOG_NET_LOG_H_ 428