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/strings/string_util.h" 11 #include "base/timer/elapsed_timer.h" 12 #include "components/metrics/metrics_log.h" 13 #include "components/metrics/metrics_pref_names.h" 14 15 namespace metrics { 16 17 namespace { 18 19 // The number of "initial" logs to save, and hope to send during a future Chrome 20 // session. Initial logs contain crash stats, and are pretty small. 21 const size_t kInitialLogsPersistLimit = 20; 22 23 // The number of ongoing logs to save persistently, and hope to 24 // send during a this or future sessions. Note that each log may be pretty 25 // large, as presumably the related "initial" log wasn't sent (probably nothing 26 // was, as the user was probably off-line). As a result, the log probably kept 27 // accumulating while the "initial" log was stalled, and couldn't be sent. As a 28 // result, we don't want to save too many of these mega-logs. 29 // A "standard shutdown" will create a small log, including just the data that 30 // was not yet been transmitted, and that is normal (to have exactly one 31 // ongoing_log_ at startup). 32 const size_t kOngoingLogsPersistLimit = 8; 33 34 // The number of bytes each of initial and ongoing logs that must be stored. 35 // This ensures that a reasonable amount of history will be stored even if there 36 // is a long series of very small logs. 37 const size_t kStorageByteLimitPerLogType = 300000; 38 39 } // namespace 40 41 MetricsLogManager::MetricsLogManager(PrefService* local_state, 42 size_t max_ongoing_log_size) 43 : unsent_logs_loaded_(false), 44 initial_log_queue_(local_state, 45 prefs::kMetricsInitialLogs, 46 prefs::kMetricsInitialLogsOld, 47 kInitialLogsPersistLimit, 48 kStorageByteLimitPerLogType, 49 0), 50 ongoing_log_queue_(local_state, 51 prefs::kMetricsOngoingLogs, 52 prefs::kMetricsOngoingLogsOld, 53 kOngoingLogsPersistLimit, 54 kStorageByteLimitPerLogType, 55 max_ongoing_log_size) {} 56 57 MetricsLogManager::~MetricsLogManager() {} 58 59 void MetricsLogManager::BeginLoggingWithLog(scoped_ptr<MetricsLog> log) { 60 DCHECK(!current_log_); 61 current_log_ = log.Pass(); 62 } 63 64 void MetricsLogManager::FinishCurrentLog() { 65 DCHECK(current_log_.get()); 66 current_log_->CloseLog(); 67 std::string log_data; 68 current_log_->GetEncodedLog(&log_data); 69 if (!log_data.empty()) 70 StoreLog(log_data, current_log_->log_type()); 71 current_log_.reset(); 72 } 73 74 void MetricsLogManager::StageNextLogForUpload() { 75 DCHECK(!has_staged_log()); 76 if (!initial_log_queue_.empty()) 77 initial_log_queue_.StageLog(); 78 else 79 ongoing_log_queue_.StageLog(); 80 } 81 82 void MetricsLogManager::DiscardStagedLog() { 83 DCHECK(has_staged_log()); 84 if (initial_log_queue_.has_staged_log()) 85 initial_log_queue_.DiscardStagedLog(); 86 else 87 ongoing_log_queue_.DiscardStagedLog(); 88 DCHECK(!has_staged_log()); 89 } 90 91 void MetricsLogManager::DiscardCurrentLog() { 92 current_log_->CloseLog(); 93 current_log_.reset(); 94 } 95 96 void MetricsLogManager::PauseCurrentLog() { 97 DCHECK(!paused_log_.get()); 98 paused_log_.reset(current_log_.release()); 99 } 100 101 void MetricsLogManager::ResumePausedLog() { 102 DCHECK(!current_log_.get()); 103 current_log_.reset(paused_log_.release()); 104 } 105 106 void MetricsLogManager::StoreLog(const std::string& log_data, 107 MetricsLog::LogType log_type) { 108 switch (log_type) { 109 case MetricsLog::INITIAL_STABILITY_LOG: 110 initial_log_queue_.StoreLog(log_data); 111 break; 112 case MetricsLog::ONGOING_LOG: 113 ongoing_log_queue_.StoreLog(log_data); 114 break; 115 } 116 } 117 118 void MetricsLogManager::StoreStagedLogAsUnsent( 119 PersistedLogs::StoreType store_type) { 120 DCHECK(has_staged_log()); 121 if (initial_log_queue_.has_staged_log()) 122 initial_log_queue_.StoreStagedLogAsUnsent(store_type); 123 else 124 ongoing_log_queue_.StoreStagedLogAsUnsent(store_type); 125 } 126 127 void MetricsLogManager::DiscardLastProvisionalStore() { 128 // We have at most one provisional store, (since at most one log is being 129 // uploaded at a time), so at least one of these will be a no-op. 130 initial_log_queue_.DiscardLastProvisionalStore(); 131 ongoing_log_queue_.DiscardLastProvisionalStore(); 132 } 133 134 void MetricsLogManager::PersistUnsentLogs() { 135 DCHECK(unsent_logs_loaded_); 136 if (!unsent_logs_loaded_) 137 return; 138 139 base::ElapsedTimer timer; 140 initial_log_queue_.SerializeLogs(); 141 ongoing_log_queue_.SerializeLogs(); 142 UMA_HISTOGRAM_TIMES("UMA.StoreLogsTime", timer.Elapsed()); 143 } 144 145 void MetricsLogManager::LoadPersistedUnsentLogs() { 146 base::ElapsedTimer timer; 147 initial_log_queue_.DeserializeLogs(); 148 ongoing_log_queue_.DeserializeLogs(); 149 UMA_HISTOGRAM_TIMES("UMA.LoadLogsTime", timer.Elapsed()); 150 151 unsent_logs_loaded_ = true; 152 } 153 154 } // namespace metrics 155