OLD | NEW |
| (Empty) |
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. | |
4 | |
5 #include "chrome/common/metrics/metrics_log_manager.h" | |
6 | |
7 #include <algorithm> | |
8 | |
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" | |
14 | |
15 MetricsLogManager::SerializedLog::SerializedLog() {} | |
16 MetricsLogManager::SerializedLog::~SerializedLog() {} | |
17 | |
18 bool MetricsLogManager::SerializedLog::IsEmpty() const { | |
19 return log_text_.empty(); | |
20 } | |
21 | |
22 void MetricsLogManager::SerializedLog::SwapLogText(std::string* log_text) { | |
23 log_text_.swap(*log_text); | |
24 if (log_text_.empty()) | |
25 log_hash_.clear(); | |
26 else | |
27 log_hash_ = base::SHA1HashString(log_text_); | |
28 } | |
29 | |
30 void MetricsLogManager::SerializedLog::Clear() { | |
31 log_text_.clear(); | |
32 log_hash_.clear(); | |
33 } | |
34 | |
35 void MetricsLogManager::SerializedLog::Swap( | |
36 MetricsLogManager::SerializedLog* other) { | |
37 log_text_.swap(other->log_text_); | |
38 log_hash_.swap(other->log_hash_); | |
39 } | |
40 | |
41 MetricsLogManager::MetricsLogManager() | |
42 : unsent_logs_loaded_(false), | |
43 staged_log_type_(MetricsLogBase::NO_LOG), | |
44 max_ongoing_log_store_size_(0), | |
45 last_provisional_store_index_(-1), | |
46 last_provisional_store_type_(MetricsLogBase::INITIAL_STABILITY_LOG) {} | |
47 | |
48 MetricsLogManager::~MetricsLogManager() {} | |
49 | |
50 void MetricsLogManager::BeginLoggingWithLog(MetricsLogBase* log) { | |
51 DCHECK(!current_log_.get()); | |
52 current_log_.reset(log); | |
53 } | |
54 | |
55 void MetricsLogManager::FinishCurrentLog() { | |
56 DCHECK(current_log_.get()); | |
57 current_log_->CloseLog(); | |
58 SerializedLog compressed_log; | |
59 CompressCurrentLog(&compressed_log); | |
60 if (!compressed_log.IsEmpty()) | |
61 StoreLog(&compressed_log, current_log_->log_type(), NORMAL_STORE); | |
62 current_log_.reset(); | |
63 } | |
64 | |
65 void MetricsLogManager::StageNextLogForUpload() { | |
66 // Prioritize initial logs for uploading. | |
67 std::vector<SerializedLog>* source_list = | |
68 unsent_initial_logs_.empty() ? &unsent_ongoing_logs_ | |
69 : &unsent_initial_logs_; | |
70 LogType source_type = (source_list == &unsent_ongoing_logs_) ? | |
71 MetricsLogBase::ONGOING_LOG : MetricsLogBase::INITIAL_STABILITY_LOG; | |
72 // CHECK, rather than DCHECK, because swap()ing with an empty list causes | |
73 // hard-to-identify crashes much later. | |
74 CHECK(!source_list->empty()); | |
75 DCHECK(staged_log_.IsEmpty()); | |
76 DCHECK_EQ(MetricsLogBase::NO_LOG, staged_log_type_); | |
77 staged_log_.Swap(&source_list->back()); | |
78 staged_log_type_ = source_type; | |
79 source_list->pop_back(); | |
80 | |
81 // If the staged log was the last provisional store, clear that. | |
82 if (last_provisional_store_index_ != -1) { | |
83 if (source_type == last_provisional_store_type_ && | |
84 static_cast<unsigned int>(last_provisional_store_index_) == | |
85 source_list->size()) { | |
86 last_provisional_store_index_ = -1; | |
87 } | |
88 } | |
89 } | |
90 | |
91 bool MetricsLogManager::has_staged_log() const { | |
92 return !staged_log_.IsEmpty(); | |
93 } | |
94 | |
95 void MetricsLogManager::DiscardStagedLog() { | |
96 staged_log_.Clear(); | |
97 staged_log_type_ = MetricsLogBase::NO_LOG; | |
98 } | |
99 | |
100 void MetricsLogManager::DiscardCurrentLog() { | |
101 current_log_->CloseLog(); | |
102 current_log_.reset(); | |
103 } | |
104 | |
105 void MetricsLogManager::PauseCurrentLog() { | |
106 DCHECK(!paused_log_.get()); | |
107 paused_log_.reset(current_log_.release()); | |
108 } | |
109 | |
110 void MetricsLogManager::ResumePausedLog() { | |
111 DCHECK(!current_log_.get()); | |
112 current_log_.reset(paused_log_.release()); | |
113 } | |
114 | |
115 void MetricsLogManager::StoreStagedLogAsUnsent(StoreType store_type) { | |
116 DCHECK(has_staged_log()); | |
117 | |
118 // If compressing the log failed, there's nothing to store. | |
119 if (staged_log_.IsEmpty()) | |
120 return; | |
121 | |
122 StoreLog(&staged_log_, staged_log_type_, store_type); | |
123 DiscardStagedLog(); | |
124 } | |
125 | |
126 void MetricsLogManager::StoreLog(SerializedLog* log, | |
127 LogType log_type, | |
128 StoreType store_type) { | |
129 DCHECK_NE(MetricsLogBase::NO_LOG, log_type); | |
130 std::vector<SerializedLog>* destination_list = | |
131 (log_type == MetricsLogBase::INITIAL_STABILITY_LOG) ? | |
132 &unsent_initial_logs_ : &unsent_ongoing_logs_; | |
133 destination_list->push_back(SerializedLog()); | |
134 destination_list->back().Swap(log); | |
135 | |
136 if (store_type == PROVISIONAL_STORE) { | |
137 last_provisional_store_index_ = destination_list->size() - 1; | |
138 last_provisional_store_type_ = log_type; | |
139 } | |
140 } | |
141 | |
142 void MetricsLogManager::DiscardLastProvisionalStore() { | |
143 if (last_provisional_store_index_ == -1) | |
144 return; | |
145 std::vector<SerializedLog>* source_list = | |
146 (last_provisional_store_type_ == MetricsLogBase::ONGOING_LOG) ? | |
147 &unsent_ongoing_logs_ : &unsent_initial_logs_; | |
148 DCHECK_LT(static_cast<unsigned int>(last_provisional_store_index_), | |
149 source_list->size()); | |
150 source_list->erase(source_list->begin() + last_provisional_store_index_); | |
151 last_provisional_store_index_ = -1; | |
152 } | |
153 | |
154 void MetricsLogManager::PersistUnsentLogs() { | |
155 DCHECK(log_serializer_.get()); | |
156 if (!log_serializer_.get()) | |
157 return; | |
158 DCHECK(unsent_logs_loaded_); | |
159 if (!unsent_logs_loaded_) | |
160 return; | |
161 | |
162 base::ElapsedTimer timer; | |
163 // Remove any ongoing logs that are over the serialization size limit. | |
164 if (max_ongoing_log_store_size_) { | |
165 for (std::vector<SerializedLog>::iterator it = unsent_ongoing_logs_.begin(); | |
166 it != unsent_ongoing_logs_.end();) { | |
167 size_t log_size = it->log_text().length(); | |
168 if (log_size > max_ongoing_log_store_size_) { | |
169 UMA_HISTOGRAM_COUNTS("UMA.Large Accumulated Log Not Persisted", | |
170 static_cast<int>(log_size)); | |
171 it = unsent_ongoing_logs_.erase(it); | |
172 } else { | |
173 ++it; | |
174 } | |
175 } | |
176 } | |
177 log_serializer_->SerializeLogs(unsent_initial_logs_, | |
178 MetricsLogBase::INITIAL_STABILITY_LOG); | |
179 log_serializer_->SerializeLogs(unsent_ongoing_logs_, | |
180 MetricsLogBase::ONGOING_LOG); | |
181 UMA_HISTOGRAM_TIMES("UMA.StoreLogsTime", timer.Elapsed()); | |
182 } | |
183 | |
184 void MetricsLogManager::LoadPersistedUnsentLogs() { | |
185 DCHECK(log_serializer_.get()); | |
186 if (!log_serializer_.get()) | |
187 return; | |
188 | |
189 base::ElapsedTimer timer; | |
190 log_serializer_->DeserializeLogs(MetricsLogBase::INITIAL_STABILITY_LOG, | |
191 &unsent_initial_logs_); | |
192 log_serializer_->DeserializeLogs(MetricsLogBase::ONGOING_LOG, | |
193 &unsent_ongoing_logs_); | |
194 UMA_HISTOGRAM_TIMES("UMA.LoadLogsTime", timer.Elapsed()); | |
195 | |
196 unsent_logs_loaded_ = true; | |
197 } | |
198 | |
199 void MetricsLogManager::CompressCurrentLog(SerializedLog* compressed_log) { | |
200 std::string log_text; | |
201 current_log_->GetEncodedLog(&log_text); | |
202 compressed_log->SwapLogText(&log_text); | |
203 } | |
OLD | NEW |