| // 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 |