Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Update metrics configuration patch #1548

Merged
merged 10 commits into from
Nov 18, 2024
1 change: 1 addition & 0 deletions metrics_sdk/Gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ gem 'opentelemetry-sdk', path: '../sdk'
gem 'opentelemetry-test-helpers', path: '../test_helpers'

group :test, :development do
gem 'opentelemetry-exporter-otlp-metrics', path: '../exporter/otlp-metrics'
gem 'pry'
gem 'pry-byebug' unless RUBY_ENGINE == 'jruby'
end
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,57 @@ module Metrics
# The ConfiguratorPatch implements a hook to configure the metrics
# portion of the SDK.
module ConfiguratorPatch
def add_metric_reader(metric_reader)
@metric_readers << metric_reader
end

private

# The metrics_configuration_hook method is where we define the setup process
# for metrics SDK.
def initialize
super
@metric_readers = []
end

# The metrics_configuration_hook method is where we define the setup process for the metrics SDK.
def metrics_configuration_hook
OpenTelemetry.meter_provider = Metrics::MeterProvider.new(resource: @resource)
configure_metric_readers
end

def configure_metric_readers
readers = @metric_readers.empty? ? wrapped_metric_exporters_from_env.compact : @metric_readers
readers.each { |r| OpenTelemetry.meter_provider.add_metric_reader(r) }
end

def wrapped_metric_exporters_from_env
exporters = ENV.fetch('OTEL_METRICS_EXPORTER', 'otlp')
exporters.split(',').map do |exporter|
case exporter.strip
when 'none' then nil
when 'console'
OpenTelemetry.meter_provider.add_metric_reader(
Metrics::Export::PeriodicMetricReader.new(
exporter: Metrics::Export::ConsoleMetricPullExporter.new
)
)
when 'otlp'
kaylareopelle marked this conversation as resolved.
Show resolved Hide resolved
begin
OpenTelemetry.meter_provider.add_metric_reader(
Metrics::Export::PeriodicMetricReader.new(
exporter: OpenTelemetry::Exporter::OTLP::Metrics::MetricsExporter.new
)
)
rescue NameError
OpenTelemetry.logger.warn 'The otlp metrics exporter cannot be configured - please add ' \
'opentelemetry-exporter-otlp-metrics to your Gemfile, metrics will not be exported'
nil
end
else
OpenTelemetry.logger.warn "The #{exporter} exporter is unknown and cannot be configured, " \
'metrics will not be exported'
nil
end
end
end
end
end
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
# frozen_string_literal: true

# Copyright The OpenTelemetry Authors
#
# SPDX-License-Identifier: Apache-2.0

require 'test_helper'
require 'opentelemetry-exporter-otlp-metrics'

describe OpenTelemetry::SDK::Metrics::ConfiguratorPatch do
let(:configurator) { OpenTelemetry::SDK::Configurator.new }
let(:default_resource_attributes) do
{
'telemetry.sdk.name' => 'opentelemetry',
'telemetry.sdk.language' => 'ruby',
'telemetry.sdk.version' => OpenTelemetry::SDK::VERSION,
'process.pid' => Process.pid,
'process.command' => $PROGRAM_NAME,
'process.runtime.name' => RUBY_ENGINE,
'process.runtime.version' => RUBY_VERSION,
'process.runtime.description' => RUBY_DESCRIPTION,
'service.name' => 'unknown_service'
}
end

describe '#configure' do
describe 'meter_provider' do
it 'is an instance of SDK::Metrics::MeterProvider' do
configurator.configure

_(OpenTelemetry.meter_provider).must_be_instance_of(
OpenTelemetry::SDK::Metrics::MeterProvider
)
end
end

describe 'metric readers' do
it 'defaults to a periodic reader with an otlp exporter' do
configurator.configure

assert_equal 1, OpenTelemetry.meter_provider.metric_readers.size
reader = OpenTelemetry.meter_provider.metric_readers[0]

assert_instance_of OpenTelemetry::SDK::Metrics::Export::PeriodicMetricReader, reader
assert_instance_of OpenTelemetry::Exporter::OTLP::Metrics::MetricsExporter, reader.instance_variable_get(:@exporter)
end

