hypertrace-agent 0.2.2 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
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