• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
MetricsLogManager(PrefService * local_state,size_t max_ongoing_log_size)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 
~MetricsLogManager()57 MetricsLogManager::~MetricsLogManager() {}
58 
BeginLoggingWithLog(scoped_ptr<MetricsLog> log)59 void MetricsLogManager::BeginLoggingWithLog(scoped_ptr<MetricsLog> log) {
60   DCHECK(!current_log_);
61   current_log_ = log.Pass();
62 }
63 
FinishCurrentLog()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 
StageNextLogForUpload()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 
DiscardStagedLog()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 
DiscardCurrentLog()91 void MetricsLogManager::DiscardCurrentLog() {
92   current_log_->CloseLog();
93   current_log_.reset();
94 }
95 
PauseCurrentLog()96 void MetricsLogManager::PauseCurrentLog() {
97   DCHECK(!paused_log_.get());
98   paused_log_.reset(current_log_.release());
99 }
100 
ResumePausedLog()101 void MetricsLogManager::ResumePausedLog() {
102   DCHECK(!current_log_.get());
103   current_log_.reset(paused_log_.release());
104 }
105 
StoreLog(const std::string & log_data,MetricsLog::LogType log_type)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 
StoreStagedLogAsUnsent(PersistedLogs::StoreType store_type)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 
DiscardLastProvisionalStore()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 
PersistUnsentLogs()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 
LoadPersistedUnsentLogs()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