1 // Copyright 2014 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.
5 #include "components/metrics/metrics_log_manager.h"
9 #include "base/metrics/histogram.h"
10 #include "base/sha1.h"
11 #include "base/strings/string_util.h"
12 #include "base/timer/elapsed_timer.h"
13 #include "components/metrics/metrics_log_base.h"
17 MetricsLogManager::SerializedLog::SerializedLog() {}
18 MetricsLogManager::SerializedLog::~SerializedLog() {}
20 bool MetricsLogManager::SerializedLog::IsEmpty() const {
21 return log_text_
.empty();
24 void MetricsLogManager::SerializedLog::SwapLogText(std::string
* log_text
) {
25 log_text_
.swap(*log_text
);
26 if (log_text_
.empty())
29 log_hash_
= base::SHA1HashString(log_text_
);
32 void MetricsLogManager::SerializedLog::Clear() {
37 void MetricsLogManager::SerializedLog::Swap(
38 MetricsLogManager::SerializedLog
* other
) {
39 log_text_
.swap(other
->log_text_
);
40 log_hash_
.swap(other
->log_hash_
);
43 MetricsLogManager::MetricsLogManager()
44 : unsent_logs_loaded_(false),
45 staged_log_type_(MetricsLogBase::NO_LOG
),
46 max_ongoing_log_store_size_(0),
47 last_provisional_store_index_(-1),
48 last_provisional_store_type_(MetricsLogBase::INITIAL_STABILITY_LOG
) {}
50 MetricsLogManager::~MetricsLogManager() {}
52 void MetricsLogManager::BeginLoggingWithLog(MetricsLogBase
* log
) {
53 DCHECK(!current_log_
.get());
54 current_log_
.reset(log
);
57 void MetricsLogManager::FinishCurrentLog() {
58 DCHECK(current_log_
.get());
59 current_log_
->CloseLog();
60 SerializedLog compressed_log
;
61 CompressCurrentLog(&compressed_log
);
62 if (!compressed_log
.IsEmpty())
63 StoreLog(&compressed_log
, current_log_
->log_type(), NORMAL_STORE
);
67 void MetricsLogManager::StageNextLogForUpload() {
68 // Prioritize initial logs for uploading.
69 std::vector
<SerializedLog
>* source_list
=
70 unsent_initial_logs_
.empty() ? &unsent_ongoing_logs_
71 : &unsent_initial_logs_
;
72 LogType source_type
= (source_list
== &unsent_ongoing_logs_
) ?
73 MetricsLogBase::ONGOING_LOG
: MetricsLogBase::INITIAL_STABILITY_LOG
;
74 // CHECK, rather than DCHECK, because swap()ing with an empty list causes
75 // hard-to-identify crashes much later.
76 CHECK(!source_list
->empty());
77 DCHECK(staged_log_
.IsEmpty());
78 DCHECK_EQ(MetricsLogBase::NO_LOG
, staged_log_type_
);
79 staged_log_
.Swap(&source_list
->back());
80 staged_log_type_
= source_type
;
81 source_list
->pop_back();
83 // If the staged log was the last provisional store, clear that.
84 if (last_provisional_store_index_
!= -1) {
85 if (source_type
== last_provisional_store_type_
&&
86 static_cast<unsigned int>(last_provisional_store_index_
) ==
87 source_list
->size()) {
88 last_provisional_store_index_
= -1;
93 bool MetricsLogManager::has_staged_log() const {
94 return !staged_log_
.IsEmpty();
97 void MetricsLogManager::DiscardStagedLog() {
99 staged_log_type_
= MetricsLogBase::NO_LOG
;
102 void MetricsLogManager::DiscardCurrentLog() {
103 current_log_
->CloseLog();
104 current_log_
.reset();
107 void MetricsLogManager::PauseCurrentLog() {
108 DCHECK(!paused_log_
.get());
109 paused_log_
.reset(current_log_
.release());
112 void MetricsLogManager::ResumePausedLog() {
113 DCHECK(!current_log_
.get());
114 current_log_
.reset(paused_log_
.release());
117 void MetricsLogManager::StoreStagedLogAsUnsent(StoreType store_type
) {
118 DCHECK(has_staged_log());
120 // If compressing the log failed, there's nothing to store.
121 if (staged_log_
.IsEmpty())
124 StoreLog(&staged_log_
, staged_log_type_
, store_type
);
128 void MetricsLogManager::StoreLog(SerializedLog
* log
,
130 StoreType store_type
) {
131 DCHECK_NE(MetricsLogBase::NO_LOG
, log_type
);
132 std::vector
<SerializedLog
>* destination_list
=
133 (log_type
== MetricsLogBase::INITIAL_STABILITY_LOG
) ?
134 &unsent_initial_logs_
: &unsent_ongoing_logs_
;
135 destination_list
->push_back(SerializedLog());
136 destination_list
->back().Swap(log
);
138 if (store_type
== PROVISIONAL_STORE
) {
139 last_provisional_store_index_
= destination_list
->size() - 1;
140 last_provisional_store_type_
= log_type
;
144 void MetricsLogManager::DiscardLastProvisionalStore() {
145 if (last_provisional_store_index_
== -1)
147 std::vector
<SerializedLog
>* source_list
=
148 (last_provisional_store_type_
== MetricsLogBase::ONGOING_LOG
)
149 ? &unsent_ongoing_logs_
150 : &unsent_initial_logs_
;
151 DCHECK_LT(static_cast<unsigned int>(last_provisional_store_index_
),
152 source_list
->size());
153 source_list
->erase(source_list
->begin() + last_provisional_store_index_
);
154 last_provisional_store_index_
= -1;
157 void MetricsLogManager::PersistUnsentLogs() {
158 DCHECK(log_serializer_
.get());
159 if (!log_serializer_
.get())
161 DCHECK(unsent_logs_loaded_
);
162 if (!unsent_logs_loaded_
)
165 base::ElapsedTimer timer
;
166 // Remove any ongoing logs that are over the serialization size limit.
167 if (max_ongoing_log_store_size_
) {
168 for (std::vector
<SerializedLog
>::iterator it
= unsent_ongoing_logs_
.begin();
169 it
!= unsent_ongoing_logs_
.end();) {
170 size_t log_size
= it
->log_text().length();
171 if (log_size
> max_ongoing_log_store_size_
) {
172 UMA_HISTOGRAM_COUNTS("UMA.Large Accumulated Log Not Persisted",
173 static_cast<int>(log_size
));
174 it
= unsent_ongoing_logs_
.erase(it
);
180 log_serializer_
->SerializeLogs(unsent_initial_logs_
,
181 MetricsLogBase::INITIAL_STABILITY_LOG
);
182 log_serializer_
->SerializeLogs(unsent_ongoing_logs_
,
183 MetricsLogBase::ONGOING_LOG
);
184 UMA_HISTOGRAM_TIMES("UMA.StoreLogsTime", timer
.Elapsed());
187 void MetricsLogManager::LoadPersistedUnsentLogs() {
188 DCHECK(log_serializer_
.get());
189 if (!log_serializer_
.get())
192 base::ElapsedTimer timer
;
193 log_serializer_
->DeserializeLogs(MetricsLogBase::INITIAL_STABILITY_LOG
,
194 &unsent_initial_logs_
);
195 log_serializer_
->DeserializeLogs(MetricsLogBase::ONGOING_LOG
,
196 &unsent_ongoing_logs_
);
197 UMA_HISTOGRAM_TIMES("UMA.LoadLogsTime", timer
.Elapsed());
199 unsent_logs_loaded_
= true;
202 void MetricsLogManager::CompressCurrentLog(SerializedLog
* compressed_log
) {
203 std::string log_text
;
204 current_log_
->GetEncodedLog(&log_text
);
205 compressed_log
->SwapLogText(&log_text
);
208 } // namespace metrics