lib/hypertrace/ruby_agent.rb in hypertrace-agent-0.2.2 vs lib/hypertrace/ruby_agent.rb in hypertrace-agent-0.3.0
- old
+ new
@@ -30,76 +30,127 @@
# RubyAgent is repetitve, but want to remain somewhat consistent compared to python/node
class Hypertrace::RubyAgent
include Hypertrace::Logging
include Singleton
+ SUPPORTED_INSTRUMENTATIONS = [
+ 'OpenTelemetry::Instrumentation::ActionPack',
+ 'OpenTelemetry::Instrumentation::ActionView',
+ 'OpenTelemetry::Instrumentation::ActiveRecord',
+ 'OpenTelemetry::Instrumentation::ActiveSupport',
+ 'OpenTelemetry::Instrumentation::Faraday',
+ 'OpenTelemetry::Instrumentation::Mongo',
+ 'OpenTelemetry::Instrumentation::Mysql2',
+ 'OpenTelemetry::Instrumentation::PG',
+ 'OpenTelemetry::Instrumentation::Rack',
+ 'OpenTelemetry::Instrumentation::Sinatra',
+ 'OpenTelemetry::Instrumentation::Net::HTTP',
+ 'OpenTelemetry::Instrumentation::HTTP',
+ 'OpenTelemetry::Instrumentation::RestClient'
+ ].freeze
+
+ SUPPORTED_INSTRUMENTATIONS_ADDITIONAL_PATCH = {
+ 'OpenTelemetry::Instrumentation::Faraday' => ['./instrumentation/faraday_patch'],
+ 'OpenTelemetry::Instrumentation::Rack' => ['./instrumentation/rack', './instrumentation/rack_env_getter'],
+ 'OpenTelemetry::Instrumentation::Net::HTTP' => ['./instrumentation/net_http_patch'],
+ 'OpenTelemetry::Instrumentation::HTTP' => ['./instrumentation/http_patch'],
+ 'OpenTelemetry::Instrumentation::RestClient' => ['./instrumentation/rest_client_patch'],
+ }
+
def self.instrument!
self.instance.instrument!
end
+ def self.instrument_as_additional!
+ self.instance.instrument_as_additional!
+ end
+
def self.config
self.instance.config
end
def initialize(version = Hypertrace::VERSION)
- log.info {"Initializing Hypertrace"}
- configure_otel_logger!
+ log.info { "Initializing Hypertrace" }
@config = Hypertrace::Config::Config.new
@version = version
- log.info {"Hypertrace version: #{Hypertrace::VERSION}"}
- log.info {"Ruby version: #{RUBY_VERSION}"}
+ log.info { "Hypertrace version: #{Hypertrace::VERSION}" }
+ log.info { "Ruby version: #{RUBY_VERSION}" }
end
def config
@config.config
end
def instrument!
initalize_tracer
end
- def initalize_tracer
+ def instrument_as_additional!
resource = OpenTelemetry::SDK::Resources::Resource.create(create_resource_attributes)
+ exporter = create_resource_customized_exporter resource
+ span_processor = create_span_processor exporter
- # TODO: Extra resource Attributes From Config
- exporter = create_exporter
- OpenTelemetry::SDK.configure do |c|
- if ENV['HT_CI_TEST'] != nil
- span_processor = OpenTelemetry::SDK::Trace::Export::SimpleSpanProcessor.new(EXPORTER)
- c.add_span_processor span_processor
- else
- c.add_span_processor OpenTelemetry::SDK::Trace::Export::BatchSpanProcessor.new(exporter)
- end
- c.resource = resource
-
- c.use 'OpenTelemetry::Instrumentation::ActionPack'
- c.use 'OpenTelemetry::Instrumentation::ActionView'
- c.use 'OpenTelemetry::Instrumentation::ActiveRecord'
- c.use 'OpenTelemetry::Instrumentation::ActiveSupport'
- c.use 'OpenTelemetry::Instrumentation::Faraday'
- c.use 'OpenTelemetry::Instrumentation::Mongo'
- c.use 'OpenTelemetry::Instrumentation::Mysql2'
- c.use 'OpenTelemetry::Instrumentation::PG'
- c.use 'OpenTelemetry::Instrumentation::Rack'
- c.use 'OpenTelemetry::Instrumentation::Sinatra'
- c.use 'OpenTelemetry::Instrumentation::Net::HTTP'
- c.use 'OpenTelemetry::Instrumentation::HTTP'
- c.use 'OpenTelemetry::Instrumentation::RestClient'
+ existing_processors = OpenTelemetry.tracer_provider.instance_variable_get(:"@span_processors")
+ if existing_processors.nil? || existing_processors&.empty?
+ log.error("No existing tracer_provider found, continuing without Hypertrace instrumentation")
+ return
end
+ existing_processors << span_processor
+ OpenTelemetry.tracer_provider.instance_variable_set(:'@span_processors', existing_processors)
+ # We don't pass a span_processor or resource because we have to add it to the already configured tracer provider
+ # The resource will be added at the export phase
+ configure_instrumentation nil, nil
+ configure_propagators
+ end
- apply_custom_patch './instrumentation/rack'
- apply_custom_patch './instrumentation/net_http_patch'
- apply_custom_patch './instrumentation/http_patch'
- apply_custom_patch './instrumentation/faraday_patch'
- apply_custom_patch './instrumentation/rest_client_patch'
- apply_custom_patch './instrumentation/rack_env_getter'
+ def create_span_processor exporter
+ return OpenTelemetry::SDK::Trace::Export::SimpleSpanProcessor.new(EXPORTER) if ENV['HT_CI_TEST'] != nil
+ return OpenTelemetry::SDK::Trace::Export::BatchSpanProcessor.new(exporter)
+ end
+ def initalize_tracer
+ resource = OpenTelemetry::SDK::Resources::Resource.create(create_resource_attributes)
+ exporter = create_exporter
+ span_processor = create_span_processor(exporter)
+ # TODO: Extra resource Attributes From Config
+ configure_instrumentation span_processor, resource
configure_propagators
end
+ def configure_instrumentation span_processor, resource
+ OpenTelemetry::SDK.configure do |c|
+ c.add_span_processor span_processor if span_processor
+ c.resource = resource if resource
+
+ SUPPORTED_INSTRUMENTATIONS.each do |instrumentation_string|
+ c.use instrumentation_string
+ additional_patches = SUPPORTED_INSTRUMENTATIONS_ADDITIONAL_PATCH[instrumentation_string]
+ if additional_patches
+ additional_patches.each do |patch_file|
+ apply_custom_patch patch_file
+ end
+ end
+ end
+ end
+ end
+
private
+ def create_resource_customized_exporter resource
+ exporter = nil
+ if config.reporting.trace_reporter_type == :OTLP
+ verify_mode = config.reporting.secure.value ? OpenSSL::SSL::VERIFY_PEER : OpenSSL::SSL::VERIFY_NONE
+ exporter = Hypertrace::OtlpHttpExporter.new(endpoint: config.reporting.endpoint.value,
+ ssl_verify_mode: verify_mode,
+ is_hypertrace: true,
+ supported_instrumentation_libraries: SUPPORTED_INSTRUMENTATIONS,
+ custom_resource: resource)
+ return exporter
+ end
+ log.error "Resource customized exporter not supported for zipkin, only OTLP HTTP"
+ end
+
def create_exporter
exporter = nil
if config.reporting.trace_reporter_type == :OTLP
verify_mode = config.reporting.secure.value ? OpenSSL::SSL::VERIFY_PEER : OpenSSL::SSL::VERIFY_NONE
exporter = OpenTelemetry::Exporter::OTLP::Exporter.new(endpoint: config.reporting.endpoint.value,
@@ -121,23 +172,23 @@
elsif format[0] == :B3
propagator_list << OpenTelemetry::Propagator::B3::Single.text_map_propagator
end
end
if propagator_list.empty?
- log.warn{"No propagators were added!"}
+ log.warn { "No propagators were added!" }
end
OpenTelemetry.propagation = OpenTelemetry::Context::Propagation::CompositeTextMapPropagator.compose_propagators(propagator_list.compact)
end
private
def apply_custom_patch file
begin
require_relative file
- log.debug{"Applied patch for #{file}"}
+ log.debug { "Applied patch for #{file}" }
rescue => _e
- log.debug{"Unable to apply patch for #{file} this is most likely because the library is unavailable or an unsupported version"}
+ log.debug { "Unable to apply patch for #{file} this is most likely because the library is unavailable or an unsupported version" }
end
end
def create_resource_attributes
{
@@ -145,13 +196,7 @@
'service.instance.id': Process.pid,
'telemetry.sdk.version': @version,
'telemetry.sdk.name': 'hypertrace',
'telemetry.sdk.language': 'ruby'
}.transform_keys(&:to_s)
- end
-
- NULL_LOGGER = Logger.new(File::NULL)
-
- def configure_otel_logger!
- OpenTelemetry.logger = NULL_LOGGER
end
end
\ No newline at end of file