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 kInitialLogsPersistLimit, 47 kStorageByteLimitPerLogType, 48 0), 49 ongoing_log_queue_(local_state, 50 prefs::kMetricsOngoingLogs, 51 kOngoingLogsPersistLimit, 52 kStorageByteLimitPerLogType, 53 max_ongoing_log_size) {} 54 55 MetricsLogManager::~MetricsLogManager() {} 56 57 void MetricsLogManager::BeginLoggingWithLog(scoped_ptr<MetricsLog> log) { 58 DCHECK(!current_log_); 59 current_log_ = log.Pass(); 60 } 61 62 void MetricsLogManager::FinishCurrentLog() { 63 DCHECK(current_log_.get()); 64 current_log_->CloseLog(); 65 std::string log_data; 66 current_log_->GetEncodedLog(&log_data); 67 if (!log_data.empty()) 68 StoreLog(log_data, current_log_->log_type()); 69 current_log_.reset(); 70 } 71 72 void MetricsLogManager::StageNextLogForUpload() { 73 DCHECK(!has_staged_log()); 74 if (!initial_log_queue_.empty()) 75 initial_log_queue_.StageLog(); 76 else 77 ongoing_log_queue_.StageLog(); 78 } 79 80 void MetricsLogManager::DiscardStagedLog() { 81 DCHECK(has_staged_log()); 82 if (initial_log_queue_.has_staged_log()) 83 initial_log_queue_.DiscardStagedLog(); 84 else 85 ongoing_log_queue_.DiscardStagedLog(); 86 DCHECK(!has_staged_log()); 87 } 88 89 void MetricsLogManager::DiscardCurrentLog() { 90 current_log_->CloseLog(); 91 current_log_.reset(); 92 } 93 94 void MetricsLogManager::PauseCurrentLog() { 95 DCHECK(!paused_log_.get()); 96 paused_log_.reset(current_log_.release()); 97 } 98 99 void MetricsLogManager::ResumePausedLog() { 100 DCHECK(!current_log_.get()); 101 current_log_.reset(paused_log_.release()); 102 } 103 104 void MetricsLogManager::StoreLog(const std::string& log_data, 105 MetricsLog::LogType log_type) { 106 switch (log_type) { 107 case MetricsLog::INITIAL_STABILITY_LOG: 108 initial_log_queue_.StoreLog(log_data); 109 break; 110 case MetricsLog::ONGOING_LOG: 111 ongoing_log_queue_.StoreLog(log_data); 112 break; 113 } 114 } 115 116 void MetricsLogManager::PersistUnsentLogs() { 117 DCHECK(unsent_logs_loaded_); 118 if (!unsent_logs_loaded_) 119 return; 120 121 base::ElapsedTimer timer; 122 initial_log_queue_.SerializeLogs(); 123 ongoing_log_queue_.SerializeLogs(); 124 UMA_HISTOGRAM_TIMES("UMA.StoreLogsTime", timer.Elapsed()); 125 } 126 127 void MetricsLogManager::LoadPersistedUnsentLogs() { 128 base::ElapsedTimer timer; 129 initial_log_queue_.DeserializeLogs(); 130 ongoing_log_queue_.DeserializeLogs(); 131 UMA_HISTOGRAM_TIMES("UMA.LoadLogsTime", timer.Elapsed()); 132 133 unsent_logs_loaded_ = true; 134 } 135 136 } // namespace metrics 137