epsagon 0.0.0 → 0.0.1

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: 036b9458b78db168edb2cb90dd4898f812eaa81a3e057abd69fc073fef9552d2
4
- data.tar.gz: 1b2b2dce82f55073377db72400737a1243f8dab08426780d59f6a5faf62a2a13
3
+ metadata.gz: 87955008fa3a72eef9788a33b27ea5b1b803f05f5b4576980cbfcde82f418b8f
4
+ data.tar.gz: 8f55c3de860ad268786aac29fc6d132d60aaf3314858de5b7a396700a8e6b57c
5
5
  SHA512:
6
- metadata.gz: 5bbbc9237c61ad7eb0818803eea213ed8b1003210b199c3c29355f1536b6dc4b7e990b628b92b8c015f4fab1c623eb92f07352d6c6cb5b6a00d0aeb12aa0dfc8
7
- data.tar.gz: 81da4b0e55ecd53569564c22cfe1a986dce0835970bf3a522a7bc100e5b5a6c373275c6ac2bccd9d0a4500dddb8c26dca54d402d499116fa90201ba8de5edef5
6
+ metadata.gz: c75902bf40adc989654cafad809e2cfac0a9dbba506981a3f52be29868fad8ba77691580bbae616fe793a3fb47e0ef4070d822cb659ae186ba1af86016ecd0a8
7
+ data.tar.gz: 7eaf1f961154c97d106bf0ec95d763bbdb049783bbcafb08abe2ff9f685a4ab17f77282b483e42d2a06bf07ef588ab9d346b66a074355141a1f13f5a6f104190
data/lib/epsagon.rb CHANGED
@@ -12,31 +12,65 @@ require_relative 'util'
12
12
 
13
13
  Bundler.require
14
14
 
15
- def metadata_only?
16
- ENV['EPSAGON_METADATA']&.to_s&.downcase != 'false'
17
- end
15
+ # Epsagon tracing main entry point
16
+ module Epsagon
17
+ module_function
18
18
 
19
- def debug?
20
- ENV['EPSAGON_DEBUG']&.to_s&.downcase == 'true'
21
- end
19
+ def init(**args)
20
+ defaults = {
21
+ metadata_only: ENV['EPSAGON_METADATA']&.to_s&.downcase != 'false',
22
+ debug: ENV['EPSAGON_DEBUG']&.to_s&.downcase == 'true',
23
+ token: ENV['EPSAGON_TOKEN'],
24
+ app_name: ENV['EPSAGON_APP_NAME'],
25
+ backend: ENV['EPSAGON_BACKEND'] || 'localhost:55681/v1/trace'
26
+ }
27
+ @@epsagon_config = defaults.merge(args)
28
+ end
29
+
30
+ def metadata_only?
31
+ ENV['EPSAGON_METADATA']&.to_s&.downcase != 'false'
32
+ end
33
+
34
+ def debug?
35
+ ENV['EPSAGON_DEBUG']&.to_s&.downcase == 'true'
36
+ end
22
37
 
