hypertrace-agent 0.2.2 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: d22bcf228d92b8f9d0b2f15859d8fe3ad2682ad81254c71a41cc766752ea03e8
4
- data.tar.gz: 101e6f0dab77ab8baf63ea6682dd7d93b5336ca0f84525ddb36ee053a5525b07
3
+ metadata.gz: 5f6326f5fd71561a9650dd5c9ad8098a9da9cf8d1632d86a4a708f4ef53d0c0d
4
+ data.tar.gz: 5e97a94ab436dfcf90a0f5d2c6b835fc4b5700798b0ce697a1ecc8d8a6ac3c4b
5
5
  SHA512:
6
- metadata.gz: 57b075dc324c1fe9c374b268ae365fda2480afcb4651dac118ddc26f9eafa8c3495444fdcee4d0e7462589269710672640ce7c6eac0a3bf790845752b5e9e40c
7
- data.tar.gz: 044dd0ec7a3bf16737b31c9b7fbd3d8d38c791c2e404d785404d143b7be13e24316fd1525f848b1aa55d8fd4f051753cd9e6af99ead448535d2e94d183896c72
6
+ metadata.gz: 042e6e70677f70145a1f6acd60e59af6f560a0f1b496fd04833b0015ca0204b95a00d168d0a051207629cafc5843b3ae22fa54d0ab15a9fdf5d0b88c1e420c84
7
+ data.tar.gz: 0ac7871f61b712e9a85cb77e4bda7654bf7419b0444fcb17ecd180f8da58869ff941832556ae85b5d07861f34afb8b8477396330a53afbd2350af4f5a94e2461
@@ -0,0 +1,118 @@
1
+ require 'opentelemetry/sdk'
2
+ require 'opentelemetry/exporter/otlp'
3
+ require 'opentelemetry/exporter/otlp/exporter'
4
+
5
+ class Hypertrace::OtlpHttpExporter < OpenTelemetry::Exporter::OTLP::Exporter
6
+
7
+ def initialize(endpoint: config_opt('OTEL_EXPORTER_OTLP_TRACES_ENDPOINT', 'OTEL_EXPORTER_OTLP_ENDPOINT', default: 'https://localhost:4318/v1/traces'), # rubocop:disable Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
8
+ certificate_file: config_opt('OTEL_EXPORTER_OTLP_TRACES_CERTIFICATE', 'OTEL_EXPORTER_OTLP_CERTIFICATE'),
9
+ ssl_verify_mode: self.class.ssl_verify_mode,
10
+ headers: config_opt('OTEL_EXPORTER_OTLP_TRACES_HEADERS', 'OTEL_EXPORTER_OTLP_HEADERS', default: {}),
11
+ compression: config_opt('OTEL_EXPORTER_OTLP_TRACES_COMPRESSION', 'OTEL_EXPORTER_OTLP_COMPRESSION', default: 'gzip'),
12
+ timeout: config_opt('OTEL_EXPORTER_OTLP_TRACES_TIMEOUT', 'OTEL_EXPORTER_OTLP_TIMEOUT', default: 10),
13
+ metrics_reporter: nil,
14
+ allowed_request_headers: [],
15
+ allowed_response_headers: [],
16
+ drop_attributes: [],
17
+ supported_instrumentation_libraries: [],
18
+ use_all: false,
19
+ is_hypertrace: false,
20
+ custom_resource: nil
21
+
22
+ )
23
+
24
+ super(
25
+ endpoint: endpoint,
26
+ certificate_file: certificate_file,
27
+ ssl_verify_mode: ssl_verify_mode,
28
+ headers: headers,
29
+ compression: compression,
30
+ timeout: timeout,
31
+ metrics_reporter: metrics_reporter
32
+ )
33
+
34
+ # If a user specifies use_all that means we need to keep all spans
35
+ # If a user specifies supported libraries that means we should drop spans that aren't from those libraries
36
+ if use_all && supported_instrumentation_libraries.length > 0
37
+ raise ArgumentError.new("Must use either use_all or supported_instrumentation_libraries, cannot specify both")
38
+ end
39
+
40
+ # if passed is_hypertrace all spans + attributes will be kept, we should be the only one passing this
41
+ @is_hypertrace = is_hypertrace
42
+ # List of request headers to allow, not used by hypertrace
43
+ @allowed_request_headers = []
44
+ # List of response headers to allow, not used by hypertrace
45
+ @allowed_response_headers = []
46
+ allowed_request_headers.each do |req_header|
47
+ @allowed_request_headers << "http.request.header.#{req_header}"
48
+ end
49
+ allowed_response_headers.each do |res_header|
50
+ @allowed_response_headers << "http.response.header.#{res_header}"
51
+ end
52
+ # List of instrumentation libraries to report for this exporter
53
+ @supported_instrumentation_libraries = supported_instrumentation_libraries
54
+ # If c.use_all is used to configure OTEL sdk this option should be used
55
+ # We won't drop any spans based on Instrumentation library
56
+ @use_all = use_all
57
+ # List of attributes to always drop
58
+ @drop_attributes = drop_attributes
59
+ # An override resource object to override default configured resource
60
+ @custom_resource = custom_resource
61
+ end
62
+
63
+ def export(span_data, timeout: nil)
64
+ # Drop spans if not from a supported library
65
+ span_data = drop_extra_spans(span_data)
66
+ # Remove any attributes that shouldn't be reported
67
+ span_data = drop_attributes(span_data)
68
+ # Override the default configured resource - only used by Hypertrace
69
+ span_data = customize_resource(span_data)
70
+ super
71
+ end
72
+
73
+ def drop_extra_spans(span_data)
74
+ return span_data if @use_all
75
+ filtered_spans = span_data.select do |span|
76
+ name = span.instrumentation_library.name
77
+ # If a user uses a manually created span we should keep it, ex: instrumentation_library.name = "My-tracer"
78
+ # If a user is using an OTel Library the value will be like: OpenTelemetry::Instrumentation::Rack
79
+ !name.include?("OpenTelemetry") || @supported_instrumentation_libraries.include?(name)
80
+ end
81
+ filtered_spans
82
+ end
83
+
84
+ def drop_attributes span_data
85
+ return span_data if @is_hypertrace
86
+ span_data.each do |span|
87
+ new_attributes = {}
88
+
89
+ span[:attributes].each do |key, value|
90
+ if @drop_attributes.include?(key)
91
+ next
92
+ elsif key.start_with?('http.request.header.')
93
+ if @allowed_request_headers.include?(key)
94
+ new_attributes[key] = value
95
+ end
96
+ next
97
+ elsif key.start_with?('http.response.header.')
98
+ if @allowed_response_headers.include?(key)
99
+ new_attributes[key] = value
100
+ end
101
+ next
102
+ else
103
+ new_attributes[key] = value
104
+ end
105
+ end
106
+ span[:attributes] = new_attributes
107
+ end
108
+ span_data
109
+ end
110
+
111
+ def customize_resource span_data
112
+ return span_data unless @custom_resource
113
+ span_data.each do |span|
114
+ span.resource = @custom_resource
115
+ end
116
+ span_data
117
+ end
118
+ end
@@ -32,21 +32,48 @@ class Hypertrace::RubyAgent
32
32
  include Hypertrace::Logging
