epsagon 0.0.27 → 0.0.28
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/arn_parser.rb +27 -0
- data/lib/epsagon.rb +59 -35
- data/lib/epsagon_constants.rb +1 -1
- data/lib/instrumentation/epsagon_rails_middleware.rb +1 -1
- data/lib/instrumentation/postgres.rb +294 -0
- data/lib/util.rb +1 -5
- metadata +23 -7
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 1a17b55f2ce2ff35ca70dd51e8f8337041e202c528b6c691800d3e3b7b0d42c4
|
4
|
+
data.tar.gz: d93046c571faa2d35a681217cb12952c57c7bd3232e77a136a5954a5534541b1
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
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
|
-
|
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
|
-
|
47
|
+
end
|
41
48
|
|
42
|
-
|
43
|
-
|
44
|
-
|
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
|
-
|
50
|
-
|
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
|
-
|
53
|
-
|
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
|
-
|
67
|
-
configurator.use '
|
68
|
-
configurator.use '
|
69
|
-
configurator.use '
|
70
|
-
configurator.use '
|
71
|
-
configurator.use '
|
72
|
-
|
73
|
-
|
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
|
|
data/lib/epsagon_constants.rb
CHANGED
@@ -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
|
-
|
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.
|
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-
|
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.
|
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.
|