// Copyright (c) 2011 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// This file defines a set of user experience metrics data recorded by
// the MetricsService. This is the unit of data that is sent to the server.
#ifndef CHROME_COMMON_METRICS_HELPERS_H_
#define CHROME_COMMON_METRICS_HELPERS_H_
#pragma once
#include <map>
#include <string>
#include "base/basictypes.h"
#include "base/memory/scoped_ptr.h"
#include "base/metrics/histogram.h"
#include "base/time.h"
#include "content/common/page_transition_types.h"
class GURL;
class MetricsLog;
// This class provides base functionality for logging metrics data.
class MetricsLogBase {
public:
// Creates a new metrics log
// client_id is the identifier for this profile on this installation
// session_id is an integer that's incremented on each application launch
MetricsLogBase(const std::string& client_id, int session_id,
const std::string& version_string);
virtual ~MetricsLogBase();
// Records a user-initiated action.
void RecordUserAction(const char* key);
enum WindowEventType {
WINDOW_CREATE = 0,
WINDOW_OPEN,
WINDOW_CLOSE,
WINDOW_DESTROY
};
void RecordWindowEvent(WindowEventType type, int window_id, int parent_id);
// Records a page load.
// window_id - the index of the tab in which the load took place
// url - which URL was loaded
// origin - what kind of action initiated the load
// load_time - how long it took to load the page
void RecordLoadEvent(int window_id,
const GURL& url,
PageTransition::Type origin,
int session_index,
base::TimeDelta load_time);
// Record any changes in a given histogram for transmission.
void RecordHistogramDelta(const base::Histogram& histogram,
const base::Histogram::SampleSet& snapshot);
// Stop writing to this record and generate the encoded representation.
// None of the Record* methods can be called after this is called.
void CloseLog();
// These methods allow retrieval of the encoded representation of the
// record. They can only be called after CloseLog() has been called.
// GetEncodedLog returns false if buffer_size is less than
// GetEncodedLogSize();
int GetEncodedLogSize();
bool GetEncodedLog(char* buffer, int buffer_size);
// Returns an empty string on failure.
std::string GetEncodedLogString();
// Returns the amount of time in seconds that this log has been in use.
int GetElapsedSeconds();
int num_events() { return num_events_; }
void set_hardware_class(const std::string& hardware_class) {
hardware_class_ = hardware_class;
}
// Creates an MD5 hash of the given value, and returns hash as a byte
// buffer encoded as a std::string.
static std::string CreateHash(const std::string& value);
// Return a base64-encoded MD5 hash of the given string.
static std::string CreateBase64Hash(const std::string& string);
// Get the GMT buildtime for the current binary, expressed in seconds since
// Januray 1, 1970 GMT.
// The value is used to identify when a new build is run, so that previous
// reliability stats, from other builds, can be abandoned.
static int64 GetBuildTime();
// Use |extension| in all uploaded appversions in addition to the standard
// version string.
static void set_version_extension(const std::string& extension) {
version_extension_ = extension;
}
virtual MetricsLog* AsMetricsLog();
protected:
class XmlWrapper;
// Returns a string containing the current time.
// Virtual so that it can be overridden for testing.
virtual std::string GetCurrentTimeString();
// Helper class that invokes StartElement from constructor, and EndElement
// from destructor.
//
// Use the macro OPEN_ELEMENT_FOR_SCOPE to help avoid usage problems.
class ScopedElement {
public:
ScopedElement(MetricsLogBase* log, const std::string& name) : log_(log) {
DCHECK(log);
log->StartElement(name.c_str());
}
ScopedElement(MetricsLogBase* log, const char* name) : log_(log) {
DCHECK(log);
log->StartElement(name);
}
~ScopedElement() {
log_->EndElement();
}
private:
MetricsLogBase* log_;
};
friend class ScopedElement;
static const char* WindowEventTypeToString(WindowEventType type);
// Frees the resources allocated by the XML document writer: the
// main writer object as well as the XML tree structure, if
// applicable.
void FreeDocWriter();
// Convenience versions of xmlWriter functions
void StartElement(const char* name);
void EndElement();
void WriteAttribute(const std::string& name, const std::string& value);
void WriteIntAttribute(const std::string& name, int value);
void WriteInt64Attribute(const std::string& name, int64 value);
// Write the attributes that are common to every metrics event type.
void WriteCommonEventAttributes();
// An extension that is appended to the appversion in each log.
static std::string version_extension_;
base::Time start_time_;
base::Time end_time_;
std::string client_id_;
std::string session_id_;
std::string hardware_class_;
// locked_ is true when record has been packed up for sending, and should
// no longer be written to. It is only used for sanity checking and is
// not a real lock.
bool locked_;
// Isolated to limit the dependency on the XML library for our consumers.
XmlWrapper* xml_wrapper_;
int num_events_; // the number of events recorded in this log
DISALLOW_COPY_AND_ASSIGN(MetricsLogBase);
};
// HistogramSender handles the logistics of gathering up available histograms
// for transmission (such as from renderer to browser, or from browser to UMA
// upload). It has several pure virtual functions that are replaced in
// derived classes to allow the exact lower level transmission mechanism,
// or error report mechanism, to be replaced. Since histograms can sit in
// memory for an extended period of time, and are vulnerable to memory
// corruption, this class also validates as much rendundancy as it can before
// calling for the marginal change (a.k.a., delta) in a histogram to be sent
// onward.
class HistogramSender {
protected:
HistogramSender();
virtual ~HistogramSender();
// Snapshot all histograms, and transmit the delta.
// The arguments allow a derived class to select only a subset for
// transmission, or to set a flag in each transmitted histogram.
void TransmitAllHistograms(base::Histogram::Flags flags_to_set,
bool send_only_uma);
// Send the histograms onward, as defined in a derived class.
// This is only called with a delta, listing samples that have not previously
// been transmitted.
virtual void TransmitHistogramDelta(
const base::Histogram& histogram,
const base::Histogram::SampleSet& snapshot) = 0;
// Record various errors found during attempts to send histograms.
virtual void InconsistencyDetected(int problem) = 0;
virtual void UniqueInconsistencyDetected(int problem) = 0;
virtual void SnapshotProblemResolved(int amount) = 0;
private:
// Maintain a map of histogram names to the sample stats we've sent.
typedef std::map<std::string, base::Histogram::SampleSet> LoggedSampleMap;
// List of histograms names, and their encontered corruptions.
typedef std::map<std::string, int> ProblemMap;
// Snapshot this histogram, and transmit the delta.
void TransmitHistogram(const base::Histogram& histogram);
// For histograms, record what we've already transmitted (as a sample for each
// histogram) so that we can send only the delta with the next log.
LoggedSampleMap logged_samples_;
// List of histograms found corrupt to be corrupt, and their problems.
scoped_ptr<ProblemMap> inconsistencies_;
DISALLOW_COPY_AND_ASSIGN(HistogramSender);
};
// This class provides base functionality for logging metrics data.
// TODO(ananta)
// Factor out more common code from chrome and chrome frame metrics service
// into this class.
class MetricsServiceBase : public HistogramSender {
protected:
MetricsServiceBase();
virtual ~MetricsServiceBase();
// Check to see if there is a log that needs to be, or is being, transmitted.
bool pending_log() const {
return pending_log_ || !compressed_log_.empty();
}
// Compress the report log in |input| using bzip2, store the result in
// |output|.
bool Bzip2Compress(const std::string& input, std::string* output);
// Discard |pending_log_|, and clear |compressed_log_|. Called after
// processing of this log is complete.
void DiscardPendingLog();
// Record complete list of histograms into the current log.
// Called when we close a log.
void RecordCurrentHistograms();
// A log that we are currently transmiting, or about to try to transmit.
MetricsLogBase* pending_log_;
// An alternate form of |pending_log_|. We persistently save this version
// into prefs if we can't transmit it. As a result, sometimes all we have is
// the compressed text version.
std::string compressed_log_;
// The log that we are still appending to.
MetricsLogBase* current_log_;
private:
// HistogramSender interface (override) methods.
virtual void TransmitHistogramDelta(
const base::Histogram& histogram,
const base::Histogram::SampleSet& snapshot);
virtual void InconsistencyDetected(int problem);
virtual void UniqueInconsistencyDetected(int problem);
virtual void SnapshotProblemResolved(int amount);
DISALLOW_COPY_AND_ASSIGN(MetricsServiceBase);
};
#endif // CHROME_COMMON_METRICS_HELPERS_H_