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