epsagon 0.0.28 → 0.0.29
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 +4 -4
- data/lib/epsagon.rb +36 -16
- data/lib/epsagon_constants.rb +1 -1
- data/lib/instrumentation/aws_sdk.rb +1 -0
- data/lib/instrumentation/epsagon_rails_middleware.rb +46 -0
- data/lib/instrumentation/epsagon_resque_job.rb +113 -0
- data/lib/instrumentation/rails.rb +0 -47
- data/lib/instrumentation/resque.rb +21 -0
- data/lib/util.rb +5 -1
- metadata +9 -7
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 25cf09d9ea5babb3e7caa3380d6b8a78365909391ec3eb84ec150e07fbd9841a
|
4
|
+
data.tar.gz: bb3f2efc49e2b0930ffb677bfb5b8440fa16fe2a41a7adb96b33a35e89efdb67
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: b179e2cf5b65329b6a7a40dec43a379fb294ddee0e58f389cd4ffc105f503265ad655cbf50067a9995b04358ddb9d9d0f8441d47e2639befcc4744c8af3c290c
|
7
|
+
data.tar.gz: 5b8443325b4afadffed3f836ba9a7385cbdfbc2cd03eebfee007bb0543ddb5f2b3c279d22a614fa80ecabb7f4a18f6a1292298567d444a84c9a364ef361bb626
|
data/lib/epsagon.rb
CHANGED
@@ -13,6 +13,7 @@ require_relative 'instrumentation/faraday'
|
|
13
13
|
require_relative 'instrumentation/aws_sdk'
|
14
14
|
require_relative 'instrumentation/rails'
|
15
15
|
require_relative 'instrumentation/postgres'
|
16
|
+
require_relative 'instrumentation/resque'
|
16
17
|
require_relative 'util'
|
17
18
|
require_relative 'epsagon_constants'
|
18
19
|
require_relative 'exporter_extension'
|
@@ -20,10 +21,13 @@ require_relative 'arn_parser'
|
|
20
21
|
|
21
22
|
Bundler.require
|
22
23
|
|
24
|
+
|
23
25
|
# Epsagon tracing main entry point
|
24
26
|
module Epsagon
|
25
27
|
DEFAULT_BACKEND = 'opentelemetry.tc.epsagon.com:443/traces'
|
26
28
|
DEFAULT_IGNORE_DOMAINS = ['newrelic.com'].freeze
|
29
|
+
MUTABLE_CONF_KEYS = Set.new([:metadata_only, :max_attribute_size, :ignore_domains])
|
30
|
+
|
27
31
|
|
28
32
|
@@epsagon_config = nil
|
29
33
|
|
@@ -31,7 +35,29 @@ module Epsagon
|
|
31
35
|
|
32
36
|
def init(**args)
|
33
37
|
get_config.merge!(args)
|
38
|
+
validate(get_config)
|
34
39
|
OpenTelemetry::SDK.configure
|
40
|
+
@@initialized = true
|
41
|
+
end
|
42
|
+
|
43
|
+
def validate(config)
|
44
|
+
Util.validate_value(config, :metadata_only, 'Must be a boolean') {|v| !!v == v}
|
45
|
+
Util.validate_value(config, :debug, 'Must be a boolean') {|v| !!v == v}
|
46
|
+
Util.validate_value(config, :token, 'Must be a valid Epsagon token') {|v| v.is_a? String and v.size > 10}
|
47
|
+
Util.validate_value(config, :app_name, 'Must be a String') {|v| v.is_a? String}
|
48
|
+
Util.validate_value(config, :max_attribute_size, 'Must be an Integer') {|v| v.is_a? Integer}
|
49
|
+
Util.validate_value(config, :ignore_domains, 'Must be iterable') {|v| v.respond_to?(:each)}
|
50
|
+
Util.validate_value(config, :ignore_domains, 'Must be iterable') {|v| v.respond_to?(:each)}
|
51
|
+
end
|
52
|
+
|
53
|
+
def set_config(**args)
|
54
|
+
unless args.keys.all? {|a| MUTABLE_CONF_KEYS.include?(a)}
|
55
|
+
raise ArgumentError("only #{MUTABLE_CONF_KEYS.to_a} are mutable after `Epsagon.init`")
|
56
|
+
end
|
57
|
+
Epsagon.init unless @@initialized
|
58
|
+
new_conf = get_config.merge(args)
|
59
|
+
validate(new_conf)
|
60
|
+
@@epsagon_config = new_conf
|
35
61
|
end
|
36
62
|
|
37
63
|
def get_config
|
@@ -85,28 +111,22 @@ module Epsagon
|
|
85
111
|
configurator.use 'EpsagonRailsInstrumentation', { epsagon: get_config }
|
86
112
|
configurator.use 'OpenTelemetry::Instrumentation::Sidekiq', { epsagon: get_config }
|
87
113
|
configurator.use 'EpsagonPostgresInstrumentation', { epsagon: get_config }
|
114
|
+
configurator.use 'EpsagonResqueInstrumentation', { epsagon: get_config }
|
88
115
|
|
89
|
-
if get_config[:debug]
|
90
|
-
configurator.add_span_processor OpenTelemetry::SDK::Trace::Export::SimpleSpanProcessor.new(
|
91
|
-
OpenTelemetry::Exporter::OTLP::Exporter.new(headers: {
|
92
|
-
'x-epsagon-token' => get_config[:token]
|
93
|
-
},
|
94
|
-
endpoint: get_config[:backend],
|
95
|
-
insecure: get_config[:insecure] || false)
|
96
|
-
)
|
97
116
|
|
117
|
+
if get_config[:debug]
|
98
118
|
configurator.add_span_processor OpenTelemetry::SDK::Trace::Export::SimpleSpanProcessor.new(
|
99
119
|
OpenTelemetry::SDK::Trace::Export::ConsoleSpanExporter.new
|
100
120
|
)
|
101
|
-
else
|
102
|
-
configurator.add_span_processor OpenTelemetry::SDK::Trace::Export::BatchSpanProcessor.new(
|
103
|
-
exporter: OpenTelemetry::Exporter::OTLP::Exporter.new(headers: {
|
104
|
-
'x-epsagon-token' => get_config[:token]
|
105
|
-
},
|
106
|
-
endpoint: get_config[:backend],
|
107
|
-
insecure: get_config[:insecure] || false)
|
108
|
-
)
|
109
121
|
end
|
122
|
+
|
123
|
+
configurator.add_span_processor OpenTelemetry::SDK::Trace::Export::BatchSpanProcessor.new(
|
124
|
+
exporter: OpenTelemetry::Exporter::OTLP::Exporter.new(headers: {
|
125
|
+
'x-epsagon-token' => get_config[:token]
|
126
|
+
},
|
127
|
+
endpoint: get_config[:backend],
|
128
|
+
insecure: get_config[:insecure] || false)
|
129
|
+
)
|
110
130
|
end
|
111
131
|
end
|
112
132
|
|
data/lib/epsagon_constants.rb
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require 'opentelemetry/trace/status'
|
4
|
+
require 'action_controller/railtie'
|
4
5
|
|
5
6
|
module QueueTime
|
6
7
|
REQUEST_START = 'HTTP_X_REQUEST_START'
|
@@ -284,3 +285,48 @@ class EpsagonRailtie < ::Rails::Railtie
|
|
284
285
|
)
|
285
286
|
end
|
286
287
|
end
|
288
|
+
|
289
|
+
module RackExtension
|
290
|
+
module_function
|
291
|
+
|
292
|
+
CURRENT_SPAN_KEY = OpenTelemetry::Context.create_key('current-span')
|
293
|
+
|
294
|
+
private_constant :CURRENT_SPAN_KEY
|
295
|
+
|
296
|
+
# Returns the current span from the current or provided context
|
297
|
+
#
|
298
|
+
# @param [optional Context] context The context to lookup the current
|
299
|
+
# {Span} from. Defaults to Context.current
|
300
|
+
def current_span(context = nil)
|
301
|
+
context ||= OpenTelemetry::Context.current
|
302
|
+
context.value(CURRENT_SPAN_KEY) || OpenTelemetry::Trace::Span::INVALID
|
303
|
+
end
|
304
|
+
|
305
|
+
# Returns a context containing the span, derived from the optional parent
|
306
|
+
# context, or the current context if one was not provided.
|
307
|
+
#
|
308
|
+
# @param [optional Context] context The context to use as the parent for
|
309
|
+
# the returned context
|
310
|
+
def context_with_span(span, parent_context: OpenTelemetry::Context.current)
|
311
|
+
parent_context.set_value(CURRENT_SPAN_KEY, span)
|
312
|
+
end
|
313
|
+
|
314
|
+
# Activates/deactivates the Span within the current Context, which makes the "current span"
|
315
|
+
# available implicitly.
|
316
|
+
#
|
317
|
+
# On exit, the Span that was active before calling this method will be reactivated.
|
318
|
+
#
|
319
|
+
# @param [Span] span the span to activate
|
320
|
+
# @yield [span, context] yields span and a context containing the span to the block.
|
321
|
+
def with_span(span)
|
322
|
+
OpenTelemetry::Context.with_value(CURRENT_SPAN_KEY, span) { |c, s| yield s, c }
|
323
|
+
end
|
324
|
+
end
|
325
|
+
|
326
|
+
module MetalPatch
|
327
|
+
def dispatch(name, request, response)
|
328
|
+
rack_span = RackExtension.current_span
|
329
|
+
# rack_span.name = "#{self.class.name}##{name}" if rack_span.context.valid? && !request.env['action_dispatch.exception']
|
330
|
+
super(name, request, response)
|
331
|
+
end
|
332
|
+
end
|
@@ -0,0 +1,113 @@
|
|
1
|
+
require 'json'
|
2
|
+
|
3
|
+
module EpsagonResqueModule
|
4
|
+
def self.prepended(base)
|
5
|
+
class << base
|
6
|
+
prepend ClassMethods
|
7
|
+
end
|
8
|
+
end
|
9
|
+
|
10
|
+
# Module to prepend to Resque singleton class
|
11
|
+
module ClassMethods
|
12
|
+
def push(queue, item)
|
13
|
+
epsagon_conf = config[:epsagon] || {}
|
14
|
+
# Check if the job is being wrapped by ActiveJob
|
15
|
+
# before retrieving the job class name
|
16
|
+
job_class = if item[:class] == 'ActiveJob::QueueAdapters::ResqueAdapter::JobWrapper' && item[:args][0]&.is_a?(Hash)
|
17
|
+
item[:args][0]['job_class']
|
18
|
+
else
|
19
|
+
item[:class]
|
20
|
+
end
|
21
|
+
attributes = {
|
22
|
+
'operation' => 'enqueue',
|
23
|
+
'messaging.system' => 'resque',
|
24
|
+
'messaging.resque.job_class' => job_class,
|
25
|
+
'messaging.destination' => queue.to_s,
|
26
|
+
'messaging.destination_kind' => 'queue',
|
27
|
+
'messaging.resque.redis_url' => Resque.redis.connection[:id]
|
28
|
+
}
|
29
|
+
unless epsagon_conf[:metadata_only]
|
30
|
+
attributes.merge!({
|
31
|
+
'messaging.resque.args' => JSON.dump(item)
|
32
|
+
})
|
33
|
+
end
|
34
|
+
|
35
|
+
tracer.in_span(queue.to_s, attributes: attributes, kind: :producer) do
|
36
|
+
OpenTelemetry.propagation.text.inject(item)
|
37
|
+
super
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
def tracer
|
42
|
+
EpsagonResqueInstrumentation.instance.tracer
|
43
|
+
end
|
44
|
+
|
45
|
+
def config
|
46
|
+
EpsagonResqueInstrumentation.instance.config
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
module EpsagonResqueJob
|
52
|
+
def perform # rubocop:disable Metrics/AbcSize, Metrics/MethodLength, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
|
53
|
+
inner_exception = nil
|
54
|
+
epsagon_conf = config[:epsagon] || {}
|
55
|
+
job_args = args || []
|
56
|
+
|
57
|
+
# Check if the job is being wrapped by ActiveJob
|
58
|
+
# before retrieving the job class name
|
59
|
+
job_class = if payload_class_name == 'ActiveJob::QueueAdapters::ResqueAdapter::JobWrapper' && job_args[0]&.is_a?(Hash)
|
60
|
+
job_args[0]['job_class']
|
61
|
+
else
|
62
|
+
payload_class_name
|
63
|
+
end
|
64
|
+
|
65
|
+
attributes = {
|
66
|
+
'operation' => 'perform',
|
67
|
+
'messaging.system' => 'resque',
|
68
|
+
'messaging.resque.job_class' => job_class,
|
69
|
+
'messaging.destination' => queue.to_s,
|
70
|
+
'messaging.destination_kind' => 'queue',
|
71
|
+
'messaging.resque.redis_url' => Resque.redis.connection[:id]
|
72
|
+
}
|
73
|
+
runner_attributes = {
|
74
|
+
'type' => 'resque_worker',
|
75
|
+
'messaging.resque.redis_url' => Resque.redis.connection[:id],
|
76
|
+
|
77
|
+
}
|
78
|
+
|
79
|
+
extracted_context = OpenTelemetry.propagation.text.extract(@payload)
|
80
|
+
|
81
|
+
unless epsagon_conf[:metadata_only]
|
82
|
+
attributes.merge!({
|
83
|
+
'messaging.resque.args' => JSON.dump(args)
|
84
|
+
})
|
85
|
+
end
|
86
|
+
tracer.in_span(
|
87
|
+
queue.to_s,
|
88
|
+
attributes: attributes,
|
89
|
+
with_parent: extracted_context,
|
90
|
+
kind: :consumer
|
91
|
+
) do |trigger_span|
|
92
|
+
tracer.in_span(job_class,
|
93
|
+
attributes: runner_attributes,
|
94
|
+
kind: :consumer
|
95
|
+
) do |runner_span|
|
96
|
+
super
|
97
|
+
end
|
98
|
+
rescue Exception => e
|
99
|
+
inner_exception = e
|
100
|
+
end
|
101
|
+
raise inner_exception if inner_exception
|
102
|
+
end
|
103
|
+
|
104
|
+
private
|
105
|
+
|
106
|
+
def tracer
|
107
|
+
EpsagonResqueInstrumentation.instance.tracer
|
108
|
+
end
|
109
|
+
|
110
|
+
def config
|
111
|
+
EpsagonResqueInstrumentation.instance.config
|
112
|
+
end
|
113
|
+
end
|
@@ -1,58 +1,11 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require 'opentelemetry'
|
4
|
-
require 'rails'
|
5
|
-
require 'action_controller/railtie'
|
6
4
|
|
7
5
|
require_relative '../util'
|
8
6
|
require_relative '../epsagon_constants'
|
9
7
|
|
10
8
|
|
11
|
-
module RackExtension
|
12
|
-
module_function
|
13
|
-
|
14
|
-
CURRENT_SPAN_KEY = OpenTelemetry::Context.create_key('current-span')
|
15
|
-
|
16
|
-
private_constant :CURRENT_SPAN_KEY
|
17
|
-
|
18
|
-
# Returns the current span from the current or provided context
|
19
|
-
#
|
20
|
-
# @param [optional Context] context The context to lookup the current
|
21
|
-
# {Span} from. Defaults to Context.current
|
22
|
-
def current_span(context = nil)
|
23
|
-
context ||= OpenTelemetry::Context.current
|
24
|
-
context.value(CURRENT_SPAN_KEY) || OpenTelemetry::Trace::Span::INVALID
|
25
|
-
end
|
26
|
-
|
27
|
-
# Returns a context containing the span, derived from the optional parent
|
28
|
-
# context, or the current context if one was not provided.
|
29
|
-
#
|
30
|
-
# @param [optional Context] context The context to use as the parent for
|
31
|
-
# the returned context
|
32
|
-
def context_with_span(span, parent_context: OpenTelemetry::Context.current)
|
33
|
-
parent_context.set_value(CURRENT_SPAN_KEY, span)
|
34
|
-
end
|
35
|
-
|
36
|
-
# Activates/deactivates the Span within the current Context, which makes the "current span"
|
37
|
-
# available implicitly.
|
38
|
-
#
|
39
|
-
# On exit, the Span that was active before calling this method will be reactivated.
|
40
|
-
#
|
41
|
-
# @param [Span] span the span to activate
|
42
|
-
# @yield [span, context] yields span and a context containing the span to the block.
|
43
|
-
def with_span(span)
|
44
|
-
OpenTelemetry::Context.with_value(CURRENT_SPAN_KEY, span) { |c, s| yield s, c }
|
45
|
-
end
|
46
|
-
end
|
47
|
-
|
48
|
-
module MetalPatch
|
49
|
-
def dispatch(name, request, response)
|
50
|
-
rack_span = RackExtension.current_span
|
51
|
-
# rack_span.name = "#{self.class.name}##{name}" if rack_span.context.valid? && !request.env['action_dispatch.exception']
|
52
|
-
super(name, request, response)
|
53
|
-
end
|
54
|
-
end
|
55
|
-
|
56
9
|
class EpsagonRailsInstrumentation < OpenTelemetry::Instrumentation::Base
|
57
10
|
install do |_config|
|
58
11
|
require_relative 'epsagon_rails_middleware'
|
@@ -0,0 +1,21 @@
|
|
1
|
+
class EpsagonResqueInstrumentation < OpenTelemetry::Instrumentation::Base
|
2
|
+
install do |_config|
|
3
|
+
require_dependencies
|
4
|
+
patch
|
5
|
+
end
|
6
|
+
|
7
|
+
present do
|
8
|
+
defined?(::Resque)
|
9
|
+
end
|
10
|
+
|
11
|
+
private
|
12
|
+
|
13
|
+
def patch
|
14
|
+
::Resque.prepend(EpsagonResqueModule)
|
15
|
+
::Resque::Job.prepend(EpsagonResqueJob)
|
16
|
+
end
|
17
|
+
|
18
|
+
def require_dependencies
|
19
|
+
require_relative 'epsagon_resque_job'
|
20
|
+
end
|
21
|
+
end
|
data/lib/util.rb
CHANGED
@@ -4,6 +4,10 @@ require 'cgi'
|
|
4
4
|
|
5
5
|
# Utilities for epsagon opentelemetry solution
|
6
6
|
module Util
|
7
|
+
def self.validate_value(h, k, message, &block)
|
8
|
+
raise ArgumentError.new( "#{k} #{message}. Got #{h[k].class}: #{h[k]}" ) unless yield(h[k])
|
9
|
+
end
|
10
|
+
|
7
11
|
def self.epsagon_query_attributes(query_string)
|
8
12
|
if query_string&.include? '='
|
9
13
|
{ 'http.request.query_params' => CGI.parse(query_string).to_json }
|
@@ -25,7 +29,7 @@ module Util
|
|
25
29
|
end
|
26
30
|
return value
|
27
31
|
elsif value.instance_of? String then
|
28
|
-
value[0, max_size]
|
32
|
+
(value.frozen? ? value.dup : value).force_encoding('utf-8')[0, max_size]
|
29
33
|
else
|
30
34
|
value
|
31
35
|
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.
|
4
|
+
version: 0.0.29
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Epsagon
|
8
|
-
autorequire:
|
8
|
+
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2021-
|
11
|
+
date: 2021-07-01 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: opentelemetry-api
|
@@ -98,7 +98,7 @@ description: 'Epsagon provides tracing to Ruby applications for the collection o
|
|
98
98
|
distributed tracing and performance metrics to simplify complex architectures, eliminate
|
99
99
|
manual work, visualize and correlate data to identify and fix problems fast.
|
100
100
|
|
101
|
-
'
|
101
|
+
'
|
102
102
|
email: info@epsagon.com
|
103
103
|
executables: []
|
104
104
|
extensions: []
|
@@ -112,10 +112,12 @@ files:
|
|
112
112
|
- lib/instrumentation/aws_sdk_plugin.rb
|
113
113
|
- lib/instrumentation/epsagon_faraday_middleware.rb
|
114
114
|
- lib/instrumentation/epsagon_rails_middleware.rb
|
115
|
+
- lib/instrumentation/epsagon_resque_job.rb
|
115
116
|
- lib/instrumentation/faraday.rb
|
116
117
|
- lib/instrumentation/net_http.rb
|
117
118
|
- lib/instrumentation/postgres.rb
|
118
119
|
- lib/instrumentation/rails.rb
|
120
|
+
- lib/instrumentation/resque.rb
|
119
121
|
- lib/instrumentation/sinatra.rb
|
120
122
|
- lib/instrumentation/version.rb
|
121
123
|
- lib/util.rb
|
@@ -123,7 +125,7 @@ homepage: https://github.com/epsagon/epsagon-ruby
|
|
123
125
|
licenses:
|
124
126
|
- MIT
|
125
127
|
metadata: {}
|
126
|
-
post_install_message:
|
128
|
+
post_install_message:
|
127
129
|
rdoc_options: []
|
128
130
|
require_paths:
|
129
131
|
- lib
|
@@ -138,8 +140,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
138
140
|
- !ruby/object:Gem::Version
|
139
141
|
version: '0'
|
140
142
|
requirements: []
|
141
|
-
rubygems_version: 3.
|
142
|
-
signing_key:
|
143
|
+
rubygems_version: 3.1.4
|
144
|
+
signing_key:
|
143
145
|
specification_version: 4
|
144
146
|
summary: Epsagon provides tracing to Ruby applications for the collection of distributed
|
145
147
|
tracing and performance metrics.
|