epsagon 0.0.27 → 0.0.28

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: 74f7a24306d3840c295345b485169ffa8bb4bfa2285f7d43ae69440d0b685e53
4
- data.tar.gz: e043b98f22a6d804fc5692b8ab60c8eb1e05d74de736412fdfef58179afce086
3
+ metadata.gz: 1a17b55f2ce2ff35ca70dd51e8f8337041e202c528b6c691800d3e3b7b0d42c4
4
+ data.tar.gz: d93046c571faa2d35a681217cb12952c57c7bd3232e77a136a5954a5534541b1
5
5
  SHA512:
6
- metadata.gz: bb53cf200be779ba464a58a41bc62d03849ec8be6e161fca6a8d1f8594b124d38c3445155ac3e2582a318dc513415e6a236fd43f9a75b782f9642a29d5795c71
7
- data.tar.gz: de6b92f478e04c362911160c29eec775553ef16f3714b9f6b78c062d60ee46161291b08d89f254f8bdf0f0d80884e4e41a79146114d87fc84ef758f246710c04
6
+ metadata.gz: 9290a8dee89f24588f93bca0ab331855cab0cd46e09fdae10c4bb0c00c7c61c35c6045bc6b41971639767fc46f30d241b49a45a89a51c29baaa734113188aa7a
7
+ data.tar.gz: 3c4c1b54d0b344bf7399f3d088cd22bebca010d2b063244b425693bcaa2ef0ced625ec3a0921d1d5ce0cf7effd81e90dc6e410d5c893f1062096c78ec66e795f
data/lib/arn_parser.rb ADDED
@@ -0,0 +1,27 @@
1
+ #
2
+ # Credit: https://gist.github.com/RulerOf/b9f5dd00a9911aba8271b57d3d269d7a
3
+ #
4
+ class Arn
5
+ attr_accessor :partition, :service, :region, :account, :resource
6
+
7
+ def initialize(partition, service, region, account, resource)
8
+ @partition = partition
9
+ @service = service
10
+ @region = region
11
+ @account = account
12
+ @resource = resource
13
+ end
14
+
15
+ def self.parse(arn)
16
+ raise TypeError, 'ARN must be supplied as a string' unless arn.is_a?(String)
17
+
18
+ arn_components = arn.split(':', 6)
19
+ raise ArgumentError, 'Could not parse ARN' if arn_components.length < 6
20
+
21
+ Arn.new arn_components[1],
22
+ arn_components[2],
23
+ arn_components[3],
24
+ arn_components[4],
25
+ arn_components[5]
26
+ end
27
+ end
data/lib/epsagon.rb CHANGED
@@ -12,23 +12,30 @@ require_relative 'instrumentation/net_http'
12
12
  require_relative 'instrumentation/faraday'
13
13
  require_relative 'instrumentation/aws_sdk'
14
14
  require_relative 'instrumentation/rails'
15
+ require_relative 'instrumentation/postgres'
15
16
  require_relative 'util'
16
17
  require_relative 'epsagon_constants'
17
18
  require_relative 'exporter_extension'
19
+ require_relative 'arn_parser'
18
20
 
19
21
  Bundler.require
20
22
 
21
23
  # Epsagon tracing main entry point
22
24
  module Epsagon
23
25
  DEFAULT_BACKEND = 'opentelemetry.tc.epsagon.com:443/traces'
24
- DEFAULT_IGNORE_DOMAINS = ['newrelic.com']
26
+ DEFAULT_IGNORE_DOMAINS = ['newrelic.com'].freeze
25
27
 
26
- @@epsagon_config = {}
28
+ @@epsagon_config = nil
27
29
 
28
30
  module_function
29
31
 
30
32
  def init(**args)
31
- @@epsagon_config = {
33
+ get_config.merge!(args)
34
+ OpenTelemetry::SDK.configure
35
+ end
36
+
37
+ def get_config
38
+ @@epsagon_config ||= {
32
39
  metadata_only: ENV['EPSAGON_METADATA']&.to_s&.downcase != 'false',
33
40
  debug: ENV['EPSAGON_DEBUG']&.to_s&.downcase == 'true',
34
41
  token: ENV['EPSAGON_TOKEN'] || '',
@@ -37,52 +44,69 @@ module Epsagon
37
44
  backend: ENV['EPSAGON_BACKEND'] || DEFAULT_BACKEND,
38
45
  ignore_domains: ENV['EPSAGON_IGNORE_DOMAINS'] || DEFAULT_IGNORE_DOMAINS
39
46
  }
40
- @@epsagon_config.merge!(args)
47
+ end
41
48
 
42
- Util.validate_value(@@epsagon_config, :metadata_only, 'Must be a boolean') {|v| !!v == v}
43
- Util.validate_value(@@epsagon_config, :debug, 'Must be a boolean') {|v| !!v == v}
44
- Util.validate_value(@@epsagon_config, :token, 'Must be a valid Epsagon token') {|v| v.is_a? String and v.size > 10}
45
- Util.validate_value(@@epsagon_config, :app_name, 'Must be a String') {|v| v.is_a? String}
46
- Util.validate_value(@@epsagon_config, :max_attribute_size, 'Must be an Integer') {|v| v.is_a? Integer}
47
- Util.validate_value(@@epsagon_config, :ignore_domains, 'Must be iterable') {|v| v.respond_to?(:each)}
49
+ def set_ecs_metadata
50
+ metadata_uri = ENV['ECS_CONTAINER_METADATA_URI']
51
+ return {} if metadata_uri.nil?
48
52
 
49
- OpenTelemetry::SDK.configure
50
- end
53
+ response = Net::HTTP.get(URI(metadata_uri))
54
+ ecs_metadata = JSON.parse(response)
55
+ arn = Arn.parse(ecs_metadata['Labels']['com.amazonaws.ecs.task-arn'])
51
56
 
52
- def get_config
53
- @@epsagon_config
57
+ {
58
+ 'aws.account_id' => arn.account,
59
+ 'aws.region' => arn.region,
60
+ 'aws.ecs.cluster' => ecs_metadata['Labels']['com.amazonaws.ecs.cluster'],
61
+ 'aws.ecs.task_arn' => ecs_metadata['Labels']['com.amazonaws.ecs.task-arn'],
62
+ 'aws.ecs.container_name' => ecs_metadata['Labels']['com.amazonaws.ecs.container-name'],
63
+ 'aws.ecs.task.family' => ecs_metadata['Labels']['com.amazonaws.ecs.task-definition-family'],
64
+ 'aws.ecs.task.revision' => ecs_metadata['Labels']['com.amazonaws.ecs.task-definition-version']
65
+ }
54
66
  end
55
67
 
56
68
  # config opentelemetry with epsaon extensions:
57
69
 
58
70
  def epsagon_confs(configurator)
71
+ otel_resource = {
72
+ 'application' => get_config[:app_name],
73
+ 'epsagon.version' => EpsagonConstants::VERSION,
74
+ 'epsagon.metadata_only' => get_config[:metadata_only]
75
+ }.merge(set_ecs_metadata)
76
+
59
77
  configurator.resource = OpenTelemetry::SDK::Resources::Resource.telemetry_sdk.merge(
60
- OpenTelemetry::SDK::Resources::Resource.create({
61
- 'application' => @@epsagon_config[:app_name],
62
- 'epsagon.version' => EpsagonConstants::VERSION,
63
- 'epsagon.metadata_only' => @@epsagon_config[:metadata_only]
64
- })
78
+ OpenTelemetry::SDK::Resources::Resource.create(otel_resource)
65
79
  )
66
- configurator.use 'EpsagonSinatraInstrumentation', { epsagon: @@epsagon_config }
67
- configurator.use 'EpsagonNetHTTPInstrumentation', { epsagon: @@epsagon_config }
68
- configurator.use 'EpsagonFaradayInstrumentation', { epsagon: @@epsagon_config }
69
- configurator.use 'EpsagonAwsSdkInstrumentation', { epsagon: @@epsagon_config }
70
- configurator.use 'EpsagonRailsInstrumentation', { epsagon: @@epsagon_config }
71
- configurator.use 'OpenTelemetry::Instrumentation::Sidekiq', { epsagon: @@epsagon_config }
72
-
73
- if @@epsagon_config[:debug]
80
+
81
+ configurator.use 'EpsagonSinatraInstrumentation', { epsagon: get_config }
82
+ configurator.use 'EpsagonNetHTTPInstrumentation', { epsagon: get_config }
83
+ configurator.use 'EpsagonFaradayInstrumentation', { epsagon: get_config }
84
+ configurator.use 'EpsagonAwsSdkInstrumentation', { epsagon: get_config }
85
+ configurator.use 'EpsagonRailsInstrumentation', { epsagon: get_config }
86
+ configurator.use 'OpenTelemetry::Instrumentation::Sidekiq', { epsagon: get_config }
87
+ configurator.use 'EpsagonPostgresInstrumentation', { epsagon: get_config }
88
+
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
+
74
98
  configurator.add_span_processor OpenTelemetry::SDK::Trace::Export::SimpleSpanProcessor.new(
75
99
  OpenTelemetry::SDK::Trace::Export::ConsoleSpanExporter.new
76
100
  )
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
+ )
77
109
  end
