1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 // This file defines a set of user experience metrics data recorded by 6 // the MetricsService. This is the unit of data that is sent to the server. 7 8 #ifndef CHROME_COMMON_METRICS_HELPERS_H_ 9 #define CHROME_COMMON_METRICS_HELPERS_H_ 10 #pragma once 11 12 #include <map> 13 #include <string> 14 15 #include "base/basictypes.h" 16 #include "base/memory/scoped_ptr.h" 17 #include "base/metrics/histogram.h" 18 #include "base/time.h" 19 #include "content/common/page_transition_types.h" 20 21 class GURL; 22 class MetricsLog; 23 24 // This class provides base functionality for logging metrics data. 25 class MetricsLogBase { 26 public: 27 // Creates a new metrics log 28 // client_id is the identifier for this profile on this installation 29 // session_id is an integer that's incremented on each application launch 30 MetricsLogBase(const std::string& client_id, int session_id, 31 const std::string& version_string); 32 virtual ~MetricsLogBase(); 33 34 // Records a user-initiated action. 35 void RecordUserAction(const char* key); 36 37 enum WindowEventType { 38 WINDOW_CREATE = 0, 39 WINDOW_OPEN, 40 WINDOW_CLOSE, 41 WINDOW_DESTROY 42 }; 43 44 void RecordWindowEvent(WindowEventType type, int window_id, int parent_id); 45 46 // Records a page load. 47 // window_id - the index of the tab in which the load took place 48 // url - which URL was loaded 49 // origin - what kind of action initiated the load 50 // load_time - how long it took to load the page 51 void RecordLoadEvent(int window_id, 52 const GURL& url, 53 PageTransition::Type origin, 54 int session_index, 55 base::TimeDelta load_time); 56 57 // Record any changes in a given histogram for transmission. 58 void RecordHistogramDelta(const base::Histogram& histogram, 59 const base::Histogram::SampleSet& snapshot); 60 61 // Stop writing to this record and generate the encoded representation. 62 // None of the Record* methods can be called after this is called. 63 void CloseLog(); 64 65 // These methods allow retrieval of the encoded representation of the 66 // record. They can only be called after CloseLog() has been called. 67 // GetEncodedLog returns false if buffer_size is less than 68 // GetEncodedLogSize(); 69 int GetEncodedLogSize(); 70 bool GetEncodedLog(char* buffer, int buffer_size); 71 // Returns an empty string on failure. 72 std::string GetEncodedLogString(); 73 74 // Returns the amount of time in seconds that this log has been in use. 75 int GetElapsedSeconds(); 76 77 int num_events() { return num_events_; } 78 79 void set_hardware_class(const std::string& hardware_class) { 80 hardware_class_ = hardware_class; 81 } 82 83 // Creates an MD5 hash of the given value, and returns hash as a byte 84 // buffer encoded as a std::string. 85 static std::string CreateHash(const std::string& value); 86 87 // Return a base64-encoded MD5 hash of the given string. 88 static std::string CreateBase64Hash(const std::string& string); 89 90 // Get the GMT buildtime for the current binary, expressed in seconds since 91 // Januray 1, 1970 GMT. 92 // The value is used to identify when a new build is run, so that previous 93 // reliability stats, from other builds, can be abandoned. 94 static int64 GetBuildTime(); 95 96 // Use |extension| in all uploaded appversions in addition to the standard 97 // version string. 98 static void set_version_extension(const std::string& extension) { 99 version_extension_ = extension; 100 } 101 102 virtual MetricsLog* AsMetricsLog(); 103 104 protected: 105 class XmlWrapper; 106 107 // Returns a string containing the current time. 108 // Virtual so that it can be overridden for testing. 109 virtual std::string GetCurrentTimeString(); 110 // Helper class that invokes StartElement from constructor, and EndElement 111 // from destructor. 112 // 113 // Use the macro OPEN_ELEMENT_FOR_SCOPE to help avoid usage problems. 114 class ScopedElement { 115 public: 116 ScopedElement(MetricsLogBase* log, const std::string& name) : log_(log) { 117 DCHECK(log); 118 log->StartElement(name.c_str()); 119 } 120 121 ScopedElement(MetricsLogBase* log, const char* name) : log_(log) { 122 DCHECK(log); 123 log->StartElement(name); 124 } 125 126 ~ScopedElement() { 127 log_->EndElement(); 128 } 129 130 private: 131 MetricsLogBase* log_; 132 }; 133 friend class ScopedElement; 134 135 static const char* WindowEventTypeToString(WindowEventType type); 136 137 // Frees the resources allocated by the XML document writer: the 138 // main writer object as well as the XML tree structure, if 139 // applicable. 140 void FreeDocWriter(); 141 142 // Convenience versions of xmlWriter functions 143 void StartElement(const char* name); 144 void EndElement(); 145 void WriteAttribute(const std::string& name, const std::string& value); 146 void WriteIntAttribute(const std::string& name, int value); 147 void WriteInt64Attribute(const std::string& name, int64 value); 148 149 // Write the attributes that are common to every metrics event type. 150 void WriteCommonEventAttributes(); 151 152 // An extension that is appended to the appversion in each log. 153 static std::string version_extension_; 154 155 base::Time start_time_; 156 base::Time end_time_; 157 158 std::string client_id_; 159 std::string session_id_; 160 std::string hardware_class_; 161 162 // locked_ is true when record has been packed up for sending, and should 163 // no longer be written to. It is only used for sanity checking and is 164 // not a real lock. 165 bool locked_; 166 167 // Isolated to limit the dependency on the XML library for our consumers. 168 XmlWrapper* xml_wrapper_; 169 170 int num_events_; // the number of events recorded in this log 171 172 DISALLOW_COPY_AND_ASSIGN(MetricsLogBase); 173 }; 174 175 // HistogramSender handles the logistics of gathering up available histograms 176 // for transmission (such as from renderer to browser, or from browser to UMA 177 // upload). It has several pure virtual functions that are replaced in 178 // derived classes to allow the exact lower level transmission mechanism, 179 // or error report mechanism, to be replaced. Since histograms can sit in 180 // memory for an extended period of time, and are vulnerable to memory 181 // corruption, this class also validates as much rendundancy as it can before 182 // calling for the marginal change (a.k.a., delta) in a histogram to be sent 183 // onward. 184 class HistogramSender { 185 protected: 186 HistogramSender(); 187 virtual ~HistogramSender(); 188 189 // Snapshot all histograms, and transmit the delta. 190 // The arguments allow a derived class to select only a subset for 191 // transmission, or to set a flag in each transmitted histogram. 192 void TransmitAllHistograms(base::Histogram::Flags flags_to_set, 193 bool send_only_uma); 194 195 // Send the histograms onward, as defined in a derived class. 196 // This is only called with a delta, listing samples that have not previously 197 // been transmitted. 198 virtual void TransmitHistogramDelta( 199 const base::Histogram& histogram, 200 const base::Histogram::SampleSet& snapshot) = 0; 201 202 // Record various errors found during attempts to send histograms. 203 virtual void InconsistencyDetected(int problem) = 0; 204 virtual void UniqueInconsistencyDetected(int problem) = 0; 205 virtual void SnapshotProblemResolved(int amount) = 0; 206 207 private: 208 // Maintain a map of histogram names to the sample stats we've sent. 209 typedef std::map<std::string, base::Histogram::SampleSet> LoggedSampleMap; 210 // List of histograms names, and their encontered corruptions. 211 typedef std::map<std::string, int> ProblemMap; 212 213 // Snapshot this histogram, and transmit the delta. 214 void TransmitHistogram(const base::Histogram& histogram); 215 216 // For histograms, record what we've already transmitted (as a sample for each 217 // histogram) so that we can send only the delta with the next log. 218 LoggedSampleMap logged_samples_; 219 220 // List of histograms found corrupt to be corrupt, and their problems. 221 scoped_ptr<ProblemMap> inconsistencies_; 222 223 DISALLOW_COPY_AND_ASSIGN(HistogramSender); 224 }; 225 226 // This class provides base functionality for logging metrics data. 227 // TODO(ananta) 228 // Factor out more common code from chrome and chrome frame metrics service 229 // into this class. 230 class MetricsServiceBase : public HistogramSender { 231 protected: 232 MetricsServiceBase(); 233 virtual ~MetricsServiceBase(); 234 235 // Check to see if there is a log that needs to be, or is being, transmitted. 236 bool pending_log() const { 237 return pending_log_ || !compressed_log_.empty(); 238 } 239 240 // Compress the report log in |input| using bzip2, store the result in 241 // |output|. 242 bool Bzip2Compress(const std::string& input, std::string* output); 243 244 // Discard |pending_log_|, and clear |compressed_log_|. Called after 245 // processing of this log is complete. 246 void DiscardPendingLog(); 247 248 // Record complete list of histograms into the current log. 249 // Called when we close a log. 250 void RecordCurrentHistograms(); 251 252 // A log that we are currently transmiting, or about to try to transmit. 253 MetricsLogBase* pending_log_; 254 255 // An alternate form of |pending_log_|. We persistently save this version 256 // into prefs if we can't transmit it. As a result, sometimes all we have is 257 // the compressed text version. 258 std::string compressed_log_; 259 260 // The log that we are still appending to. 261 MetricsLogBase* current_log_; 262 263 private: 264 // HistogramSender interface (override) methods. 265 virtual void TransmitHistogramDelta( 266 const base::Histogram& histogram, 267 const base::Histogram::SampleSet& snapshot); 268 virtual void InconsistencyDetected(int problem); 269 virtual void UniqueInconsistencyDetected(int problem); 270 virtual void SnapshotProblemResolved(int amount); 271 272 DISALLOW_COPY_AND_ASSIGN(MetricsServiceBase); 273 }; 274 275 #endif // CHROME_COMMON_METRICS_HELPERS_H_ 276