epsagon 0.0.21 → 0.0.26

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: b7a18ec8c4ad1cd7289a04041151c24e82c839376a44c7d628549cddb2e584c2
4
- data.tar.gz: 9e60dfed6adc951a30265c89aefa7d019010fa68aea423179d4cc9192ce19637
3
+ metadata.gz: 8c6a213fb12b5ded33f1d938b306f56f6de61936197c10be80d53b11258483c1
4
+ data.tar.gz: 34890a4a25d8bf528dc442b975504d1e70b177a09a7868b56538a9b6b112f3d0
5
5
  SHA512:
6
- metadata.gz: c36e3d946ad119367f51d148e7838bc4c1bec512c06171695721d2bdc65e4a6965ffb9cfe68efbe6b7a9a8df350fe4178734b6caa89c7b8db193dc90d6a04ba3
7
- data.tar.gz: 2f143dc5ca8786bfbe883ff6ae75bb5ac382236668cb90b8935a519481a0f010b31f596a28deff807a0f156ea61db9e9fb92047901d1b5795c0a66a0db190d13
6
+ metadata.gz: b0ba4c84e5db6f25b6f68c7c31cbd8c694098ac8542c893735955328a18b58f5b49b436dab779dcac6759f246394c8152e0c3ef8791e4169a4abcf2f73e831e0
7
+ data.tar.gz: 95f6e44d44be2917c1a6cb9b224c838a1b46aa0866fe991c5aa8e0ebf6cbd9703f71ede6d871c7eaebbd499d391c19bd8d887ee25a637c581628362e2fa7442d
data/lib/epsagon.rb CHANGED
@@ -1,10 +1,11 @@
1
1
  # frozen_string_literal: true
2
-
2
+ require 'json'
3
3
  require 'rubygems'
4
4
  require 'net/http'
5
5
  require 'bundler/setup'
6
6
  require 'opentelemetry/sdk'
7
7
  require 'opentelemetry/exporter/otlp'
8
+ require 'opentelemetry/instrumentation/sidekiq'
8
9
 
9
10
  require_relative 'instrumentation/sinatra'
10
11
  require_relative 'instrumentation/net_http'
@@ -13,26 +14,29 @@ require_relative 'instrumentation/aws_sdk'
13
14
  require_relative 'instrumentation/rails'
14
15
  require_relative 'util'
15
16
  require_relative 'epsagon_constants'
17
+ require_relative 'exporter_extension'
16
18
 
17
19
  Bundler.require
18
20
 
19
21
  # Epsagon tracing main entry point
20
22
  module Epsagon
21
-
22
23
  DEFAULT_BACKEND = 'opentelemetry.tc.epsagon.com:443/traces'
24
+ DEFAULT_IGNORE_DOMAINS = ['newrelic.com']
23
25
 
24
- @@epsagon_config = {
25
- metadata_only: ENV['EPSAGON_METADATA']&.to_s&.downcase != 'false',
26
- debug: ENV['EPSAGON_DEBUG']&.to_s&.downcase == 'true',
27
- token: ENV['EPSAGON_TOKEN'],
28
- app_name: ENV['EPSAGON_APP_NAME'],
29
- max_attribute_size: ENV['EPSAGON_MAX_ATTRIBUTE_SIZE'] || 5000,
30
- backend: ENV['EPSAGON_BACKEND'] || DEFAULT_BACKEND
31
- }
26
+ @@epsagon_config = {}
32
27
 
33
28
  module_function
34
29
 
35
30
  def init(**args)
31
+ @@epsagon_config = {
32
+ metadata_only: ENV['EPSAGON_METADATA']&.to_s&.downcase != 'false',
33
+ debug: ENV['EPSAGON_DEBUG']&.to_s&.downcase == 'true',
34
+ token: ENV['EPSAGON_TOKEN'] || '',
35
+ app_name: ENV['EPSAGON_APP_NAME'] || '',
36
+ max_attribute_size: ENV['EPSAGON_MAX_ATTRIBUTE_SIZE'] || 5000,
37
+ backend: ENV['EPSAGON_BACKEND'] || DEFAULT_BACKEND,
38
+ ignore_domains: ENV['EPSAGON_IGNORE_DOMAINS'] || DEFAULT_IGNORE_DOMAINS
39
+ }
36
40
  @@epsagon_config.merge!(args)
37
41
  OpenTelemetry::SDK.configure
38
42
  end
@@ -45,9 +49,10 @@ module Epsagon
45
49
 
46
50
  def epsagon_confs(configurator)
