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)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 : type_(sample_type),
25 name_(metric_name),
26 sample_(sample),
27 min_(min),
28 max_(max),
29 bucket_count_(bucket_count) {
30 }
31
~MetricSample()32 MetricSample::~MetricSample() {
33 }
34
IsValid() const35 bool MetricSample::IsValid() const {
36 return name().find(' ') == std::string::npos &&
37 name().find('\0') == std::string::npos && !name().empty();
38 }
39
ToString() const40 std::string MetricSample::ToString() const {
41 if (type_ == CRASH) {
42 return base::StringPrintf("crash%c%s%c",
43 '\0',
44 name().c_str(),
45 '\0');
46 }
47 if (type_ == SPARSE_HISTOGRAM) {
48 return base::StringPrintf("sparsehistogram%c%s %d%c",
49 '\0',
50 name().c_str(),
51 sample_,
52 '\0');
53 }
54 if (type_ == LINEAR_HISTOGRAM) {
55 return base::StringPrintf("linearhistogram%c%s %d %d%c",
56 '\0',
57 name().c_str(),
58 sample_,
59 max_,
60 '\0');
61 }
62 if (type_ == HISTOGRAM) {
63 return base::StringPrintf("histogram%c%s %d %d %d %d%c",
64 '\0',
65 name().c_str(),
66 sample_,
67 min_,
68 max_,
69 bucket_count_,
70 '\0');
71 }
72 // The type can only be USER_ACTION.
73 CHECK_EQ(type_, USER_ACTION);
74 return base::StringPrintf("useraction%c%s%c", '\0', name().c_str(), '\0');
75 }
76
sample() const77 int MetricSample::sample() const {
78 CHECK_NE(type_, USER_ACTION);
79 CHECK_NE(type_, CRASH);
80 return sample_;
81 }
82
min() const83 int MetricSample::min() const {
84 CHECK_EQ(type_, HISTOGRAM);
85 return min_;
86 }
87
max() const88 int MetricSample::max() const {
89 CHECK_NE(type_, CRASH);
90 CHECK_NE(type_, USER_ACTION);
91 CHECK_NE(type_, SPARSE_HISTOGRAM);
92 return max_;
93 }
94
bucket_count() const95 int MetricSample::bucket_count() const {
96 CHECK_EQ(type_, HISTOGRAM);
97 return bucket_count_;
98 }
99
100 // static
CrashSample(const std::string & crash_name)101 std::unique_ptr<MetricSample> MetricSample::CrashSample(
102 const std::string& crash_name) {
103 return std::make_unique<MetricSample>(CRASH, crash_name, 0, 0, 0, 0);
104 }
105
106 // static
HistogramSample(const std::string & histogram_name,int sample,int min,int max,int bucket_count)107 std::unique_ptr<MetricSample> MetricSample::HistogramSample(
108 const std::string& histogram_name,
109 int sample,
110 int min,
111 int max,
112 int bucket_count) {
113 return std::make_unique<MetricSample>(HISTOGRAM, histogram_name, sample, min,
114 max, bucket_count);
115 }
116
117 // static
ParseHistogram(const std::string & serialized_histogram)118 std::unique_ptr<MetricSample> MetricSample::ParseHistogram(
119 const std::string& serialized_histogram) {
120 std::vector<base::StringPiece> parts = base::SplitStringPiece(
121 serialized_histogram, " ", base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL);
122
123 if (parts.size() != 5)
124 return nullptr;
125 int sample, min, max, bucket_count;
126 if (parts[0].empty() || !base::StringToInt(parts[1], &sample) ||
127 !base::StringToInt(parts[2], &min) ||
128 !base::StringToInt(parts[3], &max) ||
129 !base::StringToInt(parts[4], &bucket_count)) {
130 return nullptr;
131 }
132
133 return HistogramSample(std::string(parts[0]), sample, min, max, bucket_count);
134 }
135
136 // static
SparseHistogramSample(const std::string & histogram_name,int sample)137 std::unique_ptr<MetricSample> MetricSample::SparseHistogramSample(
138 const std::string& histogram_name,
139 int sample) {
140 return std::make_unique<MetricSample>(SPARSE_HISTOGRAM, histogram_name,
141 sample, 0, 0, 0);
142 }
143
144 // static
ParseSparseHistogram(const std::string & serialized_histogram)145 std::unique_ptr<MetricSample> MetricSample::ParseSparseHistogram(
146 const std::string& serialized_histogram) {
147 std::vector<base::StringPiece> parts = base::SplitStringPiece(
148 serialized_histogram, " ", base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL);
149 if (parts.size() != 2)
150 return nullptr;
151 int sample;
152 if (parts[0].empty() || !base::StringToInt(parts[1], &sample))
153 return nullptr;
154
155 return SparseHistogramSample(std::string(parts[0]), sample);
156 }
157
158 // static
LinearHistogramSample(const std::string & histogram_name,int sample,int max)159 std::unique_ptr<MetricSample> MetricSample::LinearHistogramSample(
160 const std::string& histogram_name,
161 int sample,
162 int max) {
163 return std::make_unique<MetricSample>(LINEAR_HISTOGRAM, histogram_name,
164 sample, 0, max, 0);
165 }
166
167 // static
ParseLinearHistogram(const std::string & serialized_histogram)168 std::unique_ptr<MetricSample> MetricSample::ParseLinearHistogram(
169 const std::string& serialized_histogram) {
170 std::vector<base::StringPiece> parts = base::SplitStringPiece(
171 serialized_histogram, " ", base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL);
172 int sample, max;
173 if (parts.size() != 3)
174 return nullptr;
175 if (parts[0].empty() || !base::StringToInt(parts[1], &sample) ||
176 !base::StringToInt(parts[2], &max)) {
177 return nullptr;
178 }
179
180 return LinearHistogramSample(std::string(parts[0]), sample, max);
181 }
182
183 // static
UserActionSample(const std::string & action_name)184 std::unique_ptr<MetricSample> MetricSample::UserActionSample(
185 const std::string& action_name) {
186 return std::make_unique<MetricSample>(USER_ACTION, action_name, 0, 0, 0, 0);
187 }
188
IsEqual(const MetricSample & metric)189 bool MetricSample::IsEqual(const MetricSample& metric) {
190 return type_ == metric.type_ && name_ == metric.name_ &&
191 sample_ == metric.sample_ && min_ == metric.min_ &&
192 max_ == metric.max_ && bucket_count_ == metric.bucket_count_;
193 }
194
195 } // namespace metrics
196