it 'can be set by environment variable' do
OpenTelemetry::TestHelpers.with_env('OTEL_METRICS_EXPORTER' => 'console') do
configurator.configure
end

assert_equal 1, OpenTelemetry.meter_provider.metric_readers.size

reader = OpenTelemetry.meter_provider.metric_readers[0]

assert_instance_of OpenTelemetry::SDK::Metrics::Export::PeriodicMetricReader, reader
assert_instance_of OpenTelemetry::SDK::Metrics::Export::ConsoleMetricPullExporter, reader.instance_variable_get(:@exporter)
end

it 'supports "none" as an environment variable' do
OpenTelemetry::TestHelpers.with_test_logger do |log_stream|
OpenTelemetry::TestHelpers.with_env('OTEL_METRICS_EXPORTER' => 'none') do
configurator.configure
end

assert_empty OpenTelemetry.meter_provider.metric_readers

refute_match(/The none exporter is unknown and cannot be configured/, log_stream.string)
end
end

it 'supports multiple exporters passed by environment variable' do
OpenTelemetry::TestHelpers.with_env('OTEL_METRICS_EXPORTER' => 'otlp,console') do
configurator.configure
end

assert_equal 2, OpenTelemetry.meter_provider.metric_readers.size

reader1 = OpenTelemetry.meter_provider.metric_readers[0]
reader2 = OpenTelemetry.meter_provider.metric_readers[1]

assert_instance_of OpenTelemetry::SDK::Metrics::Export::PeriodicMetricReader, reader1
assert_instance_of OpenTelemetry::Exporter::OTLP::Metrics::MetricsExporter, reader1.instance_variable_get(:@exporter)

assert_instance_of OpenTelemetry::SDK::Metrics::Export::PeriodicMetricReader, reader2
assert_instance_of OpenTelemetry::SDK::Metrics::Export::ConsoleMetricPullExporter, reader2.instance_variable_get(:@exporter)
end

it 'defaults to noop with invalid env var' do
OpenTelemetry::TestHelpers.with_test_logger do |log_stream|
OpenTelemetry::TestHelpers.with_env('OTEL_METRICS_EXPORTER' => 'unladen_swallow') do
configurator.configure
end

assert_empty OpenTelemetry.meter_provider.metric_readers
assert_match(/The unladen_swallow exporter is unknown and cannot be configured/, log_stream.string)
end
end

it 'rescues NameErrors when otlp set to env var and the library is not installed' do
OpenTelemetry::TestHelpers.with_test_logger do |log_stream|
OpenTelemetry::Exporter::OTLP::Metrics::MetricsExporter.stub(:new, -> { raise NameError }) do
OpenTelemetry::TestHelpers.with_env('OTEL_METRICS_EXPORTER' => 'otlp') do
configurator.configure
end

assert_empty OpenTelemetry.meter_provider.metric_readers
assert_match(/The otlp metrics exporter cannot be configured - please add opentelemetry-exporter-otlp-metrics to your Gemfile, metrics will not be exported/, log_stream.string)
end
end
end
end
end
end
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,11 @@
describe OpenTelemetry::SDK::Metrics::MeterProvider do
before do
reset_metrics_sdk
OpenTelemetry::SDK.configure
# The MeterProvider tests deal with mock MetricReaders that are manually added
# Run the tests without the configuration patch interfering with the setup
OpenTelemetry::TestHelpers.with_env('OTEL_METRICS_EXPORTER' => 'none') do
OpenTelemetry::SDK.configure
end
end

describe '#meter' do
Expand Down
3 changes: 3 additions & 0 deletions metrics_sdk/test/test_helper.rb
Original file line number Diff line number Diff line change
Expand Up @@ -33,3 +33,6 @@ def with_test_logger
ensure
OpenTelemetry.logger = original_logger
end

# Suppress warn-level logs about a missing OTLP exporter for traces
ENV['OTEL_TRACES_EXPORTER'] = 'none'
Loading