• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2022 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 COMPONENTS_METRICS_METRICS_SERVICE_OBSERVER_H_
6 #define COMPONENTS_METRICS_METRICS_SERVICE_OBSERVER_H_
7 
8 #include <memory>
9 #include <optional>
10 #include <string>
11 #include <string_view>
12 #include <vector>
13 
14 #include "base/callback_list.h"
15 #include "base/containers/flat_map.h"
16 #include "base/files/file_path.h"
17 #include "base/memory/raw_ptr.h"
18 #include "components/metrics/metrics_logs_event_manager.h"
19 
20 namespace metrics {
21 
22 // Observes logs generated by a metrics collection system (UMA and UKM) and
23 // stores them in-memory. This class also provides a way to export the logs in a
24 // JSON format, which includes metadata, proto data, as well as the events
25 // describing the lifecycle of the logs.
26 class MetricsServiceObserver : public MetricsLogsEventManager::Observer {
27  public:
28   // Possible metrics service types.
29   enum class MetricsServiceType {
30     UMA,
31     UKM,
32   };
33 
34   // Represents a log and its data. Exposed for testing.
35   struct Log {
36     // Represents an event that occurred on the log. An optional message may
37     // be associated with the event. For example, the event may be
38     // |kLogTrimmed|, with |message| being "Log size too large".
39     struct Event {
40       Event();
41 
42       Event(const Event&);
43       Event& operator=(const Event&);
44 
45       ~Event();
46 
47       // The type of event.
48       MetricsLogsEventManager::LogEvent event;
49 
50       // The timestamp at which the event occurred. This is the number of
51       // milliseconds since Epoch.
52       double timestampMs;
53 
54       // An optional message associated with the event.
55       std::optional<std::string> message;
56     };
57 
58     Log();
59 
60     Log(const Log&);
61     Log& operator=(const Log&);
62 
63     ~Log();
64 
65     // The SHA1 hash of the log's data, used to uniquely identify it.
66     std::string hash;
67 
68     // The time at which the log was closed. This is the number of seconds since
69     // Epoch.
70     std::string timestamp;
71 
72     // The log's compressed (gzipped) serialized protobuf.
73     std::string data;
74 
75     // A list of the events that occurred throughout the log's lifetime.
76     std::vector<Event> events;
77 
78     // The type of log (stability, ongoing, independent). This is only set if
79     // this log is a UMA log.
80     std::optional<MetricsLog::LogType> type;
81   };
82 
83   // |service_type| is the type of service this observer will be observing from.
84   explicit MetricsServiceObserver(MetricsServiceType service_type);
85 
86   MetricsServiceObserver(const MetricsServiceObserver&) = delete;
87   MetricsServiceObserver& operator=(const MetricsServiceObserver&) = delete;
88 
89   ~MetricsServiceObserver() override;
90 
91   // MetricsLogsEventManager::Observer:
92   void OnLogCreated(
93       std::string_view log_hash,
94       std::string_view log_data,
95       std::string_view log_timestamp,
96       metrics::MetricsLogsEventManager::CreateReason reason) override;
97   void OnLogEvent(MetricsLogsEventManager::LogEvent event,
98                   std::string_view log_hash,
99                   std::string_view message) override;
100   void OnLogType(std::optional<MetricsLog::LogType> log_type) override;
101 
102   // Exports |logs_| to a JSON string and writes it to |json_output|. If
103   // |include_log_proto_data| is true, the protos of the logs will be included.
104   // The format of the JSON object is as follows:
105   //
106   // {
107   //   logType: string, // e.g. "UMA" or "UKM"
108   //   logs: [
109   //     {
110   //       type?: string, // e.g. "Ongoing" (set only for UMA logs)
111   //       hash: string,
112   //       timestamp: string,
113   //       data: string, // set if |include_log_proto_data| is true
114   //       size: number,
115   //       events: [
116   //         {
117   //           event: string, // e.g. "Trimmed"
118   //           timestamp: number,
119   //           message?: string
120   //         },
121   //         ...
122   //       ]
123   //     },
124   //     ...
125   //   ]
126   // }
127   //
128   // The "hash" field is the hex representation of the log's hash. The
129   // "data" field is a base64 encoding of the log's compressed (gzipped)
130   // serialized protobuf. The "size" field is the size (in bytes) of the log.
131   bool ExportLogsAsJson(bool include_log_proto_data, std::string* json_output);
132 
133   // Exports logs data (see ExportLogsAsJson() above) to the passed |path|. If
134   // the file pointed by |path| does not exist, it will be created. If it
135   // already exists, its contents will be overwritten.
136   void ExportLogsToFile(const base::FilePath& path);
137 
138   // Registers a callback. This callback will be run every time this observer is
139   // notified through OnLogCreated() or OnLogEvent(). When the returned
140   // CallbackListSubscription is destroyed, the callback is automatically
141   // de-registered.
142   [[nodiscard]] base::CallbackListSubscription AddNotifiedCallback(
143       base::RepeatingClosure callback);
144 
145   // Returns |logs_|.
logs_for_testing()146   std::vector<std::unique_ptr<Log>>* logs_for_testing() { return &logs_; }
147 
148  private:
149   // Returns the Log object from |logs_| with the given |log_hash| if one
150   // exists. Returns nullptr otherwise.
151   Log* GetLogFromHash(std::string_view log_hash);
152 
153   // The type of service this observer is observing. This has no impact on how
154   // the logs are stored. This is only used when exporting the logs (see
155   // ExportLogsAsJson() above) so that the type of logs is easily identifiable.
156   const MetricsServiceType service_type_;
157 
158   // The list of logs that are being kept track of. It is a vector so that we
159   // can keep the ordering of the logs as they are inserted.
160   std::vector<std::unique_ptr<Log>> logs_;
161 
162   // An overlay on |logs_| that allows for a log to be located based on its
163   // hash.
164   base::flat_map<std::string_view, raw_ptr<Log, CtnExperimental>> indexed_logs_;
165 
166   // Keeps track of the type of UMA logs (ongoing, stability, independent) that
167   // are being created. This should only be set for UMA logs, since the concept
168   // of log type only exists in UMA.
169   std::optional<MetricsLog::LogType> uma_log_type_;
170 
171   // List of callbacks to run whenever this observer is notified. Note that
172   // OnLogType() will not trigger the callbacks.
173   base::RepeatingClosureList notified_callbacks_;
174 };
175 
176 }  // namespace metrics
177 
178 #endif  // COMPONENTS_METRICS_METRICS_SERVICE_OBSERVER_H_
179