Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(7494)

Unified Diff: chrome/common/metrics/metrics_log_base.cc

Issue 9474041: Upload UMA data using protocol buffers. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Fix crash in test Created 8 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: chrome/common/metrics/metrics_log_base.cc
diff --git a/chrome/common/metrics/metrics_log_base.cc b/chrome/common/metrics/metrics_log_base.cc
index b2c42f6db3f4a8aa44ae238152db9b39cfc0a870..d6a467f3e7071941072cc26caa7c7fc2ea43885d 100644
--- a/chrome/common/metrics/metrics_log_base.cc
+++ b/chrome/common/metrics/metrics_log_base.cc
@@ -9,10 +9,13 @@
#include "base/md5.h"
#include "base/perftimer.h"
#include "base/string_number_conversions.h"
+#include "base/sys_byteorder.h"
#include "base/sys_info.h"
#include "base/third_party/nspr/prtime.h"
#include "base/utf_string_conversions.h"
#include "chrome/common/logging_chrome.h"
+#include "chrome/common/metrics/proto/histogram_event.pb.h"
+#include "chrome/common/metrics/proto/user_action_event.pb.h"
#include "libxml/xmlwriter.h"
#define OPEN_ELEMENT_FOR_SCOPE(name) ScopedElement scoped_element(this, name)
@@ -20,11 +23,8 @@
using base::Histogram;
using base::Time;
using base::TimeDelta;
-
-// http://blogs.msdn.com/oldnewthing/archive/2004/10/25/247180.aspx
-#if defined(OS_WIN)
-extern "C" IMAGE_DOS_HEADER __ImageBase;
-#endif
+using metrics::HistogramEventProto;
+using metrics::UserActionEventProto;
namespace {
@@ -33,6 +33,43 @@ inline const unsigned char* UnsignedChar(const char* input) {
return reinterpret_cast<const unsigned char*>(input);
}
+// Any id less than 16 bytes is considered to be a testing id.
+bool IsTestingID(const std::string& id) {
+ return id.size() < 16;
+}
+
+// Converts the 8-byte prefix of an MD5 hash into a uint64 value.
+inline uint64 HashToUInt64(const std::string& hash) {
+ uint64 value;
+ DCHECK_GE(hash.size(), sizeof(value));
+ memcpy(&value, hash.data(), sizeof(value));
+ return base::htonll(value);
+}
+
+// Creates an MD5 hash of the given value, and returns hash as a byte buffer
+// encoded as an std::string.
+std::string CreateHash(const std::string& value) {
+ base::MD5Context context;
+ base::MD5Init(&context);
+ base::MD5Update(&context, value);
+
+ base::MD5Digest digest;
+ base::MD5Final(&digest, &context);
+
+ std::string hash(reinterpret_cast<char*>(digest.a), arraysize(digest.a));
+
+ // The following log is VERY helpful when folks add some named histogram into
+ // the code, but forgot to update the descriptive list of histograms. When
+ // that happens, all we get to see (server side) is a hash of the histogram
+ // name. We can then use this logging to find out what histogram name was
+ // being hashed to a given MD5 value by just running the version of Chromium
+ // in question with --enable-logging.
+ DVLOG(1) << "Metrics: Hash numeric [" << value << "]=[" << HashToUInt64(hash)
+ << "]";
+
+ return hash;
+}
+
} // namespace
class MetricsLogBase::XmlWrapper {
@@ -92,11 +129,23 @@ MetricsLogBase::MetricsLogBase(const std::string& client_id, int session_id,
locked_(false),
xml_wrapper_(new XmlWrapper),
num_events_(0) {
+ int64_t build_time = GetBuildTime();
+ // Write the XML version.
StartElement("log");
WriteAttribute("clientid", client_id_);
- WriteInt64Attribute("buildtime", GetBuildTime());
+ WriteInt64Attribute("buildtime", build_time);
WriteAttribute("appversion", version_string);
+
+ // Write the protobuf version.
+ if (IsTestingID(client_id_)) {
+ uma_proto_.set_client_id(0);
+ } else {
+ uma_proto_.set_client_id(HashToUInt64(CreateHash(client_id)));
+ }
+ uma_proto_.set_session_id(session_id);
+ uma_proto_.mutable_system_profile()->set_build_timestamp(build_time);
+ uma_proto_.mutable_system_profile()->set_app_version(version_string);
}
MetricsLogBase::~MetricsLogBase() {
@@ -109,6 +158,38 @@ MetricsLogBase::~MetricsLogBase() {
xml_wrapper_ = NULL;
}
+// static
+void MetricsLogBase::CreateHashes(const std::string& string,
+ std::string* base64_encoded_hash,
+ uint64* numeric_hash) {
+ std::string hash = CreateHash(string);
+
+ std::string encoded_digest;
+ if (base::Base64Encode(hash, &encoded_digest))
+ DVLOG(1) << "Metrics: Hash [" << encoded_digest << "]=[" << string << "]";
+
+ *base64_encoded_hash = encoded_digest;
+ *numeric_hash = HashToUInt64(hash);
+}
+
+// static
+int64 MetricsLogBase::GetBuildTime() {
+ static int64 integral_build_time = 0;
+ if (!integral_build_time) {
+ Time time;
+ const char* kDateTime = __DATE__ " " __TIME__ " GMT";
+ bool result = Time::FromString(kDateTime, &time);
Nico 2013/12/05 01:49:31 Hey, should this use base/build_time.h instead? Th
Ilya Sherman 2013/12/05 01:54:29 I'm not sure, but this code currently matches what
+ DCHECK(result);
+ integral_build_time = static_cast<int64>(time.ToTimeT());
+ }
+ return integral_build_time;
+}
+
+// static
+int64 MetricsLogBase::GetCurrentTime() {
+ return (base::TimeTicks::Now() - base::TimeTicks()).InSeconds();
+}
+
void MetricsLogBase::CloseLog() {
DCHECK(!locked_);
locked_ = true;
@@ -120,6 +201,9 @@ void MetricsLogBase::CloseLog() {
DCHECK_GE(result, 0);
#if defined(OS_CHROMEOS)
+ // TODO(isherman): Once the XML pipeline is deprecated, there will be no need
+ // to track the hardware class in a separate member variable and only write it
+ // out when the log is closed.
xmlNodePtr root = xmlDocGetRootElement(xml_wrapper_->doc());
if (!hardware_class_.empty()) {
// The hardware class is determined after the first ongoing log is
@@ -127,6 +211,10 @@ void MetricsLogBase::CloseLog() {
// attribute when the log is closed instead.
xmlNewProp(root, UnsignedChar("hardwareclass"),
UnsignedChar(hardware_class_.c_str()));
+
+ // Write to the protobuf too.
+ uma_proto_.mutable_system_profile()->mutable_hardware()->set_hardware_class(
+ hardware_class_);
}
// Flattens the XML tree into a character buffer.
@@ -142,79 +230,51 @@ void MetricsLogBase::CloseLog() {
#endif // OS_CHROMEOS
}
-int MetricsLogBase::GetEncodedLogSize() {
+int MetricsLogBase::GetEncodedLogSizeXml() {
DCHECK(locked_);
CHECK(xml_wrapper_);
CHECK(xml_wrapper_->buffer());
return xml_wrapper_->buffer()->use;
}
-bool MetricsLogBase::GetEncodedLog(char* buffer, int buffer_size) {
+bool MetricsLogBase::GetEncodedLogXml(char* buffer, int buffer_size) {
DCHECK(locked_);
- if (buffer_size < GetEncodedLogSize())
+ if (buffer_size < GetEncodedLogSizeXml())
return false;
- memcpy(buffer, xml_wrapper_->buffer()->content, GetEncodedLogSize());
+ memcpy(buffer, xml_wrapper_->buffer()->content, GetEncodedLogSizeXml());
return true;
}
-std::string MetricsLogBase::GetEncodedLogString() {
+void MetricsLogBase::GetEncodedLogProto(std::string* encoded_log) {
DCHECK(locked_);
- return std::string(reinterpret_cast<char*>(xml_wrapper_->buffer()->content));
+ uma_proto_.SerializeToString(encoded_log);
}
int MetricsLogBase::GetElapsedSeconds() {
return static_cast<int>((Time::Now() - start_time_).InSeconds());
}
-std::string MetricsLogBase::CreateHash(const std::string& value) {
- base::MD5Context ctx;
- base::MD5Init(&ctx);
- base::MD5Update(&ctx, value);
-
- base::MD5Digest digest;
- base::MD5Final(&digest, &ctx);
-
- uint64 reverse_uint64;
- // UMA only uses first 8 chars of hash. We use the above uint64 instead
- // of a unsigned char[8] so that we don't run into strict aliasing issues
- // in the LOG statement below when trying to interpret reverse as a uint64.
- unsigned char* reverse = reinterpret_cast<unsigned char *>(&reverse_uint64);
- DCHECK(arraysize(digest.a) >= sizeof(reverse_uint64));
- for (size_t i = 0; i < sizeof(reverse_uint64); ++i)
- reverse[i] = digest.a[sizeof(reverse_uint64) - i - 1];
- // The following log is VERY helpful when folks add some named histogram into
- // the code, but forgot to update the descriptive list of histograms. When
- // that happens, all we get to see (server side) is a hash of the histogram
- // name. We can then use this logging to find out what histogram name was
- // being hashed to a given MD5 value by just running the version of Chromium
- // in question with --enable-logging.
- DVLOG(1) << "Metrics: Hash numeric [" << value
- << "]=[" << reverse_uint64 << "]";
- return std::string(reinterpret_cast<char*>(digest.a), arraysize(digest.a));
-}
-
-std::string MetricsLogBase::CreateBase64Hash(const std::string& string) {
- std::string encoded_digest;
- if (base::Base64Encode(CreateHash(string), &encoded_digest)) {
- DVLOG(1) << "Metrics: Hash [" << encoded_digest << "]=[" << string << "]";
- return encoded_digest;
- }
- return std::string();
-}
-
void MetricsLogBase::RecordUserAction(const char* key) {
DCHECK(!locked_);
- std::string command_hash = CreateBase64Hash(key);
- if (command_hash.empty()) {
+ std::string base64_hash;
+ uint64 numeric_hash;
+ CreateHashes(key, &base64_hash, &numeric_hash);
+ if (base64_hash.empty()) {
NOTREACHED() << "Unable generate encoded hash of command: " << key;
return;
}
+ // Write the XML version.
OPEN_ELEMENT_FOR_SCOPE("uielement");
WriteAttribute("action", "command");
- WriteAttribute("targetidhash", command_hash);
+ WriteAttribute("targetidhash", base64_hash);
+
+ // Write the protobuf version.
+ UserActionEventProto* user_action = uma_proto_.add_user_action_event();
+ user_action->set_name_hash(numeric_hash);
+ user_action->set_time(MetricsLogBase::GetCurrentTime());
// TODO(jhughes): Properly track windows.
WriteIntAttribute("window", 0);
@@ -310,7 +370,7 @@ void MetricsLogBase::WriteCommonEventAttributes() {
}
void MetricsLogBase::WriteAttribute(const std::string& name,
- const std::string& value) {
+ const std::string& value) {
DCHECK(!locked_);
DCHECK(!name.empty());
@@ -359,19 +419,6 @@ void MetricsLogBase::EndElement() {
DCHECK_GE(result, 0);
}
-// static
-int64 MetricsLogBase::GetBuildTime() {
- static int64 integral_build_time = 0;
- if (!integral_build_time) {
- Time time;
- const char* kDateTime = __DATE__ " " __TIME__ " GMT";
- bool result = Time::FromString(kDateTime, &time);
- DCHECK(result);
- integral_build_time = static_cast<int64>(time.ToTimeT());
- }
- return integral_build_time;
-}
-
// TODO(JAR): A The following should really be part of the histogram class.
// Internal state is being needlessly exposed, and it would be hard to reuse
// this code. If we moved this into the Histogram class, then we could use
@@ -387,7 +434,14 @@ void MetricsLogBase::RecordHistogramDelta(
OPEN_ELEMENT_FOR_SCOPE("histogram");
- WriteAttribute("name", CreateBase64Hash(histogram.histogram_name()));
+ std::string base64_name_hash;
+ uint64 numeric_name_hash;
+ CreateHashes(histogram.histogram_name(),
+ &base64_name_hash,
+ &numeric_name_hash);
+
+ // Write the XML version.
+ WriteAttribute("name", base64_name_hash);
WriteInt64Attribute("sum", snapshot.sum());
// TODO(jar): Remove sumsquares when protobuffer accepts this as optional.
@@ -401,4 +455,19 @@ void MetricsLogBase::RecordHistogramDelta(
WriteIntAttribute("count", snapshot.counts(i));
}
}
+
+ // Write the protobuf version.
+ HistogramEventProto* histogram_proto = uma_proto_.add_histogram_event();
+ histogram_proto->set_name_hash(numeric_name_hash);
+ histogram_proto->set_sum(snapshot.sum());
+
+ for (size_t i = 0; i < histogram.bucket_count(); ++i) {
+ if (snapshot.counts(i)) {
+ HistogramEventProto::Bucket* bucket = histogram_proto->add_bucket();
+ bucket->set_min(histogram.ranges(i));
+ bucket->set_max(histogram.ranges(i + 1));
+ bucket->set_bucket_index(i);
+ bucket->set_count(snapshot.counts(i));
+ }
+ }
}

Powered by Google App Engine
This is Rietveld 408576698