activerecord-instrumentation 0.3.0.jlauer2 → 0.4.0.jlauer1

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: a4923138123e7321b389d97d69503b1fa5db021f5f50438209dbfe06f3942aa7
4
- data.tar.gz: f31bd6a40eedfdf3f10dfbfb147a9ac0e15a23f7382dd04b09e9bd6265f4aab0
3
+ metadata.gz: 48fc834ad963b8c31ea09c9974ca1d024a692a71592a20e75f0079c9a2c93203
4
+ data.tar.gz: 6be927a6854e55963f0fa1ab1ca0f5aa05c44e2e75d4eb8bebe7b3a459a00c9a
5
5
  SHA512:
6
- metadata.gz: 8bb7a590213347f0ea7f9da3e42addd4abd2d790fcfea5becba2acc964fc1188a46373dae31277dcc3f8eb9fade5faa24620cbafbd3031b84f153d6c14d8fa00
7
- data.tar.gz: 19998dd7f54661abb0d0e0530e962d95482c48543fabfc50f39c03f529fee299a48c24283ce2e49c6d190b82b820688584dbd95a6fb86b1a53b592c1ddf87b94
6
+ metadata.gz: f4980f5d2f6d3c2081c42b1c5a2761fa10470b820ac75db0d1eda27e2b85fc4d973ddf901b69acc0aa43d0ab09e688934f7b847c6ed2c354431fa73c4e76d2ab
7
+ data.tar.gz: 2be68549771581ee9e470bcc2664036206fbaa973d6adecdfef4b7f03993c3b2b9b8b45e170ed11da4293453925c3bdebd38192c00937edaa2ac555b15c4de63
@@ -22,7 +22,11 @@
22
22
  - "./spec/*_helper*.rb"
23
23
  - "./tasks/ci.rake"
24
24
  - "Gemfile"
25
-
25
+
26
+ Layout/LineLength:
27
+ Exclude:
28
+ - "./**/*_spec.rb"
29
+
26
30
  Metrics/ModuleLength:
27
31
  Exclude:
28
32
  - "./**/*_spec*.rb"
@@ -31,5 +35,5 @@
31
35
  Exclude:
32
36
  - "./**/*_spec*.rb"
33
37
 
34
- Rails/ApplicationRecord:
38
+ Rails:
35
39
  Enabled: false
@@ -1,7 +1,10 @@
1
1
  Changelog
2
2
  =========
3
3
 
4
- ## 0.3.0.jlauer2 04/22/2020
4
+ ## 0.4.0.jlauer1 04/24/2020
5
+ * Add SQL sanitizers
6
+
7
+ ## 0.3.0 04/22/2020
5
8
  * Set up build pipeline with circleci and gem-publisher
6
9
  * Fixed linting issues
7
10
  * Renamed gem to `activerecord-instrumentation`
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- activerecord-instrumentation (0.3.0.jlauer2)
4
+ activerecord-instrumentation (0.4.0.jlauer1)
5
5
  activerecord (~> 6.0)
6
6
  opentracing (~> 0.5)
7
7
 
@@ -5,11 +5,13 @@ require "opentracing"
5
5
 
6
6
  require "active_record/open_tracing/version"
7
7
  require "active_record/open_tracing/processor"
8
+ require "active_record/open_tracing/sql_sanitizer"
8
9
 
9
10
  module ActiveRecord
10
11
  module OpenTracing
11
- def self.instrument(tracer: ::OpenTracing.global_tracer)
12
- processor = Processor.new(tracer)
12
+ def self.instrument(tracer: ::OpenTracing.global_tracer, sanitizer: nil)
13
+ sql_sanitizer = sanitizer && SqlSanitizer.build_sanitizer(sanitizer)
14
+ processor = Processor.new(tracer, sanitizer: sql_sanitizer)
13
15
 
14
16
  ActiveSupport::Notifications.subscribe("sql.active_record") do |*args|
15
17
  processor.call(*args)
@@ -8,12 +8,15 @@ module ActiveRecord
8
8
  SPAN_KIND = "client"
9
9
  DB_TYPE = "sql"
10
10
 
11
- def initialize(tracer)
11
+ attr_reader :tracer, :sanitizer
12
+
13
+ def initialize(tracer, sanitizer: nil)
12
14
  @tracer = tracer
15
+ @sanitizer = sanitizer
13
16
  end
14
17
 
15
18
  def call(_event_name, start, finish, _id, payload)
