// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 #include #include #include #include #include #include #include #include "opentelemetry/common/spin_lock_mutex.h" #include "opentelemetry/common/timestamp.h" #include "opentelemetry/nostd/function_ref.h" #include "opentelemetry/nostd/span.h" #include "opentelemetry/nostd/string_view.h" #include "opentelemetry/sdk/common/global_log_handler.h" #include "opentelemetry/sdk/instrumentationscope/instrumentation_scope.h" #include "opentelemetry/sdk/instrumentationscope/scope_configurator.h" #include "opentelemetry/sdk/metrics/export/metric_filter.h" #include "opentelemetry/sdk/metrics/meter.h" #include "opentelemetry/sdk/metrics/meter_config.h" #include "opentelemetry/sdk/metrics/meter_context.h" #include "opentelemetry/sdk/metrics/metric_reader.h" #include "opentelemetry/sdk/metrics/state/metric_collector.h" #include "opentelemetry/sdk/metrics/view/instrument_selector.h" #include "opentelemetry/sdk/metrics/view/meter_selector.h" #include "opentelemetry/sdk/metrics/view/view.h" #include "opentelemetry/sdk/metrics/view/view_registry.h" #include "opentelemetry/sdk/resource/resource.h" #include "opentelemetry/version.h" #ifdef ENABLE_METRICS_EXEMPLAR_PREVIEW # include "opentelemetry/sdk/metrics/exemplar/filter_type.h" #endif // ENABLE_METRICS_EXEMPLAR_PREVIEW OPENTELEMETRY_BEGIN_NAMESPACE namespace sdk { namespace metrics { MeterContext::MeterContext(std::unique_ptr views, const opentelemetry::sdk::resource::Resource &resource, std::unique_ptr> meter_configurator) noexcept : resource_{resource}, views_(std::move(views)), sdk_start_ts_{std::chrono::system_clock::now()}, meter_configurator_(std::move(meter_configurator)) {} const resource::Resource &MeterContext::GetResource() const noexcept { return resource_; } ViewRegistry *MeterContext::GetViewRegistry() const noexcept { return views_.get(); } const instrumentationscope::ScopeConfigurator &MeterContext::GetMeterConfigurator() const noexcept { return *meter_configurator_; } bool MeterContext::ForEachMeter( nostd::function_ref &meter)> callback) noexcept { std::lock_guard guard(meter_lock_); for (auto &meter : meters_) { if (!callback(meter)) { return false; } } return true; } nostd::span> MeterContext::GetMeters() noexcept { // no lock required, as this is called by MeterProvider in thread-safe manner. return nostd::span>{meters_.data(), meters_.size()}; } nostd::span> MeterContext::GetCollectors() noexcept { return nostd::span>(collectors_.data(), collectors_.size()); } opentelemetry::common::SystemTimestamp MeterContext::GetSDKStartTime() noexcept { return sdk_start_ts_; } void MeterContext::AddMetricReader(std::shared_ptr reader, std::unique_ptr metric_filter) noexcept { auto collector = std::shared_ptr{ new MetricCollector(this, std::move(reader), std::move(metric_filter))}; collectors_.push_back(collector); } void MeterContext::AddView(std::unique_ptr instrument_selector, std::unique_ptr meter_selector, std::unique_ptr view) noexcept { views_->AddView(std::move(instrument_selector), std::move(meter_selector), std::move(view)); } #ifdef ENABLE_METRICS_EXEMPLAR_PREVIEW void MeterContext::SetExemplarFilter(metrics::ExemplarFilterType exemplar_filter_type) noexcept { exemplar_filter_type_ = exemplar_filter_type; } ExemplarFilterType MeterContext::GetExemplarFilter() const noexcept { return exemplar_filter_type_; } #endif // ENABLE_METRICS_EXEMPLAR_PREVIEW void MeterContext::AddMeter(const std::shared_ptr &meter) { std::lock_guard guard(meter_lock_); meters_.push_back(meter); } void MeterContext::RemoveMeter(nostd::string_view name, nostd::string_view version, nostd::string_view schema_url) { std::lock_guard guard(meter_lock_); std::vector> filtered_meters; for (auto &meter : meters_) { auto scope = meter->GetInstrumentationScope(); if (scope->equal(name, version, schema_url)) { OTEL_INTERNAL_LOG_INFO("[MeterContext::RemoveMeter] removing meter name <" << name << ">, version <" << version << ">, URL <" << schema_url << ">"); } else { filtered_meters.push_back(meter); } } meters_.swap(filtered_meters); } bool MeterContext::Shutdown(std::chrono::microseconds timeout) noexcept { bool result = true; // Shutdown only once. if (!shutdown_latch_.test_and_set(std::memory_order_acquire)) { for (auto &collector : collectors_) { bool status = std::static_pointer_cast(collector)->Shutdown(timeout); result = result && status; } if (!result) { OTEL_INTERNAL_LOG_WARN("[MeterContext::Shutdown] Unable to shutdown all metric readers"); } } else { OTEL_INTERNAL_LOG_WARN("[MeterContext::Shutdown] Shutdown can be invoked only once."); } return result; } bool MeterContext::ForceFlush(std::chrono::microseconds timeout) noexcept { bool result = true; // Simultaneous flush not allowed. const std::lock_guard locked(forceflush_lock_); auto time_remaining = (std::chrono::steady_clock::duration::max)(); if (std::chrono::duration_cast(time_remaining) > timeout) { time_remaining = timeout; } auto current_time = std::chrono::steady_clock::now(); auto expire_time = (std::chrono::steady_clock::time_point::max)(); if (expire_time - current_time > time_remaining) { expire_time = current_time + time_remaining; } for (auto &collector : collectors_) { if (!std::static_pointer_cast(collector)->ForceFlush( std::chrono::duration_cast(time_remaining))) { result = false; } current_time = std::chrono::steady_clock::now(); if (expire_time >= current_time) { time_remaining = expire_time - current_time; } else { time_remaining = std::chrono::steady_clock::duration::zero(); } } if (!result) { OTEL_INTERNAL_LOG_WARN("[MeterContext::ForceFlush] Unable to ForceFlush all metric readers"); } return result; } } // namespace metrics } // namespace sdk OPENTELEMETRY_END_NAMESPACE