Home | History | Annotate | Download | only in metrics
      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                          prefs::kMetricsInitialLogsOld,
     47                          kInitialLogsPersistLimit,
     48                          kStorageByteLimitPerLogType,
     49                          0),
     50       ongoing_log_queue_(local_state,
     51                          prefs::kMetricsOngoingLogs,
     52                          prefs::kMetricsOngoingLogsOld,
     53                          kOngoingLogsPersistLimit,
     54                          kStorageByteLimitPerLogType,
     55                          max_ongoing_log_size) {}
     56 
     57 MetricsLogManager::~MetricsLogManager() {}
     58 
     59 void MetricsLogManager::BeginLoggingWithLog(scoped_ptr<MetricsLog> log) {
     60   DCHECK(!current_log_);
     61   current_log_ = log.Pass();
     62 }
     63 
     64 void MetricsLogManager::FinishCurrentLog() {
     65   DCHECK(current_log_.get());
     66   current_log_->CloseLog();
     67   std::string log_data;
     68   current_log_->GetEncodedLog(&log_data);
     69   if (!log_data.empty())
     70     StoreLog(log_data, current_log_->log_type());
     71   current_log_.reset();
     72 }
     73 
     74 void MetricsLogManager::StageNextLogForUpload() {
     75   DCHECK(!has_staged_log());
     76   if (!initial_log_queue_.empty())
     77     initial_log_queue_.StageLog();
     78   else
     79     ongoing_log_queue_.StageLog();
     80 }
     81 
     82 void MetricsLogManager::DiscardStagedLog() {
     83   DCHECK(has_staged_log());
     84   if (initial_log_queue_.has_staged_log())
     85     initial_log_queue_.DiscardStagedLog();
     86   else
     87     ongoing_log_queue_.DiscardStagedLog();
     88   DCHECK(!has_staged_log());
     89 }
     90 
     91 void MetricsLogManager::DiscardCurrentLog() {
     92   current_log_->CloseLog();
     93   current_log_.reset();
     94 }
     95 
     96 void MetricsLogManager::PauseCurrentLog() {
     97   DCHECK(!paused_log_.get());
     98   paused_log_.reset(current_log_.release());
     99 }
    100 
    101 void MetricsLogManager::ResumePausedLog() {
    102   DCHECK(!current_log_.get());
    103   current_log_.reset(paused_log_.release());
    104 }
    105 
    106 void MetricsLogManager::StoreLog(const std::string& log_data,
    107                                  MetricsLog::LogType log_type) {
    108   switch (log_type) {
    109     case MetricsLog::INITIAL_STABILITY_LOG:
    110       initial_log_queue_.StoreLog(log_data);
    111       break;
    112     case MetricsLog::ONGOING_LOG:
    113       ongoing_log_queue_.StoreLog(log_data);
    114       break;
    115   }
    116 }
    117 
    118 void MetricsLogManager::StoreStagedLogAsUnsent(
    119     PersistedLogs::StoreType store_type) {
    120   DCHECK(has_staged_log());
    121   if (initial_log_queue_.has_staged_log())
    122     initial_log_queue_.StoreStagedLogAsUnsent(store_type);
    123   else
    124     ongoing_log_queue_.StoreStagedLogAsUnsent(store_type);
    125 }
    126 
    127 void MetricsLogManager::DiscardLastProvisionalStore() {
    128   // We have at most one provisional store, (since at most one log is being
    129   // uploaded at a time), so at least one of these will be a no-op.
    130   initial_log_queue_.DiscardLastProvisionalStore();
    131   ongoing_log_queue_.DiscardLastProvisionalStore();
    132 }
    133 
    134 void MetricsLogManager::PersistUnsentLogs() {
    135   DCHECK(unsent_logs_loaded_);
    136   if (!unsent_logs_loaded_)
    137     return;
    138 
    139   base::ElapsedTimer timer;
    140   initial_log_queue_.SerializeLogs();
    141   ongoing_log_queue_.SerializeLogs();
    142   UMA_HISTOGRAM_TIMES("UMA.StoreLogsTime", timer.Elapsed());
    143 }
    144 
    145 void MetricsLogManager::LoadPersistedUnsentLogs() {
    146   base::ElapsedTimer timer;
    147   initial_log_queue_.DeserializeLogs();
    148   ongoing_log_queue_.DeserializeLogs();
    149   UMA_HISTOGRAM_TIMES("UMA.LoadLogsTime", timer.Elapsed());
    150 
    151   unsent_logs_loaded_ = true;
    152 }
    153 
    154 }  // namespace metrics
    155