33
33
  include Singleton
34
34
 
35
+ SUPPORTED_INSTRUMENTATIONS = [
36
+ 'OpenTelemetry::Instrumentation::ActionPack',
37
+ 'OpenTelemetry::Instrumentation::ActionView',
38
+ 'OpenTelemetry::Instrumentation::ActiveRecord',
39
+ 'OpenTelemetry::Instrumentation::ActiveSupport',
40
+ 'OpenTelemetry::Instrumentation::Faraday',
41
+ 'OpenTelemetry::Instrumentation::Mongo',
42
+ 'OpenTelemetry::Instrumentation::Mysql2',
43
+ 'OpenTelemetry::Instrumentation::PG',
44
+ 'OpenTelemetry::Instrumentation::Rack',
45
+ 'OpenTelemetry::Instrumentation::Sinatra',
46
+ 'OpenTelemetry::Instrumentation::Net::HTTP',
47
+ 'OpenTelemetry::Instrumentation::HTTP',
48
+ 'OpenTelemetry::Instrumentation::RestClient'
49
+ ].freeze
50
+
51
+ SUPPORTED_INSTRUMENTATIONS_ADDITIONAL_PATCH = {
52
+ 'OpenTelemetry::Instrumentation::Faraday' => ['./instrumentation/faraday_patch'],
53
+ 'OpenTelemetry::Instrumentation::Rack' => ['./instrumentation/rack', './instrumentation/rack_env_getter'],
54
+ 'OpenTelemetry::Instrumentation::Net::HTTP' => ['./instrumentation/net_http_patch'],
55
+ 'OpenTelemetry::Instrumentation::HTTP' => ['./instrumentation/http_patch'],
56
+ 'OpenTelemetry::Instrumentation::RestClient' => ['./instrumentation/rest_client_patch'],
57
+ }
58
+
35
59
  def self.instrument!
