metrics_log_manager.cc revision 010d83a9304c5a91596085d917d248abff47903a
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. 4 5#include "components/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 "components/metrics/metrics_log_base.h" 14 15namespace metrics { 16 17MetricsLogManager::SerializedLog::SerializedLog() {} 18MetricsLogManager::SerializedLog::~SerializedLog() {} 19 20bool MetricsLogManager::SerializedLog::IsEmpty() const { 21 return log_text_.empty(); 22} 23 24void MetricsLogManager::SerializedLog::SwapLogText(std::string* log_text) { 25 log_text_.swap(*log_text); 26 if (log_text_.empty()) 27 log_hash_.clear(); 28 else 29 log_hash_ = base::SHA1HashString(log_text_); 30} 31 32void MetricsLogManager::SerializedLog::Clear() { 33 log_text_.clear(); 34 log_hash_.clear(); 35} 36 37void MetricsLogManager::SerializedLog::Swap( 38 MetricsLogManager::SerializedLog* other) { 39 log_text_.swap(other->log_text_); 40 log_hash_.swap(other->log_hash_); 41} 42 43MetricsLogManager::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) {} 49 50MetricsLogManager::~MetricsLogManager() {} 51 52void MetricsLogManager::BeginLoggingWithLog(MetricsLogBase* log) { 53 DCHECK(!current_log_.get()); 54 current_log_.reset(log); 55} 56 57void 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); 64 current_log_.reset(); 65} 66 67void 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(); 82 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; 89 } 90 } 91} 92 93bool MetricsLogManager::has_staged_log() const { 94 return !staged_log_.IsEmpty(); 95} 96 97void MetricsLogManager::DiscardStagedLog() { 98 staged_log_.Clear(); 99 staged_log_type_ = MetricsLogBase::NO_LOG; 100} 101 102void MetricsLogManager::DiscardCurrentLog() { 103 current_log_->CloseLog(); 104 current_log_.reset(); 105} 106 107void MetricsLogManager::PauseCurrentLog() { 108 DCHECK(!paused_log_.get()); 109 paused_log_.reset(current_log_.release()); 110} 111 112void MetricsLogManager::ResumePausedLog() { 113 DCHECK(!current_log_.get()); 114 current_log_.reset(paused_log_.release()); 115} 116 117void MetricsLogManager::StoreStagedLogAsUnsent(StoreType store_type) { 118 DCHECK(has_staged_log()); 119 120 // If compressing the log failed, there's nothing to store. 121 if (staged_log_.IsEmpty()) 122 return; 123 124 StoreLog(&staged_log_, staged_log_type_, store_type); 125 DiscardStagedLog(); 126} 127 128void MetricsLogManager::StoreLog(SerializedLog* log, 129 LogType log_type, 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); 137 138 if (store_type == PROVISIONAL_STORE) { 139 last_provisional_store_index_ = destination_list->size() - 1; 140 last_provisional_store_type_ = log_type; 141 } 142} 143 144void MetricsLogManager::DiscardLastProvisionalStore() { 145 if (last_provisional_store_index_ == -1) 146 return; 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; 155} 156 157void MetricsLogManager::PersistUnsentLogs() { 158 DCHECK(log_serializer_.get()); 159 if (!log_serializer_.get()) 160 return; 161 DCHECK(unsent_logs_loaded_); 162 if (!unsent_logs_loaded_) 163 return; 164 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); 175 } else { 176 ++it; 177 } 178 } 179 } 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()); 185} 186 187void MetricsLogManager::LoadPersistedUnsentLogs() { 188 DCHECK(log_serializer_.get()); 189 if (!log_serializer_.get()) 190 return; 191 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()); 198 199 unsent_logs_loaded_ = true; 200} 201 202void MetricsLogManager::CompressCurrentLog(SerializedLog* compressed_log) { 203 std::string log_text; 204 current_log_->GetEncodedLog(&log_text); 205 compressed_log->SwapLogText(&log_text); 206} 207 208} // namespace metrics 209