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/strings/string_util.h"
     11 #include "chrome/common/metrics/metrics_log_base.h"
     12 
     13 MetricsLogManager::MetricsLogManager()
     14     : current_log_type_(NO_LOG),
     15       paused_log_type_(NO_LOG),
     16       staged_log_type_(NO_LOG),
     17       max_ongoing_log_store_size_(0),
     18       last_provisional_store_index_(-1),
     19       last_provisional_store_type_(INITIAL_LOG) {}
     20 
     21 MetricsLogManager::~MetricsLogManager() {}
     22 
     23 void MetricsLogManager::BeginLoggingWithLog(MetricsLogBase* log,
     24                                             LogType log_type) {
     25   DCHECK(log_type != NO_LOG);
     26   DCHECK(!current_log_.get());
     27   current_log_.reset(log);
     28   current_log_type_ = log_type;
     29 }
     30 
     31 void MetricsLogManager::FinishCurrentLog() {
     32   DCHECK(current_log_.get());
     33   DCHECK(current_log_type_ != NO_LOG);
     34   current_log_->CloseLog();
     35   std::string compressed_log;
     36   CompressCurrentLog(&compressed_log);
     37   if (!compressed_log.empty())
     38     StoreLog(&compressed_log, current_log_type_, NORMAL_STORE);
     39   current_log_.reset();
     40   current_log_type_ = NO_LOG;
     41 }
     42 
     43 void MetricsLogManager::StageNextLogForUpload() {
     44   // Prioritize initial logs for uploading.
     45   std::vector<std::string>* source_list =
     46       unsent_initial_logs_.empty() ? &unsent_ongoing_logs_
     47                                    : &unsent_initial_logs_;
     48   LogType source_type = (source_list == &unsent_ongoing_logs_) ? ONGOING_LOG
     49                                                                : INITIAL_LOG;
     50   // CHECK, rather than DCHECK, because swap()ing with an empty list causes
     51   // hard-to-identify crashes much later.
     52   CHECK(!source_list->empty());
     53   DCHECK(staged_log_text_.empty());
     54   DCHECK(staged_log_type_ == NO_LOG);
     55   staged_log_text_.swap(source_list->back());
     56   staged_log_type_ = source_type;
     57   source_list->pop_back();
     58 
     59   // If the staged log was the last provisional store, clear that.
     60   if (last_provisional_store_index_ != -1) {
     61     if (source_type == last_provisional_store_type_ &&
     62         static_cast<unsigned int>(last_provisional_store_index_) ==
     63             source_list->size()) {
     64       last_provisional_store_index_ = -1;
     65     }
     66   }
     67 }
     68 
     69 bool MetricsLogManager::has_staged_log() const {
     70   return !staged_log_text().empty();
     71 }
     72 
     73 void MetricsLogManager::DiscardStagedLog() {
     74   staged_log_text_.clear();
     75   staged_log_type_ = NO_LOG;
     76 }
     77 
     78 void MetricsLogManager::DiscardCurrentLog() {
     79   current_log_->CloseLog();
     80   current_log_.reset();
     81   current_log_type_ = NO_LOG;
     82 }
     83 
     84 void MetricsLogManager::PauseCurrentLog() {
     85   DCHECK(!paused_log_.get());
     86   DCHECK(paused_log_type_ == NO_LOG);
     87   paused_log_.reset(current_log_.release());
     88   paused_log_type_ = current_log_type_;
     89   current_log_type_ = NO_LOG;
     90 }
     91 
     92 void MetricsLogManager::ResumePausedLog() {
     93   DCHECK(!current_log_.get());
     94   DCHECK(current_log_type_ == NO_LOG);
     95   current_log_.reset(paused_log_.release());
     96   current_log_type_ = paused_log_type_;
     97   paused_log_type_ = NO_LOG;
     98 }
     99 
    100 void MetricsLogManager::StoreStagedLogAsUnsent(StoreType store_type) {
    101   DCHECK(has_staged_log());
    102 
    103   // If compressing the log failed, there's nothing to store.
    104   if (staged_log_text_.empty())
    105     return;
    106 
    107   StoreLog(&staged_log_text_, staged_log_type_, store_type);
    108   DiscardStagedLog();
    109 }
    110 
    111 void MetricsLogManager::StoreLog(std::string* log_text,
    112                                  LogType log_type,
    113                                  StoreType store_type) {
    114   DCHECK(log_type != NO_LOG);
    115   std::vector<std::string>* destination_list =
    116       (log_type == INITIAL_LOG) ? &unsent_initial_logs_
    117                                 : &unsent_ongoing_logs_;
    118   destination_list->push_back(std::string());
    119   destination_list->back().swap(*log_text);
    120 
    121   if (store_type == PROVISIONAL_STORE) {
    122     last_provisional_store_index_ = destination_list->size() - 1;
    123     last_provisional_store_type_ = log_type;
    124   }
    125 }
    126 
    127 void MetricsLogManager::DiscardLastProvisionalStore() {
    128   if (last_provisional_store_index_ == -1)
    129     return;
    130   std::vector<std::string>* source_list =
    131       (last_provisional_store_type_ == ONGOING_LOG) ? &unsent_ongoing_logs_
    132                                                     : &unsent_initial_logs_;
    133   DCHECK_LT(static_cast<unsigned int>(last_provisional_store_index_),
    134             source_list->size());
    135   source_list->erase(source_list->begin() + last_provisional_store_index_);
    136   last_provisional_store_index_ = -1;
    137 }
    138 
    139 void MetricsLogManager::PersistUnsentLogs() {
    140   DCHECK(log_serializer_.get());
    141   if (!log_serializer_.get())
    142     return;
    143   // Remove any ongoing logs that are over the serialization size limit.
    144   if (max_ongoing_log_store_size_) {
    145     for (std::vector<std::string>::iterator it = unsent_ongoing_logs_.begin();
    146          it != unsent_ongoing_logs_.end();) {
    147       size_t log_size = it->length();
    148       if (log_size > max_ongoing_log_store_size_) {
    149         UMA_HISTOGRAM_COUNTS("UMA.Large Accumulated Log Not Persisted",
    150                              static_cast<int>(log_size));
    151         it = unsent_ongoing_logs_.erase(it);
    152       } else {
    153         ++it;
    154       }
    155     }
    156   }
    157   log_serializer_->SerializeLogs(unsent_initial_logs_, INITIAL_LOG);
    158   log_serializer_->SerializeLogs(unsent_ongoing_logs_, ONGOING_LOG);
    159 }
    160 
    161 void MetricsLogManager::LoadPersistedUnsentLogs() {
    162   DCHECK(log_serializer_.get());
    163   if (!log_serializer_.get())
    164     return;
    165   log_serializer_->DeserializeLogs(INITIAL_LOG, &unsent_initial_logs_);
    166   log_serializer_->DeserializeLogs(ONGOING_LOG, &unsent_ongoing_logs_);
    167 }
    168 
    169 void MetricsLogManager::CompressCurrentLog(std::string* compressed_log) {
    170   current_log_->GetEncodedLog(compressed_log);
    171 }
    172