1 /* 2 * Copyright (C) 2015 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 #include "uploader/metrics_log_base.h" 18 19 #include "base/build_time.h" 20 #include "base/metrics/histogram_base.h" 21 #include "base/metrics/histogram_samples.h" 22 #include "uploader/metrics_hashes.h" 23 #include "uploader/proto/histogram_event.pb.h" 24 #include "uploader/proto/system_profile.pb.h" 25 #include "uploader/proto/user_action_event.pb.h" 26 27 using base::Histogram; 28 using base::HistogramBase; 29 using base::HistogramSamples; 30 using base::SampleCountIterator; 31 using base::Time; 32 using base::TimeDelta; 33 using metrics::HistogramEventProto; 34 using metrics::SystemProfileProto; 35 using metrics::UserActionEventProto; 36 37 namespace metrics { 38 namespace { 39 40 // Any id less than 16 bytes is considered to be a testing id. 41 bool IsTestingID(const std::string& id) { 42 return id.size() < 16; 43 } 44 45 } // namespace 46 47 MetricsLogBase::MetricsLogBase(const std::string& client_id, 48 int session_id, 49 LogType log_type, 50 const std::string& version_string) 51 : num_events_(0), 52 locked_(false), 53 log_type_(log_type) { 54 DCHECK_NE(NO_LOG, log_type); 55 if (IsTestingID(client_id)) 56 uma_proto_.set_client_id(0); 57 else 58 uma_proto_.set_client_id(Hash(client_id)); 59 60 uma_proto_.set_session_id(session_id); 61 uma_proto_.mutable_system_profile()->set_build_timestamp(GetBuildTime()); 62 uma_proto_.mutable_system_profile()->set_app_version(version_string); 63 } 64 65 MetricsLogBase::~MetricsLogBase() {} 66 67 // static 68 uint64_t MetricsLogBase::Hash(const std::string& value) { 69 uint64_t hash = metrics::HashMetricName(value); 70 71 // The following log is VERY helpful when folks add some named histogram into 72 // the code, but forgot to update the descriptive list of histograms. When 73 // that happens, all we get to see (server side) is a hash of the histogram 74 // name. We can then use this logging to find out what histogram name was 75 // being hashed to a given MD5 value by just running the version of Chromium 76 // in question with --enable-logging. 77 VLOG(1) << "Metrics: Hash numeric [" << value << "]=[" << hash << "]"; 78 79 return hash; 80 } 81 82 // static 83 int64_t MetricsLogBase::GetBuildTime() { 84 static int64_t integral_build_time = 0; 85 if (!integral_build_time) { 86 Time time = base::GetBuildTime(); 87 integral_build_time = static_cast<int64_t>(time.ToTimeT()); 88 } 89 return integral_build_time; 90 } 91 92 // static 93 int64_t MetricsLogBase::GetCurrentTime() { 94 return (base::TimeTicks::Now() - base::TimeTicks()).InSeconds(); 95 } 96 97 void MetricsLogBase::CloseLog() { 98 DCHECK(!locked_); 99 locked_ = true; 100 } 101 102 void MetricsLogBase::GetEncodedLog(std::string* encoded_log) { 103 DCHECK(locked_); 104 uma_proto_.SerializeToString(encoded_log); 105 } 106 107 void MetricsLogBase::RecordUserAction(const std::string& key) { 108 DCHECK(!locked_); 109 110 UserActionEventProto* user_action = uma_proto_.add_user_action_event(); 111 user_action->set_name_hash(Hash(key)); 112 user_action->set_time(GetCurrentTime()); 113 114 ++num_events_; 115 } 116 117 void MetricsLogBase::RecordHistogramDelta(const std::string& histogram_name, 118 const HistogramSamples& snapshot) { 119 DCHECK(!locked_); 120 DCHECK_NE(0, snapshot.TotalCount()); 121 122 // We will ignore the MAX_INT/infinite value in the last element of range[]. 123 124 HistogramEventProto* histogram_proto = uma_proto_.add_histogram_event(); 125 histogram_proto->set_name_hash(Hash(histogram_name)); 126 histogram_proto->set_sum(snapshot.sum()); 127 128 for (scoped_ptr<SampleCountIterator> it = snapshot.Iterator(); !it->Done(); 129 it->Next()) { 130 HistogramBase::Sample min; 131 HistogramBase::Sample max; 132 HistogramBase::Count count; 133 it->Get(&min, &max, &count); 134 HistogramEventProto::Bucket* bucket = histogram_proto->add_bucket(); 135 bucket->set_min(min); 136 bucket->set_max(max); 137 bucket->set_count(count); 138 } 139 140 // Omit fields to save space (see rules in histogram_event.proto comments). 141 for (int i = 0; i < histogram_proto->bucket_size(); ++i) { 142 HistogramEventProto::Bucket* bucket = histogram_proto->mutable_bucket(i); 143 if (i + 1 < histogram_proto->bucket_size() && 144 bucket->max() == histogram_proto->bucket(i + 1).min()) { 145 bucket->clear_max(); 146 } else if (bucket->max() == bucket->min() + 1) { 147 bucket->clear_min(); 148 } 149 } 150 } 151 152 } // namespace metrics 153