| 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 |