47
51
  configurator.resource = OpenTelemetry::SDK::Resources::Resource.telemetry_sdk.merge(
48
- OpenTelemetry::SDK::Resources::Resource.create({
52
+ OpenTelemetry::SDK::Resources::Resource.create({
49
53
  'application' => @@epsagon_config[:app_name],
50
- 'epsagon.version' => EpsagonConstants::VERSION
54
+ 'epsagon.version' => EpsagonConstants::VERSION,
55
+ 'epsagon.metadata_only' => @@epsagon_config[:metadata_only]
51
56
  })
52
57
  )
53
58
  configurator.use 'EpsagonSinatraInstrumentation', { epsagon: @@epsagon_config }
@@ -55,8 +60,7 @@ module Epsagon
55
60
  configurator.use 'EpsagonFaradayInstrumentation', { epsagon: @@epsagon_config }
56
61
  configurator.use 'EpsagonAwsSdkInstrumentation', { epsagon: @@epsagon_config }
57
62
  configurator.use 'EpsagonRailsInstrumentation', { epsagon: @@epsagon_config }
58
- configurator.use 'OpenTelemetry::Instrumentation::Sidekiq'
59
-
63
+ configurator.use 'OpenTelemetry::Instrumentation::Sidekiq', { epsagon: @@epsagon_config }
60
64
 
61
65
  if @@epsagon_config[:debug]
62
66
  configurator.add_span_processor OpenTelemetry::SDK::Trace::Export::SimpleSpanProcessor.new(
@@ -97,15 +101,89 @@ module SpanExtension
97
101
  def initialize(*args)
98
102
  super(*args)
99
103
  if @attributes
100
- @attributes = Hash[@attributes.map { |k,v|
104
+ @attributes = Hash[@attributes.select {|k,v| not BLANKS.include? v}.map { |k,v|
101
105
  [k, Util.trim_attr(v, Epsagon.get_config[:max_attribute_size])]
102
106
  }]
103
107
  end
104
-
108
+ end
109
+ end
110
+
111
+ module SidekiqClientMiddlewareExtension
112
+ def call(_worker_class, job, _queue, _redis_pool)
113
+ config = OpenTelemetry::Instrumentation::Sidekiq::Instrumentation.instance.config[:epsagon] || {}
114
+ attributes = {
115
+ 'operation' => job['at'] ? 'perform_at' : 'perform_async',
116
+ 'messaging.system' => 'sidekiq',
117
+ 'messaging.sidekiq.job_class' => job['wrapped']&.to_s || job['class'],
118
+ 'messaging.message_id' => job['jid'],
119
+ 'messaging.destination' => job['queue'],
120
+ 'messaging.destination_kind' => 'queue',
121
+ 'messaging.sidekiq.redis_url' => Sidekiq.options['url'] || Util.redis_default_url
122
+ }
123
+ unless config[:metadata_only]
124
+ attributes.merge!({
125
+ 'messaging.sidekiq.args' => JSON.dump(job['args'])
126
+ })
127
+ end
128
+ tracer.in_span(
129
+ job['queue'],
130
+ attributes: attributes,
131
+ kind: :producer
132
+ ) do |span|
133
+ OpenTelemetry.propagation.text.inject(job)
134
+ span.add_event('created_at', timestamp: job['created_at'])
135
+ Util.untraced {yield}
136
+ end
137
+ end
138
+ end
139
+
140
+ module SidekiqServerMiddlewareExtension
141
+ def call(_worker, msg, _queue)
142
+ inner_exception = nil
143
+ config = OpenTelemetry::Instrumentation::Sidekiq::Instrumentation.instance.config[:epsagon] || {}
144
+ parent_context = OpenTelemetry.propagation.text.extract(msg)
145
+ attributes = {
146
+ 'operation' => 'perform',
147
+ 'messaging.system' => 'sidekiq',
148
+ 'messaging.sidekiq.job_class' => msg['wrapped']&.to_s || msg['class'],
149
+ 'messaging.message_id' => msg['jid'],
150
+ 'messaging.destination' => msg['queue'],
151
+ 'messaging.destination_kind' => 'queue',
152
+ 'messaging.sidekiq.redis_url' => Sidekiq.options['url'] || Util.redis_default_url
153
+ }
154
+ runner_attributes = {
155
+ 'type' => 'sidekiq_worker',
156
+ 'messaging.sidekiq.redis_url' => Sidekiq.options['url'] || Util.redis_default_url,
157
+
158
+ }
159
+ unless config[:metadata_only]
160
+ attributes.merge!({
161
+ 'messaging.sidekiq.args' => JSON.dump(msg['args'])
162
+ })
163
+ end
164
+ tracer.in_span(
165
+ msg['queue'],
166
+ attributes: attributes,
167
+ with_parent: parent_context,
168
+ kind: :consumer
169
+ ) do |trigger_span|
170
+ trigger_span.add_event('created_at', timestamp: msg['created_at'])
171
+ trigger_span.add_event('enqueued_at', timestamp: msg['enqueued_at'])
172
+ tracer.in_span(msg['wrapped']&.to_s || msg['class'],
173
+ attributes: runner_attributes,
174
+ kind: :consumer
175
+ ) do |runner_span|
176
+ yield
177
+ end
178
+ rescue Exception => e
179
+ inner_exception = e
180
+ end
181
+ raise inner_exception if inner_exception
105
182
  end
106
183
  end
107
184
 
108
185
  # monkey patch to include epsagon confs
186
+
109
187
  module OpenTelemetry
110
188
  # monkey patch inner SDK module
111
189
  module SDK
@@ -122,4 +200,35 @@ module OpenTelemetry
122
200
  end
123
201
  end
124
202
  end
203
+ module Instrumentation
204
+ module Sidekiq
205
+ class Instrumentation
206
+ def add_server_middleware
207
+ ::Sidekiq.configure_server do |config|
208
+ config.server_middleware do |chain|
209
+ chain.add Middlewares::Server::TracerMiddleware
210
+ end
211
+ end
212
+
213
+ if defined?(::Sidekiq::Testing) # rubocop:disable Style/GuardClause
214
+ ::Sidekiq::Testing.server_middleware do |chain|
215
+ chain.add Middlewares::Server::TracerMiddleware
216
+ end
217
+ end
218
+ end
219
+ end
220
+ module Middlewares
221
+ module Client
222
+ class TracerMiddleware
223
+ prepend SidekiqClientMiddlewareExtension
224
+ end
225
+ end
226
+ module Server
227
+ class TracerMiddleware
228
+ prepend SidekiqServerMiddlewareExtension
229
+ end
230
+ end
231
+ end
232
+ end
233
+ end
125
234
  end
@@ -1,3 +1,3 @@
1
1
  module EpsagonConstants
2
- VERSION = '0.0.21'
2
+ VERSION = '0.0.26'
3
3
  end
@@ -0,0 +1,78 @@
1
+
2
+
3
+ module OpenTelemetry
4
+ module Exporter
5
+ module OTLP
6
+ # An OpenTelemetry trace exporter that sends spans over HTTP as Protobuf encoded OTLP ExportTraceServiceRequests.
7
+ class Exporter # rubocop:disable Metrics/ClassLength
8
+ def send_bytes(bytes, timeout:) # rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/MethodLength, Metrics/PerceivedComplexity
9
+ retry_count = 0
10
+ timeout ||= @timeout
11
+ start_time = Time.now
12
+ untraced do # rubocop:disable Metrics/BlockLength
13
+ request = Net::HTTP::Post.new(@path)
14
+ request.body = if @compression == 'gzip'
15
+ request.add_field('Content-Encoding', 'gzip')
16
+ Zlib.gzip(bytes)
17
+ else
18
+ bytes
19
+ end
20
+ request.add_field('Content-Type', 'application/x-protobuf')
21
+ @headers&.each { |key, value| request.add_field(key, value) }
22
+
23
+ remaining_timeout = OpenTelemetry::Common::Utilities.maybe_timeout(timeout, start_time)
24
+ return TIMEOUT if remaining_timeout.zero?
25
+
26
+ @http.open_timeout = remaining_timeout
27
+ @http.read_timeout = remaining_timeout
28
+ @http.write_timeout = remaining_timeout if WRITE_TIMEOUT_SUPPORTED
29
+ @http.start unless @http.started?
30
+ response = measure_request_duration { @http.request(request) }
31
+
32
+ case response
33
+ when Net::HTTPOK
34
+ response.body # Read and discard body
35
+ SUCCESS
36
+ when Net::HTTPServiceUnavailable, Net::HTTPTooManyRequests
37
+ response.body # Read and discard body
38
+ redo if backoff?(retry_after: response['Retry-After'], retry_count: retry_count += 1, reason: response.code)
39
+ FAILURE
40
+ when Net::HTTPRequestTimeOut, Net::HTTPGatewayTimeOut, Net::HTTPBadGateway
41
+ response.body # Read and discard body
42
+ redo if backoff?(retry_count: retry_count += 1, reason: response.code)
43
+ FAILURE
44
+ when Net::HTTPBadRequest, Net::HTTPClientError, Net::HTTPServerError
45
+ # TODO: decode the body as a google.rpc.Status Protobuf-encoded message when https://github.com/open-telemetry/opentelemetry-collector/issues/1357 is fixed.
46
+ response.body # Read and discard body
47
+ FAILURE
48
+ when Net::HTTPRedirection
49
+ @http.finish
50
+ handle_redirect(response['location'])
51
+ redo if backoff?(retry_after: 0, retry_count: retry_count += 1, reason: response.code)
52
+ else
53
+ @http.finish
54
+ FAILURE
55
+ end
56
+ rescue Net::OpenTimeout, Net::ReadTimeout
57
+ puts "Epsagon: timeout while sending trace" if Epsagon.get_config[:debug]
58
+ retry if backoff?(retry_count: retry_count += 1, reason: 'timeout')
59
+ return FAILURE
60
+ ensure
61
+ if Epsagon.get_config[:debug] && response && response.code.to_i >= 400
62
+ puts "Epsagon: Error while sending trace:"
63
+ puts "#{response.code} #{response.class.name} #{response.message}"
64
+ puts "Headers: #{response.to_hash.inspect}"
65
+ puts response.body
66
+ end
67
+ end
68
+ ensure
69
+ # Reset timeouts to defaults for the next call.
70
+ @http.open_timeout = @timeout
71
+ @http.read_timeout = @timeout
72
+ @http.write_timeout = @timeout if WRITE_TIMEOUT_SUPPORTED
73
+ end
74
+ end
75
+ end
76
+ end
77
+ end
78
+
@@ -4,6 +4,7 @@ require 'aws-sdk-core'
4
4
  require 'opentelemetry/common'
5
5
  require 'opentelemetry/sdk'
6
6
 
7
+
7
8
  def untraced(&block)
8
9
  OpenTelemetry::Trace.with_span(OpenTelemetry::Trace::Span.new, &block)
9
10
  end
@@ -17,14 +18,120 @@ end
17
18
 
18
19
  # Generates Spans for all uses of AWS SDK
19
20
  class EpsagonAwsHandler < Seahorse::Client::Handler
21
+ SPAN_KIND = {
22
+ 'ReceiveMessage' => :consumer,
23
+ 'SendMessage' => :producer,
24
+ 'SendMessageBatch' => :producer,
25
+ 'Publish' => :producer,
26
+ }
27
+
20
28
  def call(context)
21
- tracer.in_span('', kind: :client) do |span|
29
+ span_name = ''
30
+ span_kind = :client
31
+ attributes = {
32
+ 'aws.service' => context.client.class.to_s.split('::')[1].downcase,
33
+ 'aws.operation' => context.operation.name
34
+ }
35
+ attributes['aws.region'] = context.client.config.region unless attributes['aws.service'] == 's3'
36
+
37
+ span_kind = SPAN_KIND[attributes['aws.operation']] || span_kind
38
+ if attributes['aws.service'] == 's3'
39
+ attributes['aws.s3.bucket'] = context.params[:bucket]
40
+ span_name = attributes['aws.s3.bucket'] if attributes['aws.s3.bucket']
41
+ attributes['aws.s3.key'] = context.params[:key]
42
+ attributes['aws.s3.copy_source'] = context.params[:copy_source]
43
+ elsif attributes['aws.service'] == 'sqs'
44
+ queue_url = context.params[:queue_url]
45
+ queue_name = queue_url ? queue_url[queue_url.rindex('/')+1..-1] : context.params[:queue_name]
46
+ attributes['aws.sqs.max_number_of_messages'] = context.params[:max_number_of_messages]
47
+ attributes['aws.sqs.wait_time_seconds'] = context.params[:wait_time_seconds]
48
+ attributes['aws.sqs.visibility_timeout'] = context.params[:visibility_timeout]
49
+ attributes['aws.sqs.message_id'] = context.params[:message_id]
50
+ if queue_name
51
+ attributes['aws.sqs.queue_name'] = queue_name
52
+ span_name = attributes['aws.sqs.queue_name'] if attributes['aws.sqs.queue_name']
53
+ end
54
+ unless config[:epsagon][:metadata_only]
55
+ if attributes['aws.operation'] == 'SendMessageBatch'
56
+ messages_attributes = context.params[:entries].map do |m|
57
+ record = {
58
+ 'message_attributes' => m[:message_attributes].map {|k,v| [k, v.to_h]},
59
+ 'message_body' => m[:message_body],
60
+ }
61
+ end
62
+ attributes['aws.sqs.record'] = JSON.dump(messages_attributes) if messages_attributes
63
+ end
64
+ attributes['aws.sqs.record.message_body'] = context.params[:message_body]
65
+ attributes['aws.sqs.record.message_attributes'] = JSON.dump(context.params[:message_attributes]) if context.params[:message_attributes]
66
+ end
67
+ elsif attributes['aws.service'] == 'sns'
68
+ topic_arn = context.params[:topic_arn]
69
+ topic_name = topic_arn ? topic_arn[topic_arn.rindex(':')+1..-1] : context.params[:name]
70
+ span_name = attributes['aws.sns.topic_name'] = topic_name if topic_name
71
+ unless config[:epsagon][:metadata_only]
72
+ attributes['aws.sns.subject'] = context.params[:subject]
73
+ attributes['aws.sns.message'] = context.params[:message]
74
+ attributes['aws.sns.message_attributes'] = JSON.dump(context.params[:message_attributes]) if context.params[:message_attributes]
75
+ end
76
+ end
77
+ tracer.in_span(span_name, kind: span_kind, attributes: attributes) do |span|
22
78
  untraced do
23
- @handler.call(context).tap do
24
- span.set_attribute('aws.service', context.client.class.to_s.split('::')[1].downcase)
25
- span.set_attribute('aws.operation', context.operation.name)
26
- span.set_attribute('aws.region', context.client.config.region)
79
+ @handler.call(context).tap do |result|
80
+ if attributes['aws.service'] == 's3'
81
+ modified = context.http_response.headers[:'last-modified']
82
+ reformatted_modified = modified ?
83
+ Time.strptime(modified, '%a, %d %b %Y %H:%M:%S %Z')
84
+ .strftime('%Y-%m-%dT%H:%M:%SZ') :
85
+ nil
86
+ if context.operation.name == 'GetObject'
87
+ span.set_attribute('aws.s3.content_length', context.http_response.headers[:'content-length']&.to_i)
88
+ end
89
+ span.set_attribute('aws.s3.etag', context.http_response.headers[:etag]&.tr('"',''))
90
+ span.set_attribute('aws.s3.last_modified', reformatted_modified)
91
+ elsif attributes['aws.service'] == 'sqs'
92
+ if context.operation.name == 'SendMessage'
93
+ span.set_attribute('aws.sqs.record.message_id', result.message_id)
94
+ end
95
+ if context.operation.name == 'SendMessageBatch'
96
+ messages_attributes = result.successful.map do |m|
97
+ record = {'message_id' => m.message_id}
98
+ unless config[:epsagon][:metadata_only]
99
+ context.params[:entries].each do |e|
100
+ record.merge!({
101
+ 'message_attributes' => e[:message_attributes].map {|k,v| [k, v.to_h]},
102
+ 'message_body' => e[:message_body],
103
+ }) if e[:id] == m.id
104
+ end
105
+ end
106
+ record
107
+ end
108
+ span.set_attribute('aws.sqs.record', JSON.dump(messages_attributes)) if messages_attributes
109
+ end
110
+ if context.operation.name == 'ReceiveMessage'
111
+ messages_attributes = result.messages.map do |m|
112
+ record = {
113
+ 'message_id' => m.message_id,
114
+ 'attributes' => {
115
+ 'sender_id' => m.attributes['SenderId'],
116
+ 'sent_timestamp' => m.attributes['SentTimestamp'],
117
+ 'aws_trace_header' => m.attributes['AWSTraceHeader'],
118
+ }
119
+ }
120
+ unless config[:epsagon][:metadata_only]
121
+ record['message_attributes'] = m.message_attributes.map {|k,v| [k, v.to_h]}
122
+ record['message_body'] = m.body
123
+ end
124
+ record
125
+ end
126
+ span.set_attribute('aws.sqs.record', JSON.dump(messages_attributes)) if messages_attributes
127
+ end
128
+ elsif attributes['aws.service'] == 'sns'
129
+ span.set_attribute('aws.sns.message_id', result.message_id) if context.operation.name == 'Publish'
130
+ end
27
131
  span.set_attribute('http.status_code', context.http_response.status_code)
132
+ span.status = OpenTelemetry::Trace::Status.http_to_status(
133
+ context.http_response.status_code
134
+ )
28
135
  end
29
136
  end
30
137
  end
@@ -33,4 +140,8 @@ class EpsagonAwsHandler < Seahorse::Client::Handler
33
140
  def tracer
34
141
  EpsagonAwsSdkInstrumentation.instance.tracer()
35
142
  end
143
+
144
+ def config
145
+ EpsagonAwsSdkInstrumentation.instance.config
146
+ end
36
147
  end
@@ -37,11 +37,11 @@ class EpsagonFaradayMiddleware < ::Faraday::Middleware
37
37
  unless config[:epsagon][:metadata_only]
38
38
  attributes.merge!(Util.epsagon_query_attributes(env.url.query))
39
39
  attributes.merge!({
40
- 'http.request.path_params' => path_params,
41
- 'http.request.headers' => env.request_headers.to_json,
42
- 'http.request.body' => env.body,
43
- 'http.request.headers.User-Agent' => env.request_headers['User-Agent']
44
- })
40
+ 'http.request.path_params' => path_params,
41
+ 'http.request.headers' => env.request_headers.to_json,
42
+ 'http.request.body' => env.body,
43
+ 'http.request.headers.User-Agent' => env.request_headers['User-Agent']
44
+ })
45
45
  end
46
46
 
47
47
  tracer.in_span(
@@ -130,7 +130,7 @@ class EpsagonRackMiddleware
130
130
  def request_span_attributes(env:)
131
131
  request = Rack::Request.new(env)
132
132
  path, path_params = request.path.split(';')
133
- request_headers = JSON.generate(Hash[*env.select { |k, _v| k.start_with? 'HTTP_' }
133
+ request_headers = JSON.generate(Hash[*env.select { |k, _v| k.to_s.start_with? 'HTTP_' }
134
134
  .collect { |k, v| [k.sub(/^HTTP_/, ''), v] }
135
135
  .collect { |k, v| [k.split('_').collect(&:capitalize).join('-'), v] }
136
136
  .sort
@@ -17,6 +17,7 @@ module EpsagonNetHTTPExtension
17
17
  def request(req, body = nil, &block)
18
18
  # Do not trace recursive call for starting the connection
19
19
  return super(req, body, &block) unless started?
20
+ return super(req, body, &block) if config[:epsagon][:ignore_domains].any? {|d| @address.include? d}
20
21
 
21
22
  attributes = Hash[OpenTelemetry::Common::HTTP::ClientContext.attributes]
22
23
  path_with_params, query = req.path.split('?')
@@ -55,6 +56,7 @@ module EpsagonNetHTTPExtension
55
56
 
56
57
  def annotate_span_with_response!(span, response)
57
58
  return unless response&.code
59
+ return unless span.respond_to?(:set_attribute)
58
60
 
59
61
  status_code = response.code.to_i
60
62
 
File without changes
data/lib/util.rb CHANGED
@@ -30,4 +30,13 @@ module Util
30
30
  value
31
31
  end
32
32
  end
33
+
34
+ def self.redis_default_url
35
+ @@redis_default_url ||= "#{Redis::Client::DEFAULTS[:scheme]}://#{Redis::Client::DEFAULTS[:host]}:#{Redis::Client::DEFAULTS[:port]}/#{Redis::Client::DEFAULTS[:db]}"
36
+ end
37
+
38
+ def self.untraced(&block)
39
+ OpenTelemetry::Trace.with_span(OpenTelemetry::Trace::Span.new, &block)
40
+ end
41
+
33
42
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: epsagon
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.21
4
+ version: 0.0.26
5
5
  platform: ruby
6
6
  authors:
7
7
  - Epsagon
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2021-04-29 00:00:00.000000000 Z
11
+ date: 2021-06-01 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: opentelemetry-api
@@ -92,6 +92,7 @@ extra_rdoc_files: []
92
92
  files:
93
93
  - lib/epsagon.rb
94
94
  - lib/epsagon_constants.rb
95
+ - lib/exporter_extension.rb
95
96
  - lib/instrumentation/aws_sdk.rb
96
97
  - lib/instrumentation/aws_sdk_plugin.rb
97
98
  - lib/instrumentation/epsagon_faraday_middleware.rb
@@ -100,6 +101,7 @@ files:
100
101
  - lib/instrumentation/net_http.rb
101
102
  - lib/instrumentation/rails.rb
102
103
  - lib/instrumentation/sinatra.rb
104
+ - lib/instrumentation/version.rb
103
105
  - lib/util.rb
104
106
  homepage: https://github.com/epsagon/epsagon-ruby
105
107
  licenses: