epsagon 0.0.0 → 0.0.1

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: 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
  - - ">="