xref: /aosp_15_r20/external/cronet/components/metrics/serialization/metric_sample.cc (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
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