Bertrand SIMONNET | 52e5b99 | 2015-08-10 15:18:00 -0700 | [diff] [blame] | 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 | */ |
Alex Vakulenko | 788d3b6 | 2014-12-11 09:48:46 -0800 | [diff] [blame] | 16 | |
Bertrand SIMONNET | 4b915ae | 2015-07-28 15:38:14 -0700 | [diff] [blame] | 17 | #include "uploader/metrics_log_base.h" |
Alex Vakulenko | 788d3b6 | 2014-12-11 09:48:46 -0800 | [diff] [blame] | 18 | |
Luis Hector Chavez | 623ce74 | 2016-05-20 23:12:14 -0700 | [diff] [blame] | 19 | #include <memory> |
| 20 | |
Dan Willemsen | faa566d | 2015-10-29 13:00:31 -0700 | [diff] [blame] | 21 | #include "base/build_time.h" |
Alex Vakulenko | 788d3b6 | 2014-12-11 09:48:46 -0800 | [diff] [blame] | 22 | #include "base/metrics/histogram_base.h" |
| 23 | #include "base/metrics/histogram_samples.h" |
Bertrand SIMONNET | 4b915ae | 2015-07-28 15:38:14 -0700 | [diff] [blame] | 24 | #include "uploader/metrics_hashes.h" |
| 25 | #include "uploader/proto/histogram_event.pb.h" |
| 26 | #include "uploader/proto/system_profile.pb.h" |
| 27 | #include "uploader/proto/user_action_event.pb.h" |
Alex Vakulenko | 788d3b6 | 2014-12-11 09:48:46 -0800 | [diff] [blame] | 28 | |
| 29 | using base::Histogram; |
| 30 | using base::HistogramBase; |
| 31 | using base::HistogramSamples; |
| 32 | using base::SampleCountIterator; |
| 33 | using base::Time; |
| 34 | using base::TimeDelta; |
| 35 | using metrics::HistogramEventProto; |
| 36 | using metrics::SystemProfileProto; |
| 37 | using metrics::UserActionEventProto; |
| 38 | |
| 39 | namespace metrics { |
| 40 | namespace { |
| 41 | |
| 42 | // Any id less than 16 bytes is considered to be a testing id. |
| 43 | bool IsTestingID(const std::string& id) { |
| 44 | return id.size() < 16; |
| 45 | } |
| 46 | |
| 47 | } // namespace |
| 48 | |
| 49 | MetricsLogBase::MetricsLogBase(const std::string& client_id, |
| 50 | int session_id, |
| 51 | LogType log_type, |
| 52 | const std::string& version_string) |
| 53 | : num_events_(0), |
| 54 | locked_(false), |
| 55 | log_type_(log_type) { |
| 56 | DCHECK_NE(NO_LOG, log_type); |
| 57 | if (IsTestingID(client_id)) |
| 58 | uma_proto_.set_client_id(0); |
| 59 | else |
| 60 | uma_proto_.set_client_id(Hash(client_id)); |
| 61 | |
| 62 | uma_proto_.set_session_id(session_id); |
| 63 | uma_proto_.mutable_system_profile()->set_build_timestamp(GetBuildTime()); |
| 64 | uma_proto_.mutable_system_profile()->set_app_version(version_string); |
| 65 | } |
| 66 | |
| 67 | MetricsLogBase::~MetricsLogBase() {} |
| 68 | |
| 69 | // static |
| 70 | uint64_t MetricsLogBase::Hash(const std::string& value) { |
| 71 | uint64_t hash = metrics::HashMetricName(value); |
| 72 | |
| 73 | // The following log is VERY helpful when folks add some named histogram into |
| 74 | // the code, but forgot to update the descriptive list of histograms. When |
| 75 | // that happens, all we get to see (server side) is a hash of the histogram |
| 76 | // name. We can then use this logging to find out what histogram name was |
| 77 | // being hashed to a given MD5 value by just running the version of Chromium |
| 78 | // in question with --enable-logging. |
Bertrand SIMONNET | 8835c5b | 2015-09-02 15:07:10 -0700 | [diff] [blame] | 79 | VLOG(1) << "Metrics: Hash numeric [" << value << "]=[" << hash << "]"; |
Alex Vakulenko | 788d3b6 | 2014-12-11 09:48:46 -0800 | [diff] [blame] | 80 | |
| 81 | return hash; |
| 82 | } |
| 83 | |
| 84 | // static |
| 85 | int64_t MetricsLogBase::GetBuildTime() { |
| 86 | static int64_t integral_build_time = 0; |
| 87 | if (!integral_build_time) { |
Dan Willemsen | faa566d | 2015-10-29 13:00:31 -0700 | [diff] [blame] | 88 | Time time = base::GetBuildTime(); |
Alex Vakulenko | 788d3b6 | 2014-12-11 09:48:46 -0800 | [diff] [blame] | 89 | integral_build_time = static_cast<int64_t>(time.ToTimeT()); |
| 90 | } |
| 91 | return integral_build_time; |
| 92 | } |
| 93 | |
| 94 | // static |
| 95 | int64_t MetricsLogBase::GetCurrentTime() { |
| 96 | return (base::TimeTicks::Now() - base::TimeTicks()).InSeconds(); |
| 97 | } |
| 98 | |
| 99 | void MetricsLogBase::CloseLog() { |
| 100 | DCHECK(!locked_); |
| 101 | locked_ = true; |
| 102 | } |
| 103 | |
| 104 | void MetricsLogBase::GetEncodedLog(std::string* encoded_log) { |
| 105 | DCHECK(locked_); |
| 106 | uma_proto_.SerializeToString(encoded_log); |
| 107 | } |
| 108 | |
| 109 | void MetricsLogBase::RecordUserAction(const std::string& key) { |
| 110 | DCHECK(!locked_); |
| 111 | |
| 112 | UserActionEventProto* user_action = uma_proto_.add_user_action_event(); |
| 113 | user_action->set_name_hash(Hash(key)); |
| 114 | user_action->set_time(GetCurrentTime()); |
| 115 | |
| 116 | ++num_events_; |
| 117 | } |
| 118 | |
| 119 | void MetricsLogBase::RecordHistogramDelta(const std::string& histogram_name, |
| 120 | const HistogramSamples& snapshot) { |
| 121 | DCHECK(!locked_); |
| 122 | DCHECK_NE(0, snapshot.TotalCount()); |
| 123 | |
| 124 | // We will ignore the MAX_INT/infinite value in the last element of range[]. |
| 125 | |
| 126 | HistogramEventProto* histogram_proto = uma_proto_.add_histogram_event(); |
| 127 | histogram_proto->set_name_hash(Hash(histogram_name)); |
| 128 | histogram_proto->set_sum(snapshot.sum()); |
| 129 | |
Luis Hector Chavez | 623ce74 | 2016-05-20 23:12:14 -0700 | [diff] [blame] | 130 | for (std::unique_ptr<SampleCountIterator> it = snapshot.Iterator(); !it->Done(); |
Alex Vakulenko | 788d3b6 | 2014-12-11 09:48:46 -0800 | [diff] [blame] | 131 | it->Next()) { |
| 132 | HistogramBase::Sample min; |
| 133 | HistogramBase::Sample max; |
| 134 | HistogramBase::Count count; |
| 135 | it->Get(&min, &max, &count); |
| 136 | HistogramEventProto::Bucket* bucket = histogram_proto->add_bucket(); |
| 137 | bucket->set_min(min); |
| 138 | bucket->set_max(max); |
| 139 | bucket->set_count(count); |
| 140 | } |
| 141 | |
| 142 | // Omit fields to save space (see rules in histogram_event.proto comments). |
| 143 | for (int i = 0; i < histogram_proto->bucket_size(); ++i) { |
| 144 | HistogramEventProto::Bucket* bucket = histogram_proto->mutable_bucket(i); |
| 145 | if (i + 1 < histogram_proto->bucket_size() && |
| 146 | bucket->max() == histogram_proto->bucket(i + 1).min()) { |
| 147 | bucket->clear_max(); |
| 148 | } else if (bucket->max() == bucket->min() + 1) { |
| 149 | bucket->clear_min(); |
| 150 | } |
| 151 | } |
| 152 | } |
| 153 | |
| 154 | } // namespace metrics |