|  | // Copyright 2019 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 "metrics.h" | 
|  |  | 
|  | #include <lib/async/cpp/task.h> | 
|  | #include <lib/sync/completion.h> | 
|  | #include <lib/syslog/cpp/macros.h> | 
|  | #include <zircon/assert.h> | 
|  |  | 
|  | #include <chrono> | 
|  | #include <condition_variable> | 
|  | #include <mutex> | 
|  | #include <type_traits> | 
|  |  | 
|  | #include <cobalt-client/cpp/metric_options.h> | 
|  |  | 
|  | namespace devmgr { | 
|  | namespace { | 
|  | cobalt_client::MetricOptions MakeMetricOptions(fs_metrics::Event event) { | 
|  | cobalt_client::MetricOptions options; | 
|  | options.metric_id = static_cast<std::underlying_type<fs_metrics::Event>::type>(event); | 
|  | options.event_codes = {0, 0, 0, 0, 0}; | 
|  | return options; | 
|  | } | 
|  | }  // namespace | 
|  |  | 
|  | FsHostMetrics::FsHostMetrics(std::unique_ptr<cobalt_client::Collector> collector) | 
|  | : collector_(std::move(collector)) { | 
|  | cobalt_client::MetricOptions options = MakeMetricOptions(fs_metrics::Event::kDataCorruption); | 
|  | options.metric_dimensions = 2; | 
|  | options.event_codes[0] = static_cast<uint32_t>(fs_metrics::CorruptionSource::kMinfs); | 
|  | options.event_codes[1] = static_cast<uint32_t>(fs_metrics::CorruptionType::kMetadata); | 
|  | counters_.emplace(fs_metrics::Event::kDataCorruption, | 
|  | std::make_unique<cobalt_client::Counter>(options, collector_.get())); | 
|  | thread_ = std::thread([this] { Run(); }); | 
|  | } | 
|  |  | 
|  | FsHostMetrics::~FsHostMetrics() { | 
|  | if (!thread_.joinable()) { | 
|  | return; | 
|  | } | 
|  | { | 
|  | std::lock_guard<std::mutex> lock(mutex_); | 
|  | shut_down_ = true; | 
|  | } | 
|  | condition_.notify_all(); | 
|  | thread_.join(); | 
|  | } | 
|  |  | 
|  | void FsHostMetrics::LogMinfsCorruption() { | 
|  | counters_[fs_metrics::Event::kDataCorruption]->Increment(); | 
|  | } | 
|  |  | 
|  | void FsHostMetrics::Flush() { | 
|  | { | 
|  | std::lock_guard<std::mutex> lock(mutex_); | 
|  | flush_ = true; | 
|  | } | 
|  | condition_.notify_all(); | 
|  | } | 
|  |  | 
|  | void FsHostMetrics::Run() { | 
|  | if (collector_ == nullptr) { | 
|  | return; | 
|  | } | 
|  | auto timeout_time = kSleepDuration; | 
|  | for (;;) { | 
|  | { | 
|  | std::scoped_lock<std::mutex> lock(mutex_); | 
|  | if (shut_down_) { | 
|  | break; | 
|  | } | 
|  | while (!flush_ && !shut_down_ && | 
|  | condition_.wait_for(mutex_, timeout_time) != std::cv_status::timeout) { | 
|  | } | 
|  | flush_ = false; | 
|  | } | 
|  | if (!collector_->Flush()) { | 
|  | timeout_time = kSleepDuration; | 
|  | } else { | 
|  | // Sleep for very long time. | 
|  | timeout_time = std::chrono::hours(24 * 30); | 
|  | } | 
|  | } | 
|  |  | 
|  | if (!collector_->Flush()) { | 
|  | FX_LOGS(ERROR) << "Failed to flush metrics to cobalt"; | 
|  | } | 
|  | } | 
|  |  | 
|  | }  // namespace devmgr |