Home | History | Annotate | Download | only in metrics
      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 
     15 MetricsLogManager::SerializedLog::SerializedLog() {}
     16 MetricsLogManager::SerializedLog::~SerializedLog() {}
     17 
     18 bool MetricsLogManager::SerializedLog::IsEmpty() const {
     19   return log_text_.empty();
     20 }
     21 
     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 
     30 void MetricsLogManager::SerializedLog::Clear() {
     31   log_text_.clear();
     32   log_hash_.clear();
     33 }
     34 
     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 
     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 
     50 MetricsLogManager::~MetricsLogManager() {}
     51 
     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 
     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 
     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 
     98 bool MetricsLogManager::has_staged_log() const {
     99   return !staged_log_.IsEmpty();
    100 }
    101 
    102 void MetricsLogManager::DiscardStagedLog() {
    103   staged_log_.Clear();
    104   staged_log_type_ = MetricsLogBase::NO_LOG;
    105 }
    106 
    107 void MetricsLogManager::DiscardCurrentLog() {
    108   current_log_->CloseLog();
    109   current_log_.reset();
    110   current_log_type_ = MetricsLogBase::NO_LOG;
    111 }
    112 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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