blob: e73da004e33967fb872b67b5715da4f1d437e516 [file] [log] [blame]
// Copyright 2020 The Fuchsia 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 "src/cobalt/bin/system-metrics/archivist_stats_fetcher_impl.h"
#include <lib/inspect/contrib/cpp/archive_reader.h>
#include <lib/sys/cpp/component_context.h>
#include <lib/syslog/cpp/macros.h>
#include "src/cobalt/bin/system-metrics/diagnostics_metrics_registry.cb.h"
namespace cobalt {
namespace {
constexpr const char kAllSelector[] = "bootstrap/archivist:root/all_archive_accessor:*";
constexpr const char kFeedbackSelector[] = "bootstrap/archivist:root/feedback_archive_accessor:*";
} // namespace
using Pipeline = fuchsia_component_diagnostics::ComponentDiagnosticsMetricDimensionPipeline;
ArchivistStatsFetcherImpl::ArchivistStatsFetcherImpl(async_dispatcher_t* dispatcher,
sys::ComponentContext* context)
: ArchivistStatsFetcherImpl(dispatcher, [context] {
return context->svc()->Connect<fuchsia::diagnostics::ArchiveAccessor>();
}) {}
ArchivistStatsFetcherImpl::ArchivistStatsFetcherImpl(
async_dispatcher_t* dispatcher,
fit::function<fuchsia::diagnostics::ArchiveAccessorPtr()> connector)
: executor_(dispatcher), connector_(std::move(connector)) {}
void ArchivistStatsFetcherImpl::FetchMetrics(MetricsCallback metrics_callback) {
std::vector<std::string> selectors = {kAllSelector, kFeedbackSelector};
auto reader =
std::make_shared<inspect::contrib::ArchiveReader>(connector_(), std::move(selectors));
executor_.schedule_task(reader->GetInspectSnapshot().then([this, reader,
metrics_callback =
std::move(metrics_callback)](
fit::result<
std::vector<
inspect::contrib::
DiagnosticsData>,
std::string>& results) {
if (!results.is_ok()) {
FX_LOGS(ERROR) << "Failed to fetch data for archivist: " << results.error();
return;
}
if (results.value().size() != 1) {
FX_LOGS(ERROR) << "Expected one result, found " << results.value().size();
return;
}
struct WorkEntry {
const rapidjson::Value& node;
Pipeline pipeline;
};
std::vector<WorkEntry> work_queue;
{
const rapidjson::Value& node = results.value()[0].GetByPath({"root", "all_archive_accessor"});
if (node.IsNull() || !node.IsObject()) {
FX_LOGS(ERROR) << "Could not find object at root/all_archive_accessor";
} else {
work_queue.emplace_back(WorkEntry{.node = node, .pipeline = Pipeline::All});
}
}
{
const rapidjson::Value& node =
results.value()[0].GetByPath({"root", "feedback_archive_accessor"});
if (node.IsNull() || !node.IsObject()) {
FX_LOGS(ERROR) << "Could not find object at root/feedback_archive_accessor";
} else {
work_queue.emplace_back(WorkEntry{.node = node, .pipeline = Pipeline::Feedback});
}
}
for (const WorkEntry& work : work_queue) {
const rapidjson::Value& node = work.node;
Pipeline pipeline = work.pipeline;
for (auto it = node.MemberBegin(); it != node.MemberEnd(); ++it) {
if (!it->value.IsUint64()) {
continue;
}
if (strcmp(it->name.GetString(), "inspect_batch_iterator_get_next_requests") == 0) {
ProcessNewValue(
MeasurementKey(fuchsia_component_diagnostics::kBatchIteratorGetNextRequestsMetricId,
fuchsia_component_diagnostics::BatchIteratorGetNextRequestsEventCodes{
.pipeline = pipeline,
.data_type = fuchsia_component_diagnostics::
BatchIteratorGetNextRequestsMetricDimensionDataType::Inspect}
.ToVector()),
it->value.GetUint64(), metrics_callback);
} else if (strcmp(it->name.GetString(), "inspect_batch_iterator_get_next_errors") == 0) {
ProcessNewValue(
MeasurementKey(fuchsia_component_diagnostics::kBatchIteratorGetNextErrorsMetricId,
fuchsia_component_diagnostics::BatchIteratorGetNextErrorsEventCodes{
.pipeline = pipeline,
.data_type = fuchsia_component_diagnostics::
BatchIteratorGetNextErrorsMetricDimensionDataType::Inspect}
.ToVector()),
it->value.GetUint64(), metrics_callback);
} else if (strcmp(it->name.GetString(), "inspect_batch_iterator_get_next_result_count") ==
0) {
ProcessNewValue(
MeasurementKey(
fuchsia_component_diagnostics::kBatchIteratorGetNextResultCountMetricId,
fuchsia_component_diagnostics::BatchIteratorGetNextResultCountEventCodes{
.pipeline = pipeline,
.data_type = fuchsia_component_diagnostics::
BatchIteratorGetNextResultCountMetricDimensionDataType::Inspect}
.ToVector()),
it->value.GetUint64(), metrics_callback);
} else if (strcmp(it->name.GetString(), "inspect_batch_iterator_get_next_result_errors") ==
0) {
ProcessNewValue(
MeasurementKey(
fuchsia_component_diagnostics::kBatchIteratorGetNextResultErrorsMetricId,
fuchsia_component_diagnostics::BatchIteratorGetNextResultErrorsEventCodes{
.pipeline = pipeline,
.data_type = fuchsia_component_diagnostics::
BatchIteratorGetNextResultErrorsMetricDimensionDataType::Inspect}
.ToVector()),
it->value.GetUint64(), metrics_callback);
} else if (strcmp(it->name.GetString(), "inspect_component_timeouts_count") == 0) {
ProcessNewValue(
MeasurementKey(fuchsia_component_diagnostics::kComponentTimeoutsCountMetricId,
fuchsia_component_diagnostics::ComponentTimeoutsCountEventCodes{
.pipeline = pipeline,
.data_type = fuchsia_component_diagnostics::
ComponentTimeoutsCountMetricDimensionDataType::Inspect}
.ToVector()),
it->value.GetUint64(), metrics_callback);
} else if (strcmp(it->name.GetString(), "archive_accessor_connections_opened") == 0) {
ProcessNewValue(
MeasurementKey(
fuchsia_component_diagnostics::kArchiveAccessorConnectionsOpenedMetricId,
{pipeline}),
it->value.GetUint64(), metrics_callback);
} else if (strcmp(it->name.GetString(), "lifecycle_batch_iterator_get_next_requests") ==
0) {
ProcessNewValue(
MeasurementKey(fuchsia_component_diagnostics::kBatchIteratorGetNextRequestsMetricId,
fuchsia_component_diagnostics::BatchIteratorGetNextRequestsEventCodes{
.pipeline = pipeline,
.data_type = fuchsia_component_diagnostics::
BatchIteratorGetNextRequestsMetricDimensionDataType::Lifecycle}
.ToVector()),
it->value.GetUint64(), metrics_callback);
} else if (strcmp(it->name.GetString(), "lifecycle_batch_iterator_get_next_errors") == 0) {
ProcessNewValue(
MeasurementKey(fuchsia_component_diagnostics::kBatchIteratorGetNextErrorsMetricId,
fuchsia_component_diagnostics::BatchIteratorGetNextErrorsEventCodes{
.pipeline = pipeline,
.data_type = fuchsia_component_diagnostics::
BatchIteratorGetNextErrorsMetricDimensionDataType::Lifecycle}
.ToVector()),
it->value.GetUint64(), metrics_callback);
} else if (strcmp(it->name.GetString(), "lifecycle_batch_iterator_get_next_result_count") ==
0) {
ProcessNewValue(
MeasurementKey(
fuchsia_component_diagnostics::kBatchIteratorGetNextResultCountMetricId,
fuchsia_component_diagnostics::BatchIteratorGetNextResultCountEventCodes{
.pipeline = pipeline,
.data_type = fuchsia_component_diagnostics::
BatchIteratorGetNextResultCountMetricDimensionDataType::Lifecycle}
.ToVector()),
it->value.GetUint64(), metrics_callback);
} else if (strcmp(it->name.GetString(),
"lifecycle_batch_iterator_get_next_result_errors") == 0) {
ProcessNewValue(
MeasurementKey(
fuchsia_component_diagnostics::kBatchIteratorGetNextResultErrorsMetricId,
fuchsia_component_diagnostics::BatchIteratorGetNextResultErrorsEventCodes{
.pipeline = pipeline,
.data_type = fuchsia_component_diagnostics::
BatchIteratorGetNextResultErrorsMetricDimensionDataType::Lifecycle}
.ToVector()),
it->value.GetUint64(), metrics_callback);
} else if (strcmp(it->name.GetString(), "lifecycle_component_timeouts_count") == 0) {
ProcessNewValue(
MeasurementKey(fuchsia_component_diagnostics::kComponentTimeoutsCountMetricId,
fuchsia_component_diagnostics::ComponentTimeoutsCountEventCodes{
.pipeline = pipeline,
.data_type = fuchsia_component_diagnostics::
ComponentTimeoutsCountMetricDimensionDataType::Lifecycle}
.ToVector()),
it->value.GetUint64(), metrics_callback);
}
}
}
}));
}
void ArchivistStatsFetcherImpl::ProcessNewValue(MeasurementKey key, MeasurementValue value,
const MetricsCallback& callback) {
Measurement diff = std::make_pair(key, GetDifferenceForMetric(key, value));
if (diff.second > 0 && callback(diff)) {
UpdatePreviousValue(key, value);
}
}
ArchivistStatsFetcherImpl::MeasurementValue ArchivistStatsFetcherImpl::GetDifferenceForMetric(
const MeasurementKey& key, MeasurementValue value) {
auto it = previous_measurements_.find(key);
MeasurementValue prev = 0;
if (it != previous_measurements_.end()) {
prev = it->second;
}
if (value > prev) {
return value - prev;
} else {
// Prevent underflow.
return 0;
}
}
void ArchivistStatsFetcherImpl::UpdatePreviousValue(const MeasurementKey& key,
MeasurementValue value) {
auto it = previous_measurements_.find(key);
if (it != previous_measurements_.end()) {
it->second = value;
} else {
previous_measurements_.insert(std::make_pair(key, value));
}
}
} // namespace cobalt