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