Skip to content

Commit

Permalink
feat: Update metrics configuration patch (#1548)
Browse files Browse the repository at this point in the history
* feat: Add configuration patch to set metrics exporter by environment variable

The environment variable has options for:
* console (default)
* otlp
* in-memory
* none

Like the Traces exporter, more than one exporter can be configured

* fix: Use updated class name for OTLP exporter

* feat: Update config patch for spec compliance

* Default option is now OTLP
* In-Memory option removed, it's not in the spec
* PeriodicMetricReader added for both Console and OTLP exporters
* Add the metrics OTLP exporter gem to the test gem group

* test: Remove setup/teardown tracer env var setting

* test: Update tests for JRuby

* style: Rubocop lines in block

---------

Co-authored-by: Matthew Wear <matthew.wear@gmail.com>
  • Loading branch information
kaylareopelle and mwear authored Nov 18, 2024
1 parent aa6ecce commit d60e3a7
Show file tree
Hide file tree
Showing 5 changed files with 173 additions and 3 deletions.
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' unless RUBY_ENGINE == 'jruby'
gem 'pry'
gem 'pry-byebug' unless RUBY_ENGINE == 'jruby'
end
39 changes: 37 additions & 2 deletions metrics_sdk/lib/opentelemetry/sdk/metrics/configuration_patch.rb
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,47 @@ 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' then OpenTelemetry.meter_provider.add_metric_reader(Metrics::Export::PeriodicMetricReader.new(exporter: Metrics::Export::ConsoleMetricPullExporter.new))
when 'in-memory' then OpenTelemetry.meter_provider.add_metric_reader(Metrics::Export::InMemoryMetricPullExporter.new)
when 'otlp'
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
127 changes: 127 additions & 0 deletions metrics_sdk/test/opentelemetry/sdk/metrics/configuration_patch_test.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
# frozen_string_literal: true

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

require 'test_helper'
require 'opentelemetry-exporter-otlp-metrics' unless RUBY_ENGINE == 'jruby'

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
skip 'OTLP exporter not compatible with JRuby' if RUBY_ENGINE == 'jruby'

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' => 'console,in-memory') 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::SDK::Metrics::Export::ConsoleMetricPullExporter, reader1.instance_variable_get(:@exporter)

assert_instance_of OpenTelemetry::SDK::Metrics::Export::InMemoryMetricPullExporter, reader2
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
if RUBY_ENGINE == 'jruby'
OpenTelemetry::TestHelpers.with_test_logger do |log_stream|
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
else
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
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'

0 comments on commit d60e3a7

Please sign in to comment.