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