36
60
  self.instance.instrument!
37
61
  end
38
62
 
63
+ def self.instrument_as_additional!
64
+ self.instance.instrument_as_additional!
65
+ end
66
+
39
67
  def self.config
40
68
  self.instance.config
41
69
  end
42
70
 
43
71
  def initialize(version = Hypertrace::VERSION)
44
- log.info {"Initializing Hypertrace"}
45
- configure_otel_logger!
72
+ log.info { "Initializing Hypertrace" }
46
73
  @config = Hypertrace::Config::Config.new
47
74
  @version = version
48
- log.info {"Hypertrace version: #{Hypertrace::VERSION}"}
49
- log.info {"Ruby version: #{RUBY_VERSION}"}
75
+ log.info { "Hypertrace version: #{Hypertrace::VERSION}" }
76
+ log.info { "Ruby version: #{RUBY_VERSION}" }
50
77
  end
51
78
 
52
79
  def config
@@ -57,47 +84,71 @@ class Hypertrace::RubyAgent
57
84
  initalize_tracer
58
85
  end
59
86
 
60
- def initalize_tracer
87
+ def instrument_as_additional!
61
88
  resource = OpenTelemetry::SDK::Resources::Resource.create(create_resource_attributes)
89
+ exporter = create_resource_customized_exporter resource
90
+ span_processor = create_span_processor exporter
62
91
 
63
- # TODO: Extra resource Attributes From Config
64
- exporter = create_exporter
65
- OpenTelemetry::SDK.configure do |c|
66
- if ENV['HT_CI_TEST'] != nil
67
- span_processor = OpenTelemetry::SDK::Trace::Export::SimpleSpanProcessor.new(EXPORTER)
68
- c.add_span_processor span_processor
69
- else
70
- c.add_span_processor OpenTelemetry::SDK::Trace::Export::BatchSpanProcessor.new(exporter)
71
- end
72
- c.resource = resource
73
-
74
- c.use 'OpenTelemetry::Instrumentation::ActionPack'
75
- c.use 'OpenTelemetry::Instrumentation::ActionView'
76
- c.use 'OpenTelemetry::Instrumentation::ActiveRecord'
77
- c.use 'OpenTelemetry::Instrumentation::ActiveSupport'
78
- c.use 'OpenTelemetry::Instrumentation::Faraday'
79
- c.use 'OpenTelemetry::Instrumentation::Mongo'
80
- c.use 'OpenTelemetry::Instrumentation::Mysql2'
81
- c.use 'OpenTelemetry::Instrumentation::PG'
82
- c.use 'OpenTelemetry::Instrumentation::Rack'
83
- c.use 'OpenTelemetry::Instrumentation::Sinatra'
84
- c.use 'OpenTelemetry::Instrumentation::Net::HTTP'
85
- c.use 'OpenTelemetry::Instrumentation::HTTP'
86
- c.use 'OpenTelemetry::Instrumentation::RestClient'
92
+ existing_processors = OpenTelemetry.tracer_provider.instance_variable_get(:"@span_processors")
93
+ if existing_processors.nil? || existing_processors&.empty?
94
+ log.error("No existing tracer_provider found, continuing without Hypertrace instrumentation")
95
+ return
87
96
  end
97
+ existing_processors << span_processor
98
+ OpenTelemetry.tracer_provider.instance_variable_set(:'@span_processors', existing_processors)
99
+ # We don't pass a span_processor or resource because we have to add it to the already configured tracer provider
100
+ # The resource will be added at the export phase
101
+ configure_instrumentation nil, nil
102
+ configure_propagators
103
+ end
88
104
 
89
- apply_custom_patch './instrumentation/rack'
90
- apply_custom_patch './instrumentation/net_http_patch'
91
- apply_custom_patch './instrumentation/http_patch'
92
- apply_custom_patch './instrumentation/faraday_patch'
93
- apply_custom_patch './instrumentation/rest_client_patch'
94
- apply_custom_patch './instrumentation/rack_env_getter'
105
+ def create_span_processor exporter
106
+ return OpenTelemetry::SDK::Trace::Export::SimpleSpanProcessor.new(EXPORTER) if ENV['HT_CI_TEST'] != nil
107
+ return OpenTelemetry::SDK::Trace::Export::BatchSpanProcessor.new(exporter)
108
+ end
95
109
 
