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