78
-
79
- configurator.add_span_processor OpenTelemetry::SDK::Trace::Export::BatchSpanProcessor.new(
80
- exporter: OpenTelemetry::Exporter::OTLP::Exporter.new(headers: {
81
- 'x-epsagon-token' => @@epsagon_config[:token]
82
- },
83
- endpoint: @@epsagon_config[:backend],
84
- insecure: @@epsagon_config[:insecure] || false)
85
- )
86
110
  end
87
111
  end
88
112
 
@@ -1,3 +1,3 @@
1
1
  module EpsagonConstants
2
- VERSION = '0.0.27'
2
+ VERSION = '0.0.28'
3
3
  end
@@ -189,7 +189,7 @@ class EpsagonRackMiddleware
189
189
  def set_attributes_after_request(http_span, _framework_span, status, headers, response)
190
190
  unless config[:epsagon][:metadata_only]
191
191
  http_span.set_attribute('http.response.headers', JSON.generate(headers))
192
- http_span.set_attribute('http.response.body', response.join)
192
+ http_span.set_attribute('http.response.body', response.join) if response.respond_to?(:join)
193
193
  end
194
194
 
195
195
  http_span.set_attribute('http.status_code', status)
@@ -0,0 +1,294 @@
1
+ require 'pg_query'
2
+
3
+ module PostgresExtension
4
+ # A list of SQL commands, from: https://www.postgresql.org/docs/current/sql-commands.html
5
+ # Commands are truncated to their first word, and all duplicates
6
+ # are removed, This favors brevity and low-cardinality over descriptiveness.
7
+ SQL_COMMANDS = %w[
8
+ ABORT
9
+ ALTER
10
+ ANALYZE
11
+ BEGIN
12
+ CALL
13
+ CHECKPOINT
14
+ CLOSE
15
+ CLUSTER
16
+ COMMENT
17
+ COMMIT
18
+ COPY
19
+ CREATE
20
+ DEALLOCATE
21
+ DECLARE
22
+ DELETE
23
+ DISCARD
24
+ DO
25
+ DROP
26
+ END
27
+ EXECUTE
28
+ EXPLAIN
29
+ FETCH
30
+ GRANT
31
+ IMPORT
32
+ INSERT
33
+ LISTEN
34
+ LOAD
35
+ LOCK
36
+ MOVE
37
+ NOTIFY
38
+ PREPARE
39
+ PREPARE
40
+ REASSIGN
41
+ REFRESH
42
+ REINDEX
43
+ RELEASE
44
+ RESET
45
+ REVOKE
46
+ ROLLBACK
47
+ SAVEPOINT
48
+ SECURITY
49
+ SELECT
50
+ SELECT
51
+ SET
52
+ SHOW
53
+ START
54
+ TRUNCATE
55
+ UNLISTEN
56
+ UPDATE
57
+ VACUUM
58
+ VALUES
59
+ ].freeze
60
+
61
+ # From: https://github.com/newrelic/newrelic-ruby-agent/blob/9787095d4b5b2d8fcaf2fdbd964ed07c731a8b6b/lib/new_relic/agent/database/obfuscation_helpers.rb#L9-L34
62
+ COMPONENTS_REGEX_MAP = {
63
+ single_quotes: /'(?:[^']|'')*?(?:\\'.*|'(?!'))/,
64
+ dollar_quotes: /(\$(?!\d)[^$]*?\$).*?(?:\1|$)/,
65
+ uuids: /\{?(?:[0-9a-fA-F]\-*){32}\}?/,
66
+ numeric_literals: /-?\b(?:[0-9]+\.)?[0-9]+([eE][+-]?[0-9]+)?\b/,
67
+ boolean_literals: /\b(?:true|false|null)\b/i,
68
+ comments: /(?:#|--).*?(?=\r|\n|$)/i,
69
+ multi_line_comments: %r{\/\*(?:[^\/]|\/[^*])*?(?:\*\/|\/\*.*)}
70
+ }.freeze
71
+
72
+ POSTGRES_COMPONENTS = %i[
73
+ single_quotes
74
+ dollar_quotes
75
+ uuids
76
+ numeric_literals
77
+ boolean_literals
78
+ comments
79
+ multi_line_comments
80
+ ].freeze
81
+
82
+ UNMATCHED_PAIRS_REGEX = %r{'|\/\*|\*\/|\$(?!\?)}.freeze
83
+
84
+ # These are all alike in that they will have a SQL statement as the first parameter.
85
+ # That statement may possibly be parameterized, but we can still use it - the
86
+ # obfuscation code will just transform $1 -> $? in that case (which is fine enough).
87
+ EXEC_ISH_METHODS = %i[
88
+ exec
89
+ query
90
+ sync_exec
91
+ async_exec
92
+ exec_params
93
+ async_exec_params
94
+ sync_exec_params
95
+ ].freeze
96
+
97
+ # The following methods all take a statement name as the first
98
+ # parameter, and a SQL statement as the second - and possibly
99
+ # further parameters after that. We can trace them all alike.
100
+ PREPARE_ISH_METHODS = %i[
101
+ prepare
102
+ async_prepare
103
+ sync_prepare
104
+ ].freeze
105
+
106
+ # The following methods take a prepared statement name as their first
107
+ # parameter - everything after that is either potentially quite sensitive
108
+ # (an array of bind params) or not useful to us. We trace them all alike.
109
+ EXEC_PREPARED_ISH_METHODS = %i[
110
+ exec_prepared
111
+ async_exec_prepared
112
+ sync_exec_prepared
113
+ ].freeze
114
+
115
+ EXEC_ISH_METHODS.each do |method|
116
+ define_method method do |*args|
117
+ span_name, attrs = span_attrs(:query, *args)
118
+ tracer.in_span(span_name, attributes: attrs, kind: :client) do
119
+ super(*args)
120
+ end
121
+ end
122
+ end
123
+
124
+ PREPARE_ISH_METHODS.each do |method|
125
+ define_method method do |*args|
126
+ span_name, attrs = span_attrs(:prepare, *args)
127
+ tracer.in_span(span_name, attributes: attrs, kind: :client) do
128
+ super(*args)
129
+ end
130
+ end
131
+ end
132
+
133
+ EXEC_PREPARED_ISH_METHODS.each do |method|
134
+ define_method method do |*args|
135
+ span_name, attrs = span_attrs(:execute, *args)
136
+ tracer.in_span(span_name, attributes: attrs, kind: :client) do
137
+ super(*args)
138
+ end
139
+ end
140
+ end
141
+
142
+ def config
143
+ EpsagonPostgresInstrumentation.instance.config
144
+ end
145
+
146
+ def tracer
147
+ EpsagonPostgresInstrumentation.instance.tracer
148
+ end
149
+
150
+ def lru_cache
151
+ # When SQL is being sanitized, we know that this cache will
152
+ # never be more than 50 entries * 2000 characters (so, presumably
153
+ # 100k bytes - or 97k). When not sanitizing SQL, then this cache
154
+ # could grow much larger - but the small cache size should otherwise
155
+ # help contain memory growth. The intended use here is to cache
156
+ # prepared SQL statements, so that we can attach a reasonable
157
+ # `db.sql.statement` value to spans when those prepared statements
158
+ # are executed later on.
159
+ @lru_cache ||= LruCache.new(50)
160
+ end
161
+
162
+ # Rubocop is complaining about 19.31/18 for Metrics/AbcSize.
163
+ # But, getting that metric in line would force us over the
164
+ # module size limit! We can't win here unless we want to start
165
+ # abstracting things into a million pieces.
166
+ def span_attrs(kind, *args) # rubocop:disable Metrics/AbcSize
167
+ if kind == :query
168
+ operation = extract_operation(args[0])
169
+ sql = args[0]
170
+ else
171
+ statement_name = args[0]
172
+
173
+ if kind == :prepare
174
+ sql = args[1]
175
+ lru_cache[statement_name] = sql
176
+ operation = 'PREPARE'
177
+ else
178
+ sql = lru_cache[statement_name]
179
+ operation = 'EXECUTE'
180
+ end
181
+ end
182
+
183
+ attrs = { 'db.operation' => validated_operation(operation), 'db.postgresql.prepared_statement_name' => statement_name }
184
+ attrs['db.statement'] = sql if config[:epsagon][:metadata_only] == false
185
+ attrs['db.sql.table'] = table_name(sql)
186
+ attrs.reject! { |_, v| v.nil? }
187
+
188
+ [database_name, client_attributes.merge(attrs)]
189
+ end
190
+
191
+ def table_name(sql)
192
+ return '' if sql.nil?
193
+
194
+ parsed_query = PgQuery.parse(sql)
195
+ if parsed_query.tables.length == 0
196
+ ''
197
+ else
198
+ parsed_query.tables[0]
199
+ end
200
+ rescue PgQuery::ParseError
201
+ ''
202
+ end
203
+
204
+ def validated_operation(operation)
205
+ operation if PostgresExtension::SQL_COMMANDS.include?(operation)
206
+ end
207
+
208
+ def extract_operation(sql)
209
+ # From: https://github.com/open-telemetry/opentelemetry-js-contrib/blob/9244a08a8d014afe26b82b91cf86e407c2599d73/plugins/node/opentelemetry-instrumentation-pg/src/utils.ts#L35
210
+ sql.to_s.split[0].to_s.upcase
211
+ end
212
+
213
+ def generated_postgres_regex
214
+ @generated_postgres_regex ||= Regexp.union(PostgresExtension::POSTGRES_COMPONENTS.map { |component| PostgresExtension::COMPONENTS_REGEX_MAP[component] })
215
+ end
216
+
217
+ def database_name
218
+ conninfo_hash[:dbname]&.to_s
219
+ end
220
+
221
+ def client_attributes
222
+ attributes = {
223
+ 'db.system' => 'postgresql',
224
+ 'db.user' => conninfo_hash[:user]&.to_s,
225
+ 'db.name' => database_name,
226
+ 'net.peer.name' => conninfo_hash[:host]&.to_s
227
+ }
228
+ # attributes['peer.service'] = config[:peer_service] # if config[:peer_service]
229
+
230
+ attributes.merge(transport_attrs).reject { |_, v| v.nil? }
231
+ end
232
+
233
+ def transport_attrs
234
+ if conninfo_hash[:host]&.start_with?('/')
235
+ { 'net.transport' => 'Unix' }
236
+ else
237
+ {
238
+ 'net.transport' => 'IP.TCP',
239
+ 'net.peer.ip' => conninfo_hash[:hostaddr]&.to_s,
240
+ 'net.peer.port' => conninfo_hash[:port]&.to_s
241
+ }
242
+ end
243
+ end
244
+ end
245
+
246
+ # Copyright The OpenTelemetry Authors
247
+ #
248
+ # SPDX-License-Identifier: Apache-2.0
249
+ # A simple LRU cache for the postgres instrumentation.
250
+ class LruCache
251
+ # Rather than take a dependency on another gem, we implement a very, very basic
252
+ # LRU cache here. We can take advantage of the fact that Ruby hashes are ordered
253
+ # to always keep the recently-accessed keys at the top.
254
+ def initialize(size)
255
+ raise ArgumentError, 'Invalid size' if size < 1
256
+
257
+ @limit = size
258
+ @store = {}
259
+ end
260
+
261
+ def [](key)
262
+ # We need to check for the key explicitly, because `nil` is a valid hash value.
263
+ return unless @store.key?(key)
264
+
265
+ # Since the cache contains the item, we delete and re-insert into the hash.
266
+ # This guarantees that hash keys are ordered by access recency.
267
+ value = @store.delete(key)
268
+ @store[key] = value
269
+
270
+ value
271
+ end
272
+
273
+ def []=(key, value)
274
+ # We remove the value if it's already present, so that the hash keys remain ordered
275
+ # by access recency.
276
+ @store.delete(key)
277
+ @store[key] = value
278
+ @store.shift if @store.length > @limit
279
+ end
280
+ end
281
+
282
+ #
283
+ # EpsagonPostgresInstrumentation
284
+ # Installs the Instrumentation on the PG::Connection class
285
+ #
286
+ class EpsagonPostgresInstrumentation < OpenTelemetry::Instrumentation::Base
287
+ install do |_config|
288
+ ::PG::Connection.prepend(PostgresExtension)
289
+ end
290
+
291
+ present do
292
+ defined?(::PG)
293
+ end
294
+ end
data/lib/util.rb CHANGED
@@ -4,10 +4,6 @@ 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
-
11
7
  def self.epsagon_query_attributes(query_string)
12
8
  if query_string&.include? '='
13
9
  { 'http.request.query_params' => CGI.parse(query_string).to_json }
@@ -29,7 +25,7 @@ module Util
29
25
  end
30
26
  return value
31
27
  elsif value.instance_of? String then
32
- (value.frozen? ? value.dup : value).force_encoding('utf-8')[0, max_size]
28
+ value[0, max_size]
33
29
  else
34
30
  value
35
31
  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.27
4
+ version: 0.0.28
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-06-08 00:00:00.000000000 Z
11
+ date: 2021-06-10 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: opentelemetry-api
@@ -80,16 +80,31 @@ dependencies:
80
80
  - - "~>"
81
81
  - !ruby/object:Gem::Version
82
82
  version: 0.11.1
83
+ - !ruby/object:Gem::Dependency
84
+ name: pg_query
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - "~>"
88
+ - !ruby/object:Gem::Version
89
+ version: '2.0'
90
+ type: :runtime
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - "~>"
95
+ - !ruby/object:Gem::Version
96
+ version: '2.0'
83
97
  description: 'Epsagon provides tracing to Ruby applications for the collection of
84
98
  distributed tracing and performance metrics to simplify complex architectures, eliminate
85
99
  manual work, visualize and correlate data to identify and fix problems fast.
86
100
 
87
- '
101
+ '
88
102
  email: info@epsagon.com
89
103
  executables: []
90
104
  extensions: []
91
105
  extra_rdoc_files: []
92
106
  files:
107
+ - lib/arn_parser.rb
93
108
  - lib/epsagon.rb
94
109
  - lib/epsagon_constants.rb
95
110
  - lib/exporter_extension.rb
@@ -99,6 +114,7 @@ files:
99
114
  - lib/instrumentation/epsagon_rails_middleware.rb
100
115
  - lib/instrumentation/faraday.rb
101
116
  - lib/instrumentation/net_http.rb
117
+ - lib/instrumentation/postgres.rb
102
118
  - lib/instrumentation/rails.rb
103
119
  - lib/instrumentation/sinatra.rb
104
120
  - lib/instrumentation/version.rb
@@ -107,7 +123,7 @@ homepage: https://github.com/epsagon/epsagon-ruby
107
123
  licenses:
108
124
  - MIT
109
125
  metadata: {}
110
- post_install_message:
126
+ post_install_message:
111
127
  rdoc_options: []
112
128
  require_paths:
113
129
  - lib
@@ -122,8 +138,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
122
138
  - !ruby/object:Gem::Version
123
139
  version: '0'
124
140
  requirements: []
125
- rubygems_version: 3.1.4
126
- signing_key:
141
+ rubygems_version: 3.0.3
142
+ signing_key:
127
143
  specification_version: 4
128
144
  summary: Epsagon provides tracing to Ruby applications for the collection of distributed
129
145
  tracing and performance metrics.