110
+ def initalize_tracer
111
+ resource = OpenTelemetry::SDK::Resources::Resource.create(create_resource_attributes)
112
+ exporter = create_exporter
113
+ span_processor = create_span_processor(exporter)
114
+ # TODO: Extra resource Attributes From Config
115
+ configure_instrumentation span_processor, resource
96
116
  configure_propagators
97
117
  end
98
118
 
119
+ def configure_instrumentation span_processor, resource
120
+ OpenTelemetry::SDK.configure do |c|
121
+ c.add_span_processor span_processor if span_processor
122
+ c.resource = resource if resource
123
+
124
+ SUPPORTED_INSTRUMENTATIONS.each do |instrumentation_string|
125
+ c.use instrumentation_string
126
+ additional_patches = SUPPORTED_INSTRUMENTATIONS_ADDITIONAL_PATCH[instrumentation_string]
127
+ if additional_patches
128
+ additional_patches.each do |patch_file|
129
+ apply_custom_patch patch_file
130
+ end
131
+ end
132
+ end
133
+ end
134
+ end
135
+
99
136
  private
100
137
 
138
+ def create_resource_customized_exporter resource
139
+ exporter = nil
140
+ if config.reporting.trace_reporter_type == :OTLP
141
+ verify_mode = config.reporting.secure.value ? OpenSSL::SSL::VERIFY_PEER : OpenSSL::SSL::VERIFY_NONE
142
+ exporter = Hypertrace::OtlpHttpExporter.new(endpoint: config.reporting.endpoint.value,
143
+ ssl_verify_mode: verify_mode,
144
+ is_hypertrace: true,
145
+ supported_instrumentation_libraries: SUPPORTED_INSTRUMENTATIONS,
146
+ custom_resource: resource)
147
+ return exporter
148
+ end
149
+ log.error "Resource customized exporter not supported for zipkin, only OTLP HTTP"
150
+ end
151
+
101
152
  def create_exporter
102
153
  exporter = nil
103
154
  if config.reporting.trace_reporter_type == :OTLP
@@ -123,7 +174,7 @@ class Hypertrace::RubyAgent
123
174
  end
124
175
  end
125
176
  if propagator_list.empty?
126
- log.warn{"No propagators were added!"}
177
+ log.warn { "No propagators were added!" }
127
178
  end
128
179
  OpenTelemetry.propagation = OpenTelemetry::Context::Propagation::CompositeTextMapPropagator.compose_propagators(propagator_list.compact)
129
180
  end
@@ -133,9 +184,9 @@ class Hypertrace::RubyAgent
133
184
  def apply_custom_patch file
134
185
  begin
135
186
  require_relative file
136
- log.debug{"Applied patch for #{file}"}
187
+ log.debug { "Applied patch for #{file}" }
137
188
  rescue => _e
138
- log.debug{"Unable to apply patch for #{file} this is most likely because the library is unavailable or an unsupported version"}
189
+ log.debug { "Unable to apply patch for #{file} this is most likely because the library is unavailable or an unsupported version" }
139
190
  end
140
191
  end
141
192
 
@@ -148,10 +199,4 @@ class Hypertrace::RubyAgent
148
199
  'telemetry.sdk.language': 'ruby'
149
200
  }.transform_keys(&:to_s)
150
201
  end
151
-
152
- NULL_LOGGER = Logger.new(File::NULL)
153
-
154
- def configure_otel_logger!
155
- OpenTelemetry.logger = NULL_LOGGER
156
- end
157
202
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Hypertrace
4
- VERSION = "0.2.2"
4
+ VERSION = "0.3.0"
5
5
  end
data/lib/hypertrace.rb CHANGED
@@ -8,6 +8,5 @@ require_relative './hypertrace/version'
8
8
  require_relative './hypertrace/env_var_settings'
9
9
  require_relative './hypertrace/logging'
10
10
  require_relative './hypertrace/config'
11
+ require_relative './hypertrace/otlp_http_exporter'
11
12
  require_relative './hypertrace/ruby_agent'
12
-
13
-
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: hypertrace-agent
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.2
4
+ version: 0.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - prodion23
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2024-05-30 00:00:00.000000000 Z
11
+ date: 2024-06-13 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: google-protobuf
@@ -257,6 +257,7 @@ files:
257
257
  - lib/hypertrace/instrumentation/rest_client_patch.rb
258
258
  - lib/hypertrace/instrumentation/sinatra.rb
259
259
  - lib/hypertrace/logging.rb
260
+ - lib/hypertrace/otlp_http_exporter.rb
260
261
  - lib/hypertrace/ruby_agent.rb
261
262
  - lib/hypertrace/version.rb
262
263
  - release.sh