23
- # #config opentelemetry with epsaon extensions:
24
- OpenTelemetry::SDK.configure do |c|
25
- c.use 'EpsagonSinatraInstrumentation'
26
- c.use 'EpsagonNetHTTPInstrumentation'
27
- c.use 'EpsagonFaradayInstrumentation'
28
- if ENV['EPSAGON_BACKEND']
29
- c.add_span_processor OpenTelemetry::SDK::Trace::Export::SimpleSpanProcessor.new(
30
- OpenTelemetry::Exporter::OTLP::Exporter.new(headers: {
31
- epasgon_token: ENV['EPSAGON_TOKEN'],
32
- epasgon_app_name: ENV['EPSAGON_APP_NAME']
33
- },
34
- endpoint: ENV['EPSAGON_BACKEND'],
35
- insecure: false)
38
+ # config opentelemetry with epsaon extensions:
39
+
40
+ def epsagon_confs(configurator)
41
+ configurator.resource = OpenTelemetry::SDK::Resources::Resource.telemetry_sdk.merge(
42
+ OpenTelemetry::SDK::Resources::Resource.create({ 'application' => ENV['EPSAGON_APP_NAME'] })
43
+ )
44
+ configurator.use 'EpsagonSinatraInstrumentation', { epsagon: @@epsagon_config }
45
+ configurator.use 'EpsagonNetHTTPInstrumentation', { epsagon: @@epsagon_config }
46
+ configurator.use 'EpsagonFaradayInstrumentation', { epsagon: @@epsagon_config }
47
+ # if ENV['EPSAGON_BACKEND']
48
+ configurator.add_span_processor OpenTelemetry::SDK::Trace::Export::BatchSpanProcessor.new(
49
+ exporter: OpenTelemetry::Exporter::OTLP::Exporter.new(headers: {
50
+ 'x-epsagon-token' => @@epsagon_config[:token]
51
+ },
52
+ endpoint: @@epsagon_config[:backend],
53
+ insecure: @@epsagon_config[:insecure] || false)
36
54
  )
37
- else
38
- c.add_span_processor OpenTelemetry::SDK::Trace::Export::SimpleSpanProcessor.new(
55
+ return unless debug?
56
+
57
+ configurator.add_span_processor OpenTelemetry::SDK::Trace::Export::SimpleSpanProcessor.new(
39
58
  OpenTelemetry::SDK::Trace::Export::ConsoleSpanExporter.new
40
59
  )
41
60
  end
61
+
62
+ OpenTelemetry::SDK.configure
63
+ end
64
+
65
+ # monkey patch to include epsagon confs
66
+ module OpenTelemetry
67
+ # monkey patch inner SDK module
68
+ module SDK
69
+ def self.configure
70
+ super do |c|
71
+ yield c if block_given?
72
+ Epsagon.epsagon_confs c
73
+ end
74
+ end
75
+ end
42
76
  end
@@ -0,0 +1,171 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative '../util'
4
+
5
+ # AWS SDK plugin for epsagon instrumentation
6
+ class EpsagonAwsPlugin < Seahorse::Client::Plugin
7
+ def add_handlers(handlers, _)
8
+ handlers.add(EpsagonAwsHandler, step: :validate)
9
+ end
10
+ end
11
+
12
+ # Generates Spans for all uses of AWS SDK
13
+ class EpsagonAwsHandler < Seahorse::Client::Handler
14
+ def call(context)
15
+ span_name = "AWS #{context[:service_name]}"
16
+ tracer.in_span(span_name) do |span|
17
+ @handler.call(context).tap do
18
+ span.set_attribute('aws.command', context[:command])
19
+ span.set_attribute('aws.status_code', context[:status_code])
20
+ end
21
+ end
22
+ end
23
+
24
+ def tracer
25
+ EpsagonAwsSdkInstrumentation.instance.tracer
26
+ end
27
+ end
28
+
29
+ # AWS SDK epsagon instrumentation
30
+ class EpsagonAwsSdkInstrumentation < OpenTelemetry::Instrumentation::Base
31
+ VERSION = '0.0.0'
32
+ SERVICES = %w[
33
+ ACM
34
+ APIGateway
35
+ AppStream
36
+ ApplicationAutoScaling
37
+ ApplicationDiscoveryService
38
+ Athena
39
+ AutoScaling
40
+ Batch
41
+ Budgets
42
+ CloudDirectory
43
+ CloudFormation
44
+ CloudFront
45
+ CloudHSM
46
+ CloudHSMV2
47
+ CloudSearch
48
+ CloudSearchDomain
49
+ CloudTrail
50
+ CloudWatch
51
+ CloudWatchEvents
52
+ CloudWatchLogs
53
+ CodeBuild
54
+ CodeCommit
55
+ CodeDeploy
56
+ CodePipeline
57
+ CodeStar
58
+ CognitoIdentity
59
+ CognitoIdentityProvider
60
+ CognitoSync
61
+ ConfigService
62
+ CostandUsageReportService
63
+ DAX
64
+ DataPipeline
65
+ DatabaseMigrationService
66
+ DeviceFarm
67
+ DirectConnect
68
+ DirectoryService
69
+ DynamoDB
70
+ DynamoDBStreams
71
+ EC2
72
+ ECR
73
+ ECS
74
+ EFS
75
+ EMR
76
+ ElastiCache
77
+ ElasticBeanstalk
78
+ ElasticLoadBalancing
79
+ ElasticLoadBalancingV2
80
+ ElasticTranscoder
81
+ ElasticsearchService
82
+ EventBridge
83
+ Firehose
84
+ GameLift
85
+ Glacier
86
+ Glue
87
+ Greengrass
88
+ Health
89
+ IAM
90
+ ImportExport
91
+ Inspector
92
+ IoT
93
+ IoTDataPlane
94
+ KMS
95
+ Kinesis
96
+ KinesisAnalytics
97
+ Lambda
98
+ LambdaPreview
99
+ Lex
100
+ LexModelBuildingService
101
+ Lightsail
102
+ MTurk
103
+ MachineLearning
104
+ MarketplaceCommerceAnalytics
105
+ MarketplaceEntitlementService
106
+ MarketplaceMetering
107
+ MigrationHub
108
+ Mobile
109
+ OpsWorks
110
+ OpsWorksCM
111
+ Organizations
112
+ Pinpoint
113
+ Polly
114
+ RDS
115
+ Redshift
116
+ Rekognition
117
+ ResourceGroupsTaggingAPI
118
+ Route53
119
+ Route53Domains
120
+ S3
121
+ SES
122
+ SMS
123
+ SNS
124
+ SQS
125
+ SSM
126
+ STS
127
+ SWF
128
+ ServiceCatalog
129
+ Shield
130
+ SimpleDB
131
+ Snowball
132
+ States
133
+ StorageGateway
134
+ Support
135
+ Textract
136
+ WAF
137
+ WAFRegional
138
+ WorkDocs
139
+ WorkSpaces
140
+ XRay
141
+ ].freeze
142
+
143
+ install do |_|
144
+ ::Seahorse::Client::Base.add_plugin(EpsagonAwsPlugin)
145
+ loaded_constants.each { |klass| klass.add_plugin(EpsagonAwsPlugin) }
146
+ end
147
+
148
+ present do
149
+ defined?(::Seahorse::Client::Base)
150
+ end
151
+
152
+ private
153
+
154
+ def loaded_constants
155
+ # Cross-check services against loaded AWS constants
156
+ # Module#const_get can return a constant from ancestors when there's a miss.
157
+ # If this conincidentally matches another constant, it will attempt to patch
158
+ # the wrong constant, resulting in patch failure.
159
+ available_services = ::Aws.constants & SERVICES.map(&:to_sym)
160
+
161
+ available_services.each_with_object([]) do |service, constants|
162
+ next if ::Aws.autoload?(service)
163
+
164
+ begin
165
+ constants << ::Aws.const_get(service, false).const_get(:Client, false)
166
+ rescue StandardError
167
+ next
168
+ end
169
+ end
170
+ end
171
+ end
@@ -3,7 +3,12 @@
3
3
  require 'faraday'
4
4
  require_relative '../util'
5
5
 
6
+ # Faraday middleware for epsagon instrumentaton
6
7
  class EpsagonFaradayMiddleware < ::Faraday::Middleware
8
+ def config
9
+ EpsagonFaradayInstrumentation.instance.config
10
+ end
11
+
7
12
  HTTP_METHODS_SYMBOL_TO_STRING = {
8
13
  connect: 'CONNECT',
9
14
  delete: 'DELETE',
@@ -27,7 +32,7 @@ class EpsagonFaradayMiddleware < ::Faraday::Middleware
27
32
  'http.request.path' => path
28
33
  }
29
34
 
30
- unless metadata_only?
35
+ unless config[:epsagon][:metadata_only]
31
36
  attributes.merge!(Util.epsagon_query_attributes(env.url.query))
32
37
  attributes.merge!({
33
38
  'http.request.path_params' => path_params,
@@ -59,7 +64,7 @@ class EpsagonFaradayMiddleware < ::Faraday::Middleware
59
64
  def trace_response(span, response)
60
65
  span.set_attribute('http.status_code', response.status)
61
66
 
62
- unless metadata_only?
67
+ unless config[:epsagon][:metadata_only]
63
68
  span.set_attribute('http.response.headers', response.headers.to_json)
64
69
  span.set_attribute('http.response.body', response.body)
65
70
  end
@@ -69,6 +74,7 @@ class EpsagonFaradayMiddleware < ::Faraday::Middleware
69
74
  end
70
75
  end
71
76
 
77
+ # Patch faraday to include middleware
72
78
  module EpsagonFaradayPatch
73
79
  def adapter(*args)
74
80
  use(:epsagon_open_telemetry) unless @handlers.any? do |handler|
@@ -79,12 +85,15 @@ module EpsagonFaradayPatch
79
85
  end
80
86
  end
81
87
 
88
+ # Faraday epsagon instrumentaton
82
89
  class EpsagonFaradayInstrumentation < OpenTelemetry::Instrumentation::Base
90
+ VERSION = '0.0.0'
91
+
83
92
  install do |_config|
84
93
  ::Faraday::Middleware.register_middleware(
85
94
  epsagon_open_telemetry: EpsagonFaradayMiddleware
86
95
  )
87
- ::Faraday::RackBuilder.prepend(EpsagonFaradayPatch)
96
+ ::Faraday::RackBuilder.include(EpsagonFaradayPatch)
88
97
  end
89
98
 
90
99
  present do
@@ -4,10 +4,15 @@ require 'opentelemetry'
4
4
 
5
5
  require_relative '../util'
6
6
 
7
+ # Net::HTTP patch for epsagon instrumentaton
7
8
  module EpsagonNetHTTPExtension
8
9
  HTTP_METHODS_TO_SPAN_NAMES = Hash.new { |h, k| h[k] = "HTTP #{k}" }
9
10
  USE_SSL_TO_SCHEME = { false => 'http', true => 'https' }.freeze
10
11
 
12
+ def config
13
+ EpsagonNetHTTPInstrumentation.instance.config
14
+ end
15
+
11
16
  def request(req, body = nil, &block)
12
17
  # Do not trace recursive call for starting the connection
13
18
  return super(req, body, &block) unless started?
@@ -22,7 +27,7 @@ module EpsagonNetHTTPExtension
22
27
  'http.request.path' => path
23
28
  })
24
29
 
25
- unless metadata_only?
30
+ unless config[:epsagon][:metadata_only]
26
31
  headers = Hash[req.each_header.to_a]
27
32
  attributes.merge!({
28
33
  'http.request.path_params' => path_params,
@@ -53,7 +58,7 @@ module EpsagonNetHTTPExtension
53
58
  status_code = response.code.to_i
54
59
 
55
60
  span.set_attribute('http.status_code', status_code)
56
- unless metadata_only?
61
+ unless config[:epsagon][:metadata_only]
57
62
  span.set_attribute('http.response.headers', Hash[response.each_header.to_a].to_json)
58
63
  span.set_attribute('http.response.body', response.body)
59
64
  end
@@ -67,7 +72,10 @@ module EpsagonNetHTTPExtension
67
72
  end
68
73
  end
69
74
 
75
+ # Net::HTTP epsagon instrumentaton
70
76
  class EpsagonNetHTTPInstrumentation < OpenTelemetry::Instrumentation::Base
77
+ VERSION = '0.0.0'
78
+
71
79
  install do |_|
72
80
  ::Net::HTTP.prepend(EpsagonNetHTTPExtension)
73
81
  end
@@ -5,11 +5,16 @@ require 'opentelemetry'
5
5
 
6
6
  require_relative '../util'
7
7
 
8
+ # Sinatra middleware for epsagon instrumentation
8
9
  class EpsagonTracerMiddleware
9
10
  def initialize(app)
10
11
  @app = app
11
12
  end
12
13
 
14
+ def config
15
+ EpsagonSinatraInstrumentation.instance.config
16
+ end
17
+
13
18
  def call(env)
14
19
  request = Rack::Request.new(env)
15
20
  path, path_params = request.path.split(';')
@@ -27,7 +32,7 @@ class EpsagonTracerMiddleware
27
32
  'http.request.headers' => request_headers
28
33
  }
29
34
 
30
- unless metadata_only?
35
+ unless config[:epsagon][:metadata_only]
31
36
  request.body.rewind
32
37
  request_body = request.body.read
33
38
  request.body.rewind
@@ -68,7 +73,7 @@ class EpsagonTracerMiddleware
68
73
  def trace_response(http_span, framework_span, env, resp)
69
74
  status, headers, response_body = resp
70
75
 
71
- unless metadata_only?
76
+ unless config[:epsagon][:metadata_only]
72
77
  http_span.set_attribute('http.response.headers', JSON.generate(headers))
73
78
  http_span.set_attribute('http.response.body', response_body.join)
74
79
  end
@@ -79,6 +84,7 @@ class EpsagonTracerMiddleware
79
84
  end
80
85
  end
81
86
 
87
+ # Sinatra extension for epsagon instrumentation
82
88
  module EpsagonTracerExtension
83
89
  # Sinatra hook after extension is registered
84
90
  def self.registered(app)
@@ -100,7 +106,10 @@ module EpsagonTracerExtension
100
106
  end
101
107
  end
102
108
 
109
+ # Sinatra epsagon instrumentation
103
110
  class EpsagonSinatraInstrumentation < OpenTelemetry::Instrumentation::Base
111
+ VERSION = '0.0.0'
112
+
104
113
  install do |_|
105
114
  ::Sinatra::Base.register EpsagonTracerExtension
106
115
  end
data/lib/util.rb CHANGED
@@ -2,6 +2,7 @@
2
2
 
3
3
  require 'cgi'
4
4
 
5
+ # Utilities for epsagon opentelemetry solution
5
6
  module Util
6
7
  def self.epsagon_query_attributes(query_string)
7
8
  if query_string&.include? '='
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.0
4
+ version: 0.0.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Assaf Paneth
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2021-02-06 00:00:00.000000000 Z
11
+ date: 2021-03-24 00:00:00.000000000 Z
12
12
  dependencies: []
13
13
  description: Epsagon for ruby
14
14
  email: assaf.paneth@gmail.com
@@ -18,6 +18,7 @@ extra_rdoc_files: []
18
18
  files:
19
19
  - lib/epsagon.rb
20
20
  - lib/epsagon_opentelemetry.rb
21
+ - lib/instrumentation/aws_sdk.rb
21
22
  - lib/instrumentation/faraday.rb
22
23
  - lib/instrumentation/net_http.rb
23
24
  - lib/instrumentation/sinatra.rb
@@ -32,9 +33,9 @@ require_paths:
32
33
  - lib
33
34
  required_ruby_version: !ruby/object:Gem::Requirement
34
35
  requirements:
35
- - - ">="
36
+ - - "~>"
36
37
  - !ruby/object:Gem::Version
37
- version: '0'
38
+ version: '2.7'
38
39
  required_rubygems_version: !ruby/object:Gem::Requirement
39
40
  requirements:
40
41
  - - ">="