// Copyright 2018 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 #include #include #include #include #include #include #include #include namespace cobalt_client { namespace { using internal::Logger; using internal::Metadata; using internal::RemoteCounter; using internal::RemoteHistogram; Metadata MakeMetadata(uint32_t event_type_index) { Metadata metadata; metadata.event_type = 0; metadata.event_type_index = event_type_index; return metadata; } } // namespace Collector::Collector(const CollectorOptions& options, fbl::unique_ptr logger) : logger_(fbl::move(logger)) { flushing_.store(false); remote_counters_.reserve(options.max_counters); remote_histograms_.reserve(options.max_histograms); histogram_options_.reserve(options.max_histograms); } Collector::Collector(Collector&& other) : histogram_options_(fbl::move(other.histogram_options_)), remote_histograms_(fbl::move(other.remote_histograms_)), remote_counters_(fbl::move(other.remote_counters_)), logger_(fbl::move(other.logger_)), flushing_(other.flushing_.load()) {} Collector::~Collector() { if (logger_ != nullptr) { Flush(); } }; Histogram Collector::AddHistogram(uint64_t metric_id, uint32_t event_type_index, const HistogramOptions& options) { ZX_DEBUG_ASSERT_MSG(remote_histograms_.size() < remote_histograms_.capacity(), "Exceeded pre-allocated histogram capacity."); remote_histograms_.push_back( RemoteHistogram(options.bucket_count + 2, metric_id, {MakeMetadata(event_type_index)})); histogram_options_.push_back(options); size_t index = remote_histograms_.size() - 1; return Histogram(&histogram_options_[index], &remote_histograms_[index]); } Counter Collector::AddCounter(uint64_t metric_id, uint32_t event_type_index) { ZX_DEBUG_ASSERT_MSG(remote_counters_.size() < remote_counters_.capacity(), "Exceeded pre-allocated counter capacity."); remote_counters_.push_back(RemoteCounter(metric_id, {MakeMetadata(event_type_index)})); size_t index = remote_counters_.size() - 1; return Counter(&remote_counters_[index]); } void Collector::Flush() { // If we are already flushing we just return and do nothing. // First come first serve. if (flushing_.exchange(true)) { return; } for (auto& histogram : remote_histograms_) { LogHistogram(&histogram); } for (auto& counter : remote_counters_) { LogCounter(&counter); } // Once we are finished we allow flushing again. flushing_.store(false); } void Collector::LogHistogram(RemoteHistogram* histogram) { histogram->Flush([this, histogram](uint64_t metric_id, const RemoteHistogram::EventBuffer& buffer, RemoteHistogram::FlushCompleteFn complete_fn) { if (!logger_->Log(metric_id, buffer)) { // If we failed to log the data, then add the values again to the histogram, so they may // be flushed in the future, and we dont need to keep a buffer around for retrying or // anything. for (auto& bucket : buffer.event_data()) { if (bucket.count > 0) { histogram->IncrementCount(bucket.index, bucket.count); } } } // Make the buffer writeable again. complete_fn(); }); } void Collector::LogCounter(RemoteCounter* counter) { counter->Flush([this, counter](uint64_t metric_id, const RemoteCounter::EventBuffer& buffer, RemoteCounter::FlushCompleteFn complete_fn) { // Attempt to log data, if we fail, we increase the in process counter by the amount // flushed. if (!logger_->Log(metric_id, buffer)) { if (buffer.event_data() > 0) { counter->Increment(buffer.event_data()); } } // Make the buffer writeable again. complete_fn(); }); } } // namespace cobalt_client