16
- span = @tracer.start_span(
19
+ span = tracer.start_span(
17
20
  payload[:name] || DEFAULT_OPERATION_NAME,
18
21
  start_time: start,
19
22
  tags: tags_for_payload(payload)
@@ -45,12 +48,16 @@ module ActiveRecord
45
48
  "span.kind" => SPAN_KIND,
46
49
  "db.instance" => db_instance,
47
50
  "db.cached" => payload.fetch(:cached, false),
48
- "db.statement" => payload.fetch(:sql).squish,
51
+ "db.statement" => sanitize_sql(payload.fetch(:sql).squish),
49
52
  "db.type" => DB_TYPE,
50
53
  "peer.address" => db_address
51
54
  }
52
55
  end
53
56
 
57
+ def sanitize_sql(sql)
58
+ sanitizer ? sanitizer.sanitize(sql) : sql
59
+ end
60
+
54
61
  def db_instance
55
62
  @db_instance ||= db_config.fetch(:database)
56
63
  end
@@ -0,0 +1,37 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "active_record/open_tracing/sql_sanitizer/base"
4
+ require "active_record/open_tracing/sql_sanitizer/mysql"
5
+ require "active_record/open_tracing/sql_sanitizer/postgres"
6
+ require "active_record/open_tracing/sql_sanitizer/sql_server"
7
+ require "active_record/open_tracing/sql_sanitizer/sqlite"
8
+ require "active_record/open_tracing/sql_sanitizer/regexes"
9
+
10
+ module ActiveRecord
11
+ module OpenTracing
12
+ module SqlSanitizer
13
+ KLASSES = {
14
+ mysql: Mysql,
15
+ postgres: Postgres,
16
+ sql_server: SqlServer,
17
+ sqlite: Sqlite
18
+ }.freeze
19
+
20
+ class << self
21
+ def build_sanitizer(sanitizer_name)
22
+ sanitizer_klass(sanitizer_name).build
23
+ end
24
+
25
+ private
26
+
27
+ def sanitizer_klass(sanitizer_name)
28
+ key = KLASSES.keys.detect do |name|
29
+ sanitizer_name.to_sym == name
30
+ end || (raise NameError, "Unknown sanitizer #{sanitizer_name.inspect}")
31
+
32
+ KLASSES.fetch(key)
33
+ end
34
+ end
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,63 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ActiveRecord
4
+ module OpenTracing
5
+ module SqlSanitizer
6
+ class Base
7
+ require "active_record/open_tracing/sql_sanitizer/regexes"
8
+ include ActiveRecord::OpenTracing::SqlSanitizer::Regexes
9
+
10
+ def sanitize(sql)
11
+ scrubbed = scrub(sql.dup)
12
+ apply_substitutions(scrubbed)
13
+ end
14
+
15
+ private
16
+
17
+ def substitutions
18
+ raise NotImplementedError
19
+ end
20
+
21
+ def apply_substitutions(str)
22
+ substitutions.inject(str.dup) do |memo, (regex, replacement)|
23
+ if replacement.respond_to?(:call)
24
+ memo.gsub(regex, &replacement)
25
+ else
26
+ memo.gsub(regex, replacement)
27
+ end
28
+ end.strip
29
+ end
30
+
31
+ def encodings?(encodings = %w[UTF-8 binary])
32
+ encodings.all? do |enc|
33
+ begin
34
+ Encoding.find(enc)
35
+ rescue StandardError
36
+ false
37
+ end
38
+ end
39
+ end
40
+
41
+ MAX_SQL_LENGTH = 16384
42
+
43
+ def scrub(str)
44
+ # safeguard - don't sanitize or scrub large SQL statements
45
+ return "" if !str.is_a?(String) || str.length > MAX_SQL_LENGTH
46
+
47
+ # Whatever encoding it is, it is valid and we can operate on it
48
+ return str if str.valid_encoding?
49
+
50
+ # Prefer scrub over convert
51
+ if str.respond_to?(:scrub)
52
+ str.scrub("_")
53
+ elsif encodings?(%w[UTF-8 binary])
54
+ str.encode("UTF-8", "binary", invalid: :replace, undef: :replace, replace: "_")
55
+ else
56
+ # Unable to scrub invalid sql encoding, returning empty string
57
+ ""
58
+ end
59
+ end
60
+ end
61
+ end
62
+ end
63
+ end
@@ -0,0 +1,20 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ActiveRecord
4
+ module OpenTracing
5
+ module SqlSanitizer
6
+ class Mysql < Base
7
+ def substitutions
8
+ [
9
+ [MYSQL_VAR_INTERPOLATION, ""],
10
+ [MYSQL_REMOVE_SINGLE_QUOTE_STRINGS, "?"],
11
+ [MYSQL_REMOVE_DOUBLE_QUOTE_STRINGS, "?"],
12
+ [MYSQL_REMOVE_INTEGERS, "?"],
13
+ [MYSQL_IN_CLAUSE, "IN (?)"],
14
+ [MULTIPLE_QUESTIONS, "?"]
15
+ ]
16
+ end
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,20 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ActiveRecord
4
+ module OpenTracing
5
+ module SqlSanitizer
6
+ class Postgres < Base
7
+ def substitutions
8
+ [
9
+ [PSQL_PLACEHOLDER, "?"],
10
+ [PSQL_VAR_INTERPOLATION, ""],
11
+ [PSQL_AFTER_WHERE, ->(c) { c.gsub(PSQL_REMOVE_STRINGS, "?") }],
12
+ [PSQL_REMOVE_INTEGERS, "?"],
13
+ [PSQL_IN_CLAUSE, "IN (?)"],
14
+ [MULTIPLE_SPACES, " "]
15
+ ]
16
+ end
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,33 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ActiveRecord
4
+ module OpenTracing
5
+ module SqlSanitizer
6
+ module Regexes
7
+ MULTIPLE_SPACES = /\s+/.freeze
8
+ MULTIPLE_QUESTIONS = /\?(,\?)+/.freeze
9
+
10
+ PSQL_VAR_INTERPOLATION = /\[\[.*\]\]\s*$/.freeze
11
+ PSQL_REMOVE_STRINGS = /'(?:[^']|'')*'/.freeze
12
+ PSQL_REMOVE_INTEGERS = /(?<!LIMIT )\b\d+\b/.freeze
13
+ PSQL_PLACEHOLDER = /\$\d+/.freeze
14
+ PSQL_IN_CLAUSE = /IN\s+\(\?[^\)]*\)/.freeze
15
+ PSQL_AFTER_WHERE = /(?:WHERE\s+).*?(?:SELECT|$)/i.freeze
16
+
17
+ MYSQL_VAR_INTERPOLATION = /\[\[.*\]\]\s*$/.freeze
18
+ MYSQL_REMOVE_INTEGERS = /(?<!LIMIT )\b\d+\b/.freeze
19
+ MYSQL_REMOVE_SINGLE_QUOTE_STRINGS = /'(?:\\'|[^']|'')*'/.freeze
20
+ MYSQL_REMOVE_DOUBLE_QUOTE_STRINGS = /"(?:\\"|[^"]|"")*"/.freeze
21
+ MYSQL_IN_CLAUSE = /IN\s+\(\?[^\)]*\)/.freeze
22
+
23
+ SQLITE_VAR_INTERPOLATION = /\[\[.*\]\]\s*$/.freeze
24
+ SQLITE_REMOVE_STRINGS = /'(?:[^']|'')*'/.freeze
25
+ SQLITE_REMOVE_INTEGERS = /(?<!LIMIT )\b\d+\b/.freeze
26
+
27
+ SQLSERVER_EXECUTESQL = /EXEC sp_executesql N'(.*?)'.*/.freeze
28
+ SQLSERVER_REMOVE_INTEGERS = /(?<!LIMIT )\b(?<!@)\d+\b/.freeze
29
+ SQLSERVER_IN_CLAUSE = /IN\s+\(\?[^\)]*\)/.freeze
30
+ end
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ActiveRecord
4
+ module OpenTracing
5
+ module SqlSanitizer
6
+ class SqlServer < Base
7
+ def substitutions
8
+ [
9
+ [SQLSERVER_EXECUTESQL, '\1'],
10
+ [SQLSERVER_REMOVE_INTEGERS, "?"],
11
+ [SQLSERVER_IN_CLAUSE, "IN (?)"]
12
+ ]
13
+ end
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,18 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ActiveRecord
4
+ module OpenTracing
5
+ module SqlSanitizer
6
+ class Sqlite < Base
7
+ def substitutions
8
+ [
9
+ [SQLITE_VAR_INTERPOLATION, ""],
10
+ [SQLITE_REMOVE_STRINGS, "?"],
11
+ [SQLITE_REMOVE_INTEGERS, "?"],
12
+ [MULTIPLE_SPACES, " "]
13
+ ]
14
+ end
15
+ end
16
+ end
17
+ end
18
+ end
@@ -2,6 +2,6 @@
2
2
 
