xref: /aosp_15_r20/external/cronet/net/log/net_log.h (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
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