• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
SerializedLog()15 MetricsLogManager::SerializedLog::SerializedLog() {}
~SerializedLog()16 MetricsLogManager::SerializedLog::~SerializedLog() {}
17 
IsEmpty() const18 bool MetricsLogManager::SerializedLog::IsEmpty() const {
19   return log_text_.empty();
20 }
21 
SwapLogText(std::string * log_text)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 
Clear()30 void MetricsLogManager::SerializedLog::Clear() {
31   log_text_.clear();
32   log_hash_.clear();
33 }
34 
Swap(MetricsLogManager::SerializedLog * other)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 
MetricsLogManager()41 MetricsLogManager::MetricsLogManager()
42     : unsent_logs_loaded_(false),
43       current_log_type_(MetricsLogBase::NO_LOG),
44       paused_log_type_(MetricsLogBase::NO_LOG),
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_LOG) {}
49 
~MetricsLogManager()50 MetricsLogManager::~MetricsLogManager() {}
51 
BeginLoggingWithLog(MetricsLogBase * log,LogType log_type)52 void MetricsLogManager::BeginLoggingWithLog(MetricsLogBase* log,
53                                             LogType log_type) {
54   DCHECK_NE(MetricsLogBase::NO_LOG, log_type);
55   DCHECK(!current_log_.get());
56   current_log_.reset(log);
57   current_log_type_ = log_type;
58 }
59 
FinishCurrentLog()60 void MetricsLogManager::FinishCurrentLog() {
61   DCHECK(current_log_.get());
62   DCHECK_NE(MetricsLogBase::NO_LOG, current_log_type_);
63   current_log_->CloseLog();
64   SerializedLog compressed_log;
65   CompressCurrentLog(&compressed_log);
66   if (!compressed_log.IsEmpty())
67     StoreLog(&compressed_log, current_log_type_, NORMAL_STORE);
68   current_log_.reset();
69   current_log_type_ = MetricsLogBase::NO_LOG;
70 }
71 
StageNextLogForUpload()72 void MetricsLogManager::StageNextLogForUpload() {
73   // Prioritize initial logs for uploading.
74   std::vector<SerializedLog>* source_list =
75       unsent_initial_logs_.empty() ? &unsent_ongoing_logs_
76                                    : &unsent_initial_logs_;
77   LogType source_type = (source_list == &unsent_ongoing_logs_) ?
78       MetricsLogBase::ONGOING_LOG : MetricsLogBase::INITIAL_LOG;
79   // CHECK, rather than DCHECK, because swap()ing with an empty list causes
80   // hard-to-identify crashes much later.
81   CHECK(!source_list->empty());
82   DCHECK(staged_log_.IsEmpty());
83   DCHECK_EQ(MetricsLogBase::NO_LOG, staged_log_type_);
84   staged_log_.Swap(&source_list->back());
85   staged_log_type_ = source_type;
86   source_list->pop_back();
87 
88   // If the staged log was the last provisional store, clear that.
89   if (last_provisional_store_index_ != -1) {
90     if (source_type == last_provisional_store_type_ &&
91         static_cast<unsigned int>(last_provisional_store_index_) ==
92             source_list->size()) {
93       last_provisional_store_index_ = -1;
94     }
95   }
96 }
97 
has_staged_log() const98 bool MetricsLogManager::has_staged_log() const {
99   return !staged_log_.IsEmpty();
100 }
101 
DiscardStagedLog()102 void MetricsLogManager::DiscardStagedLog() {
103   staged_log_.Clear();
104   staged_log_type_ = MetricsLogBase::NO_LOG;
105 }
106 
DiscardCurrentLog()107 void MetricsLogManager::DiscardCurrentLog() {
108   current_log_->CloseLog();
109   current_log_.reset();
110   current_log_type_ = MetricsLogBase::NO_LOG;
111 }
112 
PauseCurrentLog()113 void MetricsLogManager::PauseCurrentLog() {
114   DCHECK(!paused_log_.get());
115   DCHECK_EQ(MetricsLogBase::NO_LOG, paused_log_type_);
116   paused_log_.reset(current_log_.release());
117   paused_log_type_ = current_log_type_;
118   current_log_type_ = MetricsLogBase::NO_LOG;
119 }
120 
ResumePausedLog()121 void MetricsLogManager::ResumePausedLog() {
122   DCHECK(!current_log_.get());
123   DCHECK_EQ(MetricsLogBase::NO_LOG, current_log_type_);
124   current_log_.reset(paused_log_.release());
125   current_log_type_ = paused_log_type_;
126   paused_log_type_ = MetricsLogBase::NO_LOG;
127 }
128 
StoreStagedLogAsUnsent(StoreType store_type)129 void MetricsLogManager::StoreStagedLogAsUnsent(StoreType store_type) {
130   DCHECK(has_staged_log());
131 
132   // If compressing the log failed, there's nothing to store.
133   if (staged_log_.IsEmpty())
134     return;
135 
136   StoreLog(&staged_log_, staged_log_type_, store_type);
137   DiscardStagedLog();
138 }
139 
StoreLog(SerializedLog * log,LogType log_type,StoreType store_type)140 void MetricsLogManager::StoreLog(SerializedLog* log,
141                                  LogType log_type,
142                                  StoreType store_type) {
143   DCHECK_NE(MetricsLogBase::NO_LOG, log_type);
144   std::vector<SerializedLog>* destination_list =
145       (log_type == MetricsLogBase::INITIAL_LOG) ? &unsent_initial_logs_
146                                                 : &unsent_ongoing_logs_;
147   destination_list->push_back(SerializedLog());
148   destination_list->back().Swap(log);
149 
150   if (store_type == PROVISIONAL_STORE) {
151     last_provisional_store_index_ = destination_list->size() - 1;
152     last_provisional_store_type_ = log_type;
153   }
154 }
155 
DiscardLastProvisionalStore()156 void MetricsLogManager::DiscardLastProvisionalStore() {
157   if (last_provisional_store_index_ == -1)
158     return;
159   std::vector<SerializedLog>* source_list =
160       (last_provisional_store_type_ == MetricsLogBase::ONGOING_LOG) ?
161           &unsent_ongoing_logs_ : &unsent_initial_logs_;
162   DCHECK_LT(static_cast<unsigned int>(last_provisional_store_index_),
163             source_list->size());
164   source_list->erase(source_list->begin() + last_provisional_store_index_);
165   last_provisional_store_index_ = -1;
166 }
167 
PersistUnsentLogs()168 void MetricsLogManager::PersistUnsentLogs() {
169   DCHECK(log_serializer_.get());
170   if (!log_serializer_.get())
171     return;
172   DCHECK(unsent_logs_loaded_);
173   if (!unsent_logs_loaded_)
174     return;
175 
176   base::ElapsedTimer timer;
177   // Remove any ongoing logs that are over the serialization size limit.
178   if (max_ongoing_log_store_size_) {
179     for (std::vector<SerializedLog>::iterator it = unsent_ongoing_logs_.begin();
180          it != unsent_ongoing_logs_.end();) {
181       size_t log_size = it->log_text().length();
182       if (log_size > max_ongoing_log_store_size_) {
183         UMA_HISTOGRAM_COUNTS("UMA.Large Accumulated Log Not Persisted",
184                              static_cast<int>(log_size));
185         it = unsent_ongoing_logs_.erase(it);
186       } else {
187         ++it;
188       }
189     }
190   }
191   log_serializer_->SerializeLogs(unsent_initial_logs_,
192                                  MetricsLogBase::INITIAL_LOG);
193   log_serializer_->SerializeLogs(unsent_ongoing_logs_,
194                                  MetricsLogBase::ONGOING_LOG);
195   UMA_HISTOGRAM_TIMES("UMA.StoreLogsTime", timer.Elapsed());
196 }
197 
LoadPersistedUnsentLogs()198 void MetricsLogManager::LoadPersistedUnsentLogs() {
199   DCHECK(log_serializer_.get());
200   if (!log_serializer_.get())
201     return;
202 
203   base::ElapsedTimer timer;
204   log_serializer_->DeserializeLogs(MetricsLogBase::INITIAL_LOG,
205                                    &unsent_initial_logs_);
206   log_serializer_->DeserializeLogs(MetricsLogBase::ONGOING_LOG,
207                                    &unsent_ongoing_logs_);
208   UMA_HISTOGRAM_TIMES("UMA.LoadLogsTime", timer.Elapsed());
209 
210   unsent_logs_loaded_ = true;
211 }
212 
CompressCurrentLog(SerializedLog * compressed_log)213 void MetricsLogManager::CompressCurrentLog(SerializedLog* compressed_log) {
214   std::string log_text;
215   current_log_->GetEncodedLog(&log_text);
216   compressed_log->SwapLogText(&log_text);
217 }
218