3
3
  module ActiveRecord
4
4
  module OpenTracing
5
- VERSION = "0.3.0.jlauer2"
5
+ VERSION = "0.4.0.jlauer1"
6
6
  end
7
7
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: activerecord-instrumentation
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.0.jlauer2
4
+ version: 0.4.0.jlauer1
5
5
  platform: ruby
6
6
  authors:
7
7
  - SaleMove TechMovers
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2020-04-22 00:00:00.000000000 Z
12
+ date: 2020-04-24 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: bundler
@@ -200,6 +200,13 @@ files:
200
200
  - activerecord-instrumentation.gemspec
201
201
  - lib/active_record/open_tracing.rb
202
202
  - lib/active_record/open_tracing/processor.rb
203
+ - lib/active_record/open_tracing/sql_sanitizer.rb
204
+ - lib/active_record/open_tracing/sql_sanitizer/base.rb
205
+ - lib/active_record/open_tracing/sql_sanitizer/mysql.rb
206
+ - lib/active_record/open_tracing/sql_sanitizer/postgres.rb
207
+ - lib/active_record/open_tracing/sql_sanitizer/regexes.rb
208
+ - lib/active_record/open_tracing/sql_sanitizer/sql_server.rb
209
+ - lib/active_record/open_tracing/sql_sanitizer/sqlite.rb
203
210
  - lib/active_record/open_tracing/version.rb
204
211
  homepage: https://github.com/doximity/ruby-activerecord-opentracing
205
212
  licenses: