1 // Copyright (c) 2012 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 "chrome/common/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 "chrome/common/metrics/metrics_log_base.h"
15 MetricsLogManager::SerializedLog::SerializedLog() {}
16 MetricsLogManager::SerializedLog::~SerializedLog() {}
18 bool MetricsLogManager::SerializedLog::IsEmpty() const {
19 return log_text_
.empty();
22 void MetricsLogManager::SerializedLog::SwapLogText(std::string
* log_text
) {
23 log_text_
.swap(*log_text
);
24 if (log_text_
.empty())
27 log_hash_
= base::SHA1HashString(log_text_
);
30 void MetricsLogManager::SerializedLog::Clear() {
35 void MetricsLogManager::SerializedLog::Swap(
36 MetricsLogManager::SerializedLog
* other
) {
37 log_text_
.swap(other
->log_text_
);
38 log_hash_
.swap(other
->log_hash_
);
41 MetricsLogManager::MetricsLogManager()
42 : unsent_logs_loaded_(false),
43 current_log_type_(MetricsLogBase::NO_LOG
),
44 paused_log_type_(MetricsLogBase::NO_LOG
),
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_LOG
) {}
50 MetricsLogManager::~MetricsLogManager() {}
52 void MetricsLogManager::BeginLoggingWithLog(MetricsLogBase
* log
,
54 DCHECK_NE(MetricsLogBase::NO_LOG
, log_type
);
55 DCHECK(!current_log_
.get());
56 current_log_
.reset(log
);
57 current_log_type_
= log_type
;
60 void MetricsLogManager::FinishCurrentLog() {
61 DCHECK(current_log_
.get());
62 DCHECK_NE(MetricsLogBase::NO_LOG
, current_log_type_
);
63 current_log_
->CloseLog();
64 SerializedLog compressed_log
;
65 CompressCurrentLog(&compressed_log
);
66 if (!compressed_log
.IsEmpty())
67 StoreLog(&compressed_log
, current_log_type_
, NORMAL_STORE
);
69 current_log_type_
= MetricsLogBase::NO_LOG
;
72 void MetricsLogManager::StageNextLogForUpload() {
73 // Prioritize initial logs for uploading.
74 std::vector
<SerializedLog
>* source_list
=
75 unsent_initial_logs_
.empty() ? &unsent_ongoing_logs_
76 : &unsent_initial_logs_
;
77 LogType source_type
= (source_list
== &unsent_ongoing_logs_
) ?
78 MetricsLogBase::ONGOING_LOG
: MetricsLogBase::INITIAL_LOG
;
79 // CHECK, rather than DCHECK, because swap()ing with an empty list causes
80 // hard-to-identify crashes much later.
81 CHECK(!source_list
->empty());
82 DCHECK(staged_log_
.IsEmpty());
83 DCHECK_EQ(MetricsLogBase::NO_LOG
, staged_log_type_
);
84 staged_log_
.Swap(&source_list
->back());
85 staged_log_type_
= source_type
;
86 source_list
->pop_back();
88 // If the staged log was the last provisional store, clear that.
89 if (last_provisional_store_index_
!= -1) {
90 if (source_type
== last_provisional_store_type_
&&
91 static_cast<unsigned int>(last_provisional_store_index_
) ==
92 source_list
->size()) {
93 last_provisional_store_index_
= -1;
98 bool MetricsLogManager::has_staged_log() const {
99 return !staged_log_
.IsEmpty();
102 void MetricsLogManager::DiscardStagedLog() {
104 staged_log_type_
= MetricsLogBase::NO_LOG
;
107 void MetricsLogManager::DiscardCurrentLog() {
108 current_log_
->CloseLog();
109 current_log_
.reset();
110 current_log_type_
= MetricsLogBase::NO_LOG
;
113 void MetricsLogManager::PauseCurrentLog() {
114 DCHECK(!paused_log_
.get());
115 DCHECK_EQ(MetricsLogBase::NO_LOG
, paused_log_type_
);
116 paused_log_
.reset(current_log_
.release());
117 paused_log_type_
= current_log_type_
;
118 current_log_type_
= MetricsLogBase::NO_LOG
;
121 void MetricsLogManager::ResumePausedLog() {
122 DCHECK(!current_log_
.get());
123 DCHECK_EQ(MetricsLogBase::NO_LOG
, current_log_type_
);
124 current_log_
.reset(paused_log_
.release());
125 current_log_type_
= paused_log_type_
;
126 paused_log_type_
= MetricsLogBase::NO_LOG
;
129 void MetricsLogManager::StoreStagedLogAsUnsent(StoreType store_type
) {
130 DCHECK(has_staged_log());
132 // If compressing the log failed, there's nothing to store.
133 if (staged_log_
.IsEmpty())
136 StoreLog(&staged_log_
, staged_log_type_
, store_type
);
140 void MetricsLogManager::StoreLog(SerializedLog
* log
,
142 StoreType store_type
) {
143 DCHECK_NE(MetricsLogBase::NO_LOG
, log_type
);
144 std::vector
<SerializedLog
>* destination_list
=
145 (log_type
== MetricsLogBase::INITIAL_LOG
) ? &unsent_initial_logs_
146 : &unsent_ongoing_logs_
;
147 destination_list
->push_back(SerializedLog());
148 destination_list
->back().Swap(log
);
150 if (store_type
== PROVISIONAL_STORE
) {
151 last_provisional_store_index_
= destination_list
->size() - 1;
152 last_provisional_store_type_
= log_type
;
156 void MetricsLogManager::DiscardLastProvisionalStore() {
157 if (last_provisional_store_index_
== -1)
159 std::vector
<SerializedLog
>* source_list
=
160 (last_provisional_store_type_
== MetricsLogBase::ONGOING_LOG
) ?
161 &unsent_ongoing_logs_
: &unsent_initial_logs_
;
162 DCHECK_LT(static_cast<unsigned int>(last_provisional_store_index_
),
163 source_list
->size());
164 source_list
->erase(source_list
->begin() + last_provisional_store_index_
);
165 last_provisional_store_index_
= -1;
168 void MetricsLogManager::PersistUnsentLogs() {
169 DCHECK(log_serializer_
.get());
170 if (!log_serializer_
.get())
172 DCHECK(unsent_logs_loaded_
);
173 if (!unsent_logs_loaded_
)
176 base::ElapsedTimer timer
;
177 // Remove any ongoing logs that are over the serialization size limit.
178 if (max_ongoing_log_store_size_
) {
179 for (std::vector
<SerializedLog
>::iterator it
= unsent_ongoing_logs_
.begin();
180 it
!= unsent_ongoing_logs_
.end();) {
181 size_t log_size
= it
->log_text().length();
182 if (log_size
> max_ongoing_log_store_size_
) {
183 UMA_HISTOGRAM_COUNTS("UMA.Large Accumulated Log Not Persisted",
184 static_cast<int>(log_size
));
185 it
= unsent_ongoing_logs_
.erase(it
);
191 log_serializer_
->SerializeLogs(unsent_initial_logs_
,
192 MetricsLogBase::INITIAL_LOG
);
193 log_serializer_
->SerializeLogs(unsent_ongoing_logs_
,
194 MetricsLogBase::ONGOING_LOG
);
195 UMA_HISTOGRAM_TIMES("UMA.StoreLogsTime", timer
.Elapsed());
198 void MetricsLogManager::LoadPersistedUnsentLogs() {
199 DCHECK(log_serializer_
.get());
200 if (!log_serializer_
.get())
203 base::ElapsedTimer timer
;
204 log_serializer_
->DeserializeLogs(MetricsLogBase::INITIAL_LOG
,
205 &unsent_initial_logs_
);
206 log_serializer_
->DeserializeLogs(MetricsLogBase::ONGOING_LOG
,
207 &unsent_ongoing_logs_
);
208 UMA_HISTOGRAM_TIMES("UMA.LoadLogsTime", timer
.Elapsed());
210 unsent_logs_loaded_
= true;
213 void MetricsLogManager::CompressCurrentLog(SerializedLog
* compressed_log
) {
214 std::string log_text
;
215 current_log_
->GetEncodedLog(&log_text
);
216 compressed_log
->SwapLogText(&log_text
);