1 // Copyright 2014 The Chromium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "components/metrics/serialization/metric_sample.h"
6
7 #include <string>
8 #include <vector>
9
10 #include "base/check_op.h"
11 #include "base/strings/string_number_conversions.h"
12 #include "base/strings/string_piece.h"
13 #include "base/strings/string_split.h"
14 #include "base/strings/stringprintf.h"
15
16 namespace metrics {
17
MetricSample(MetricSample::SampleType sample_type,const std::string & metric_name,int sample,int min,int max,int bucket_count,int num_samples)18 MetricSample::MetricSample(MetricSample::SampleType sample_type,
19 const std::string& metric_name,
20 int sample,
21 int min,
22 int max,
23 int bucket_count,
24 int num_samples)
25 : type_(sample_type),
26 name_(metric_name),
27 sample_(sample),
28 min_(min),
29 max_(max),
30 bucket_count_(bucket_count),
31 num_samples_(num_samples) {}
32
~MetricSample()33 MetricSample::~MetricSample() {
34 }
35
IsValid() const36 bool MetricSample::IsValid() const {
37 return name().find(' ') == std::string::npos &&
38 name().find('\0') == std::string::npos && !name().empty();
39 }
40
ToString() const41 std::string MetricSample::ToString() const {
42 std::string samples =
43 (num_samples_ == 1) ? "" : base::StringPrintf(" %d", num_samples_);
44 if (type_ == CRASH) {
45 return base::StringPrintf("crash%c%s%s%c", '\0', name().c_str(),
46 samples.c_str(), '\0');
47 }
48 if (type_ == SPARSE_HISTOGRAM) {
49 return base::StringPrintf("sparsehistogram%c%s %d%s%c", '\0',
50 name().c_str(), sample_, samples.c_str(), '\0');
51 }
52 if (type_ == LINEAR_HISTOGRAM) {
53 return base::StringPrintf("linearhistogram%c%s %d %d%s%c", '\0',
54 name().c_str(), sample_, max_, samples.c_str(),
55 '\0');
56 }
57 if (type_ == HISTOGRAM) {
58 return base::StringPrintf("histogram%c%s %d %d %d %d%s%c", '\0',
59 name().c_str(), sample_, min_, max_,
60 bucket_count_, samples.c_str(), '\0');
61 }
62 // The type can only be USER_ACTION.
63 CHECK_EQ(type_, USER_ACTION);
64 return base::StringPrintf("useraction%c%s%s%c", '\0', name().c_str(),
65 samples.c_str(), '\0');
66 }
67
sample() const68 int MetricSample::sample() const {
69 CHECK_NE(type_, USER_ACTION);
70 CHECK_NE(type_, CRASH);
71 return sample_;
72 }
73
min() const74 int MetricSample::min() const {
75 CHECK_EQ(type_, HISTOGRAM);
76 return min_;
77 }
78
max() const79 int MetricSample::max() const {
80 CHECK_NE(type_, CRASH);
81 CHECK_NE(type_, USER_ACTION);
82 CHECK_NE(type_, SPARSE_HISTOGRAM);
83 return max_;
84 }
85
bucket_count() const86 int MetricSample::bucket_count() const {
87 CHECK_EQ(type_, HISTOGRAM);
88 return bucket_count_;
89 }
90
91 // static
CrashSample(const std::string & crash_name,int num_samples)92 std::unique_ptr<MetricSample> MetricSample::CrashSample(
93 const std::string& crash_name,
94 int num_samples) {
95 return std::make_unique<MetricSample>(CRASH, crash_name, 0, 0, 0, 0,
96 num_samples);
97 }
98
99 // static
ParseCrash(const std::string & serialized)100 std::unique_ptr<MetricSample> MetricSample::ParseCrash(
101 const std::string& serialized) {
102 std::vector<base::StringPiece> parts = base::SplitStringPiece(
103 serialized, " ", base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL);
104
105 if (parts.size() != 1 && parts.size() != 2) {
106 return nullptr;
107 }
108 if (parts[0].empty()) {
109 return nullptr;
110 }
111 int num_samples = 1;
112 if (parts.size() == 2) {
113 if (!base::StringToInt(parts[1], &num_samples) || num_samples <= 0) {
114 return nullptr;
115 }
116 }
117
118 return CrashSample(std::string(parts[0]), num_samples);
119 }
120
121 // static
HistogramSample(const std::string & histogram_name,int sample,int min,int max,int bucket_count,int num_samples)122 std::unique_ptr<MetricSample> MetricSample::HistogramSample(
123 const std::string& histogram_name,
124 int sample,
125 int min,
126 int max,
127 int bucket_count,
128 int num_samples) {
129 return std::make_unique<MetricSample>(HISTOGRAM, histogram_name, sample, min,
130 max, bucket_count, num_samples);
131 }
132
133 // static
ParseHistogram(const std::string & serialized_histogram)134 std::unique_ptr<MetricSample> MetricSample::ParseHistogram(
135 const std::string& serialized_histogram) {
136 std::vector<base::StringPiece> parts = base::SplitStringPiece(
137 serialized_histogram, " ", base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL);
138
139 if (parts.size() != 5 && parts.size() != 6) {
140 return nullptr;
141 }
142 int sample, min, max, bucket_count;
143 if (parts[0].empty() || !base::StringToInt(parts[1], &sample) ||
144 !base::StringToInt(parts[2], &min) ||
145 !base::StringToInt(parts[3], &max) ||
146 !base::StringToInt(parts[4], &bucket_count)) {
147 return nullptr;
148 }
149 int num_samples = 1;
150 if (parts.size() == 6) {
151 if (!base::StringToInt(parts[5], &num_samples) || num_samples <= 0) {
152 return nullptr;
153 }
154 }
155
156 return HistogramSample(std::string(parts[0]), sample, min, max, bucket_count,
157 num_samples);
158 }
159
160 // static
SparseHistogramSample(const std::string & histogram_name,int sample,int num_samples)161 std::unique_ptr<MetricSample> MetricSample::SparseHistogramSample(
162 const std::string& histogram_name,
163 int sample,
164 int num_samples) {
165 return std::make_unique<MetricSample>(SPARSE_HISTOGRAM, histogram_name,
166 sample, 0, 0, 0, num_samples);
167 }
168
169 // static
ParseSparseHistogram(const std::string & serialized_histogram)170 std::unique_ptr<MetricSample> MetricSample::ParseSparseHistogram(
171 const std::string& serialized_histogram) {
172 std::vector<base::StringPiece> parts = base::SplitStringPiece(
173 serialized_histogram, " ", base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL);
174 if (parts.size() != 2 && parts.size() != 3) {
175 return nullptr;
176 }
177 int sample;
178 if (parts[0].empty() || !base::StringToInt(parts[1], &sample))
179 return nullptr;
180
181 int num_samples = 1;
182 if (parts.size() == 3) {
183 if (!base::StringToInt(parts[2], &num_samples) || num_samples <= 0) {
184 return nullptr;
185 }
186 }
187
188 return SparseHistogramSample(std::string(parts[0]), sample, num_samples);
189 }
190
191 // static
LinearHistogramSample(const std::string & histogram_name,int sample,int max,int num_samples)192 std::unique_ptr<MetricSample> MetricSample::LinearHistogramSample(
193 const std::string& histogram_name,
194 int sample,
195 int max,
196 int num_samples) {
197 return std::make_unique<MetricSample>(LINEAR_HISTOGRAM, histogram_name,
198 sample, 0, max, 0, num_samples);
199 }
200
201 // static
ParseLinearHistogram(const std::string & serialized_histogram)202 std::unique_ptr<MetricSample> MetricSample::ParseLinearHistogram(
203 const std::string& serialized_histogram) {
204 std::vector<base::StringPiece> parts = base::SplitStringPiece(
205 serialized_histogram, " ", base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL);
206 int sample, max;
207 if (parts.size() != 3 && parts.size() != 4) {
208 return nullptr;
209 }
210 if (parts[0].empty() || !base::StringToInt(parts[1], &sample) ||
211 !base::StringToInt(parts[2], &max)) {
212 return nullptr;
213 }
214
215 int num_samples = 1;
216 if (parts.size() == 4) {
217 if (!base::StringToInt(parts[3], &num_samples) || num_samples <= 0) {
218 return nullptr;
219 }
220 }
221
222 return LinearHistogramSample(std::string(parts[0]), sample, max, num_samples);
223 }
224
225 // static
UserActionSample(const std::string & action_name,int num_samples)226 std::unique_ptr<MetricSample> MetricSample::UserActionSample(
227 const std::string& action_name,
228 int num_samples) {
229 return std::make_unique<MetricSample>(USER_ACTION, action_name, 0, 0, 0, 0,
230 num_samples);
231 }
232
233 // static
ParseUserAction(const std::string & serialized)234 std::unique_ptr<MetricSample> MetricSample::ParseUserAction(
235 const std::string& serialized) {
236 std::vector<base::StringPiece> parts = base::SplitStringPiece(
237 serialized, " ", base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL);
238
239 if (parts.size() != 1 && parts.size() != 2) {
240 return nullptr;
241 }
242 if (parts[0].empty()) {
243 return nullptr;
244 }
245 int num_samples = 1;
246 if (parts.size() == 2) {
247 if (!base::StringToInt(parts[1], &num_samples) || num_samples <= 0) {
248 return nullptr;
249 }
250 }
251
252 return UserActionSample(std::string(parts[0]), num_samples);
253 }
254
IsEqual(const MetricSample & metric)255 bool MetricSample::IsEqual(const MetricSample& metric) {
256 return type_ == metric.type_ && name_ == metric.name_ &&
257 sample_ == metric.sample_ && min_ == metric.min_ &&
258 max_ == metric.max_ && bucket_count_ == metric.bucket_count_ &&
259 num_samples_ == metric.num_samples_;
260 }
261
262 } // namespace metrics
263