Home | History | Annotate | Download | only in common
      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