1 // Copyright 2015 The Chromium Authors. All rights reserved.
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/rappor/public/sample.h"
6
7 #include <map>
8 #include <string>
9
10 #include "base/logging.h"
11 #include "base/metrics/metrics_hashes.h"
12 #include "components/rappor/bloom_filter.h"
13 #include "components/rappor/byte_vector_utils.h"
14 #include "components/rappor/proto/rappor_metric.pb.h"
15 #include "components/rappor/reports.h"
16
17 namespace rappor {
18
Sample(int32_t cohort_seed,const RapporParameters & parameters)19 Sample::Sample(int32_t cohort_seed, const RapporParameters& parameters)
20 : parameters_(parameters),
21 bloom_offset_((cohort_seed % parameters_.num_cohorts) *
22 parameters_.bloom_filter_hash_function_count) {
23 // Must use bloom filter size that fits in uint64_t.
24 DCHECK_LE(parameters_.bloom_filter_size_bytes, 8u);
25 }
26
~Sample()27 Sample::~Sample() {
28 }
29
SetStringField(const std::string & field_name,const std::string & value)30 void Sample::SetStringField(const std::string& field_name,
31 const std::string& value) {
32 DVLOG(2) << "Recording sample \"" << value
33 << "\" for sample metric field \"" << field_name << "\"";
34 DCHECK_EQ(0u, field_info_[field_name].size);
35 uint64_t bloom_bits = internal::GetBloomBits(
36 parameters_.bloom_filter_size_bytes,
37 parameters_.bloom_filter_hash_function_count,
38 bloom_offset_,
39 value);
40 field_info_[field_name] = Sample::FieldInfo{
41 parameters_.bloom_filter_size_bytes /* size */,
42 bloom_bits /* value */,
43 parameters_.noise_level,
44 };
45 }
46
SetFlagsField(const std::string & field_name,uint64_t flags,size_t num_flags)47 void Sample::SetFlagsField(const std::string& field_name,
48 uint64_t flags,
49 size_t num_flags) {
50 SetFlagsField(field_name, flags, num_flags, parameters_.noise_level);
51 }
52
SetFlagsField(const std::string & field_name,uint64_t flags,size_t num_flags,NoiseLevel noise_level)53 void Sample::SetFlagsField(const std::string& field_name,
54 uint64_t flags,
55 size_t num_flags,
56 NoiseLevel noise_level) {
57 if (noise_level == NO_NOISE) {
58 // Non-noised fields can only be recorded for UMA rappor metrics.
59 DCHECK_EQ(UMA_RAPPOR_GROUP, parameters_.recording_group);
60 if (parameters_.recording_group != UMA_RAPPOR_GROUP)
61 return;
62 }
63 DVLOG(2) << "Recording flags " << flags
64 << " for sample metric field \"" << field_name << "\"";
65 DCHECK_EQ(0u, field_info_[field_name].size);
66 DCHECK_GT(num_flags, 0u);
67 DCHECK_LE(num_flags, 64u);
68 DCHECK(num_flags == 64u || flags >> num_flags == 0);
69 field_info_[field_name] = Sample::FieldInfo{
70 (num_flags + 7) / 8 /* size */,
71 flags /* value */,
72 noise_level,
73 };
74 }
75
SetUInt64Field(const std::string & field_name,uint64_t value,NoiseLevel noise_level)76 void Sample::SetUInt64Field(const std::string& field_name,
77 uint64_t value,
78 NoiseLevel noise_level) {
79 // Noised integers not supported yet.
80 DCHECK_EQ(NO_NOISE, noise_level);
81 // Non-noised fields can only be recorded for UMA rappor metrics.
82 DCHECK_EQ(UMA_RAPPOR_GROUP, parameters_.recording_group);
83 if (parameters_.recording_group != UMA_RAPPOR_GROUP)
84 return;
85 DCHECK_EQ(0u, field_info_[field_name].size);
86 field_info_[field_name] = Sample::FieldInfo{
87 8,
88 value,
89 noise_level,
90 };
91 }
92
ExportMetrics(const std::string & secret,const std::string & metric_name,RapporReports * reports) const93 void Sample::ExportMetrics(const std::string& secret,
94 const std::string& metric_name,
95 RapporReports* reports) const {
96 for (const auto& kv : field_info_) {
97 FieldInfo field_info = kv.second;
98 ByteVector value_bytes(field_info.size);
99 Uint64ToByteVector(field_info.value, field_info.size, &value_bytes);
100 ByteVector report_bytes = internal::GenerateReport(
101 secret,
102 internal::kNoiseParametersForLevel[field_info.noise_level],
103 value_bytes);
104
105 RapporReports::Report* report = reports->add_report();
106 report->set_name_hash(base::HashMetricName(
107 metric_name + "." + kv.first));
108 report->set_bits(std::string(report_bytes.begin(), report_bytes.end()));
109 DVLOG(2) << "Exporting sample " << metric_name << "." << kv.first;
110 }
111 }
112
113 } // namespace rappor
114