blob: de5c17c99ae9aca598624e38f0657b3d6ef1cea1 [file] [log] [blame]
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/browser/chromeos/external_metrics.h"
#include <stddef.h>
#include <map>
#include <memory>
#include <string>
#include <vector>
#include "base/bind.h"
#include "base/command_line.h"
#include "base/metrics/histogram.h"
#include "base/metrics/histogram_functions.h"
#include "base/metrics/statistics_recorder.h"
#include "base/metrics/user_metrics.h"
#include "base/strings/string_number_conversions.h"
#include "base/task/post_task.h"
#include "chrome/browser/metrics/chromeos_metrics_provider.h"
#include "chromeos/chromeos_switches.h"
#include "components/metrics/serialization/metric_sample.h"
#include "components/metrics/serialization/serialization_utils.h"
#include "content/public/browser/browser_task_traits.h"
#include "content/public/browser/browser_thread.h"
using content::BrowserThread;
namespace chromeos {
namespace {
bool CheckValues(const std::string& name,
int minimum,
int maximum,
uint32_t bucket_count) {
if (!base::Histogram::InspectConstructionArguments(
name, &minimum, &maximum, &bucket_count))
return false;
base::HistogramBase* histogram =
base::StatisticsRecorder::FindHistogram(name);
if (!histogram)
return true;
return histogram->HasConstructionArguments(minimum, maximum, bucket_count);
}
bool CheckLinearValues(const std::string& name, int maximum) {
return CheckValues(name, 1, maximum, maximum + 1);
}
// The file from which externally-reported metrics are read.
constexpr char kEventsFilePath[] = "/var/lib/metrics/uma-events";
// Default interval between externally-reported metrics being collected.
constexpr base::TimeDelta kDefaultCollectionInterval =
base::TimeDelta::FromSeconds(30);
} // namespace
ExternalMetrics::ExternalMetrics()
: uma_events_file_(kEventsFilePath),
collection_interval_(kDefaultCollectionInterval) {
const std::string flag_value =
base::CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
switches::kExternalMetricsCollectionInterval);
if (!flag_value.empty()) {
int seconds = -1;
if (base::StringToInt(flag_value, &seconds) && seconds > 0) {
collection_interval_ = base::TimeDelta::FromSeconds(seconds);
} else {
LOG(WARNING) << "Ignoring bad value \"" << flag_value << "\" in --"
<< switches::kExternalMetricsCollectionInterval;
}
}
}
ExternalMetrics::~ExternalMetrics() {}
void ExternalMetrics::Start() {
ScheduleCollector();
}
// static
scoped_refptr<ExternalMetrics> ExternalMetrics::CreateForTesting(
const std::string& filename) {
scoped_refptr<ExternalMetrics> external_metrics(new ExternalMetrics());
external_metrics->uma_events_file_ = filename;
return external_metrics;
}
void ExternalMetrics::RecordActionUI(const std::string& action_string) {
base::RecordComputedAction(action_string);
}
void ExternalMetrics::RecordAction(const std::string& action) {
base::PostTaskWithTraits(
FROM_HERE, {BrowserThread::UI},
base::Bind(&ExternalMetrics::RecordActionUI, this, action));
}
void ExternalMetrics::RecordCrashUI(const std::string& crash_kind) {
ChromeOSMetricsProvider::LogCrash(crash_kind);
}
void ExternalMetrics::RecordCrash(const std::string& crash_kind) {
base::PostTaskWithTraits(
FROM_HERE, {BrowserThread::UI},
base::Bind(&ExternalMetrics::RecordCrashUI, this, crash_kind));
}
void ExternalMetrics::RecordHistogram(const metrics::MetricSample& sample) {
CHECK_EQ(metrics::MetricSample::HISTOGRAM, sample.type());
if (!CheckValues(
sample.name(), sample.min(), sample.max(), sample.bucket_count())) {
DLOG(ERROR) << "Invalid histogram: " << sample.name();
return;
}
base::UmaHistogramCustomCounts(sample.name(), sample.sample(), sample.min(),
sample.max(), sample.bucket_count());
}
void ExternalMetrics::RecordLinearHistogram(
const metrics::MetricSample& sample) {
CHECK_EQ(metrics::MetricSample::LINEAR_HISTOGRAM, sample.type());
if (!CheckLinearValues(sample.name(), sample.max())) {
DLOG(ERROR) << "Invalid linear histogram: " << sample.name();
return;
}
base::UmaHistogramExactLinear(sample.name(), sample.sample(), sample.max());
}
void ExternalMetrics::RecordSparseHistogram(
const metrics::MetricSample& sample) {
CHECK_EQ(metrics::MetricSample::SPARSE_HISTOGRAM, sample.type());
base::UmaHistogramSparse(sample.name(), sample.sample());
}
int ExternalMetrics::CollectEvents() {
std::vector<std::unique_ptr<metrics::MetricSample>> samples;
metrics::SerializationUtils::ReadAndTruncateMetricsFromFile(uma_events_file_,
&samples);
for (auto it = samples.begin(); it != samples.end(); ++it) {
const metrics::MetricSample& sample = **it;
// Do not use the UMA_HISTOGRAM_... macros here. They cache the Histogram
// instance and thus only work if |sample.name()| is constant.
switch (sample.type()) {
case metrics::MetricSample::CRASH:
RecordCrash(sample.name());
break;
case metrics::MetricSample::USER_ACTION:
RecordAction(sample.name());
break;
case metrics::MetricSample::HISTOGRAM:
RecordHistogram(sample);
break;
case metrics::MetricSample::LINEAR_HISTOGRAM:
RecordLinearHistogram(sample);
break;
case metrics::MetricSample::SPARSE_HISTOGRAM:
RecordSparseHistogram(sample);
break;
}
}
return samples.size();
}
void ExternalMetrics::CollectEventsAndReschedule() {
CollectEvents();
ScheduleCollector();
}
void ExternalMetrics::ScheduleCollector() {
base::PostDelayedTaskWithTraits(
FROM_HERE, {base::MayBlock(), base::TaskPriority::BEST_EFFORT},
base::BindOnce(&chromeos::ExternalMetrics::CollectEventsAndReschedule,
this),
collection_interval_);
}
} // namespace chromeos