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