stackify-ruby-apm 1.10.2 → 1.13.2

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.
Files changed (44) hide show
  1. checksums.yaml +4 -4
  2. data/lib/stackify_apm/agent.rb +0 -2
  3. data/lib/stackify_apm/config.rb +36 -5
  4. data/lib/stackify_apm/context.rb +4 -1
  5. data/lib/stackify_apm/context/prefix.rb +30 -0
  6. data/lib/stackify_apm/context/request/headers.rb +30 -0
  7. data/lib/stackify_apm/context_builder.rb +1 -0
  8. data/lib/stackify_apm/helper/database_helper.rb +40 -1
  9. data/lib/stackify_apm/instrumenter_helper.rb +90 -4
  10. data/lib/stackify_apm/logger/logger_high_version.rb +5 -1
  11. data/lib/stackify_apm/logger/logger_lower_version.rb +5 -1
  12. data/lib/stackify_apm/middleware.rb +21 -3
  13. data/lib/stackify_apm/normalizers/active_record.rb +16 -8
  14. data/lib/stackify_apm/root_info.rb +7 -1
  15. data/lib/stackify_apm/serializers/transactions.rb +5 -0
  16. data/lib/stackify_apm/span/context.rb +42 -1
  17. data/lib/stackify_apm/spies.rb +4 -2
  18. data/lib/stackify_apm/spies/action_dispatch.rb +6 -1
  19. data/lib/stackify_apm/spies/curb.rb +41 -20
  20. data/lib/stackify_apm/spies/curb/easy.rb +220 -92
  21. data/lib/stackify_apm/spies/curb/multi.rb +26 -12
  22. data/lib/stackify_apm/spies/custom_instrumenter.rb +25 -4
  23. data/lib/stackify_apm/spies/delayed_job.rb +49 -0
  24. data/lib/stackify_apm/spies/dynamo_db.rb +50 -0
  25. data/lib/stackify_apm/spies/faraday.rb +87 -0
  26. data/lib/stackify_apm/spies/httparty.rb +45 -24
  27. data/lib/stackify_apm/spies/httpclient.rb +41 -20
  28. data/lib/stackify_apm/spies/httprb.rb +39 -18
  29. data/lib/stackify_apm/spies/log4r.rb +60 -0
  30. data/lib/stackify_apm/spies/logger.rb +117 -0
  31. data/lib/stackify_apm/spies/logging.rb +66 -0
  32. data/lib/stackify_apm/spies/net_http.rb +38 -20
  33. data/lib/stackify_apm/spies/redis.rb +36 -30
  34. data/lib/stackify_apm/spies/sequel.rb +28 -11
  35. data/lib/stackify_apm/spies/sinatra_activerecord/mysql_adapter.rb +27 -25
  36. data/lib/stackify_apm/spies/sinatra_activerecord/postgresql_adapter.rb +27 -24
  37. data/lib/stackify_apm/spies/sinatra_activerecord/sqlite_adapter.rb +18 -8
  38. data/lib/stackify_apm/spies/stackify_logger.rb +28 -16
  39. data/lib/stackify_apm/spies/sucker_punch.rb +39 -0
  40. data/lib/stackify_apm/spies/yell.rb +65 -0
  41. data/lib/stackify_apm/util.rb +10 -9
  42. data/lib/stackify_apm/version.rb +1 -1
  43. data/stackify-ruby-apm.gemspec +1 -0
  44. metadata +26 -2
@@ -2,6 +2,8 @@
2
2
 
3
3
  # Spies for active record when sinatra framework is used and active_record is being extended. (mysql adapter)
4
4
 
5
+ require 'stackify_apm/helper/database_helper'
6
+
5
7
  module StackifyRubyAPM
6
8
  # @api private
7
9
  module Spies
@@ -22,14 +24,10 @@ module StackifyRubyAPM
22
24
  exec_update_without_apm(sql, name, binds)
23
25
  end
24
26
 
25
- ctx = Span::Context.new(
26
- CATEGORY: 'Database',
27
- SUBCATEGORY: 'Execute',
28
- COMPONENT_CATEGORY: 'DB Query',
29
- COMPONENT_DETAIL: 'Execute SQL Query',
30
- SQL: sql,
31
- PROVIDER: 'mysql'
32
- )
27
+ payload = {sql: sql, binds: binds}
28
+ statement = query_variables(payload)
29
+ check_prepared_stmt(statement, payload)
30
+ ctx = Span::Context.new(statement)
33
31
 
34
32
  result = exec_update_without_apm(sql, name, binds)
35
33
 
@@ -45,14 +43,10 @@ module StackifyRubyAPM
45
43
  exec_delete_without_apm(sql, name, binds)
46
44
  end
47
45
 
48
- ctx = Span::Context.new(
49
- CATEGORY: 'Database',
50
- SUBCATEGORY: 'Execute',
51
- COMPONENT_CATEGORY: 'DB Query',
52
- COMPONENT_DETAIL: 'Execute SQL Query',
53
- SQL: sql,
54
- PROVIDER: 'mysql'
55
- )
46
+ payload = {sql: sql, binds: binds}
47
+ statement = query_variables(payload)
48
+ check_prepared_stmt(statement, payload)
49
+ ctx = Span::Context.new(statement)
56
50
 
57
51
  result = exec_delete_without_apm(sql, name, binds)
58
52
 
@@ -69,22 +63,30 @@ module StackifyRubyAPM
69
63
  exec_query_without_apm(sql, name, binds)
70
64
  end
71
65
 
72
- ctx = Span::Context.new(
73
- CATEGORY: 'Database',
74
- SUBCATEGORY: 'Execute',
75
- COMPONENT_CATEGORY: 'DB Query',
76
- COMPONENT_DETAIL: 'Execute SQL Query',
77
- SQL: sql,
78
- PROVIDER: 'mysql'
79
- )
66
+ payload = {sql: sql, binds: binds}
67
+ statement = query_variables(payload)
68
+ check_prepared_stmt(statement, payload)
69
+ ctx = Span::Context.new(statement)
80
70
 
81
71
  result = exec_query_without_apm(sql, name, binds)
82
-
83
72
  StackifyRubyAPM.span name, TYPE, context: ctx do
84
73
  return result
85
74
  end
86
75
  end
87
76
  # rubocop:enable Lint/UnusedMethodArgument
77
+
78
+ def query_variables(payload)
79
+ props = get_common_db_properties
80
+ props[:PROVIDER] = 'mysql'
81
+ props[:SQL] = payload[:sql]
82
+ props
83
+ end
84
+
85
+ def check_prepared_stmt(statement, payload)
86
+ if StackifyRubyAPM.agent.config.prefix_enabled
87
+ check_prepared_stmt_by_placeholder(payload[:sql].include?('?'), statement, payload)
88
+ end
89
+ end
88
90
  end
89
91
  end
90
92
  else
@@ -2,6 +2,8 @@
2
2
 
3
3
  # Spies for active record when sinatra framework is used and active_record is being extended. (mysql adapter)
4
4
 
5
+ require 'stackify_apm/helper/database_helper'
6
+
5
7
  module StackifyRubyAPM
6
8
  # @api private
7
9
  module Spies
@@ -22,15 +24,11 @@ module StackifyRubyAPM
22
24
  exec_update_without_apm(sql, name, binds)
23
25
  end
24
26
 
25
- ctx = Span::Context.new(
26
- CATEGORY: 'Database',
27
- SUBCATEGORY: 'Execute',
28
- COMPONENT_CATEGORY: 'DB Query',
29
- COMPONENT_DETAIL: 'Execute SQL Query',
30
- SQL: sql,
31
- PROVIDER: 'postgresql'
32
- )
27
+ payload = {sql: sql, binds: binds}
28
+ statement = query_variables(payload)
29
+ check_prepared_stmt(statement, payload)
33
30
 
31
+ ctx = Span::Context.new(statement)
34
32
  result = exec_update_without_apm(sql, name, binds)
35
33
 
36
34
  StackifyRubyAPM.span name, TYPE, context: ctx do
@@ -45,15 +43,11 @@ module StackifyRubyAPM
45
43
  exec_delete_without_apm(sql, name, binds)
46
44
  end
47
45
 
48
- ctx = Span::Context.new(
49
- CATEGORY: 'Database',
50
- SUBCATEGORY: 'Execute',
51
- COMPONENT_CATEGORY: 'DB Query',
52
- COMPONENT_DETAIL: 'Execute SQL Query',
53
- SQL: sql,
54
- PROVIDER: 'postgresql'
55
- )
46
+ payload = {sql: sql, binds: binds}
47
+ statement = query_variables(payload)
48
+ check_prepared_stmt(statement, payload)
56
49
 
50
+ ctx = Span::Context.new(statement)
57
51
  result = exec_delete_without_apm(sql, name, binds)
58
52
 
59
53
  StackifyRubyAPM.span name, TYPE, context: ctx do
@@ -69,15 +63,11 @@ module StackifyRubyAPM
69
63
  exec_query_without_apm(sql, name, binds)
70
64
  end
71
65
 
72
- ctx = Span::Context.new(
73
- CATEGORY: 'Database',
74
- SUBCATEGORY: 'Execute',
75
- COMPONENT_CATEGORY: 'DB Query',
76
- COMPONENT_DETAIL: 'Execute SQL Query',
77
- SQL: sql,
78
- PROVIDER: 'postgresql'
79
- )
66
+ payload = {sql: sql, binds: binds}
67
+ statement = query_variables(payload)
68
+ check_prepared_stmt(statement, payload)
80
69
 
70
+ ctx = Span::Context.new(statement)
81
71
  result = exec_query_without_apm(sql, name, binds)
82
72
 
83
73
  StackifyRubyAPM.span name, TYPE, context: ctx do
@@ -85,6 +75,19 @@ module StackifyRubyAPM
85
75
  end
86
76
  end
87
77
  # rubocop:enable Lint/UnusedMethodArgument
78
+
79
+ def query_variables(payload)
80
+ props = get_common_db_properties
81
+ props[:PROVIDER] = 'postgresql'
82
+ props[:SQL] = payload[:sql]
83
+ props
84
+ end
85
+
86
+ def check_prepared_stmt(statement, payload)
87
+ if StackifyRubyAPM.agent.config.prefix_enabled
88
+ check_prepared_stmt_by_placeholder(!!payload[:sql].match(/\$\d/), statement, payload)
89
+ end
90
+ end
88
91
  end
89
92
  end
90
93
  end
@@ -2,6 +2,8 @@
2
2
 
3
3
  # Spies for active record when sinatra framework is used and active_record is being extended. (mysql adapter)
4
4
 
5
+ require 'stackify_apm/helper/database_helper'
6
+
5
7
  module StackifyRubyAPM
6
8
  # @api private
7
9
  module Spies
@@ -21,15 +23,11 @@ module StackifyRubyAPM
21
23
  exec_query_without_apm(sql, name, binds)
22
24
  end
23
25
 
24
- ctx = Span::Context.new(
25
- CATEGORY: 'Database',
26
- SUBCATEGORY: 'Execute',
27
- COMPONENT_CATEGORY: 'DB Query',
28
- COMPONENT_DETAIL: 'Execute SQL Query',
29
- SQL: sql,
30
- PROVIDER: 'generic'
31
- )
26
+ payload = {sql: sql, binds: binds}
27
+ statement = query_variables(payload)
28
+ check_prepared_stmt(statement, payload)
32
29
 
30
+ ctx = Span::Context.new(statement)
33
31
  result = exec_query_without_apm(sql, name, binds)
34
32
 
35
33
  StackifyRubyAPM.span name, TYPE, context: ctx do
@@ -37,6 +35,18 @@ module StackifyRubyAPM
37
35
  end
38
36
  end
39
37
  # rubocop:enable Lint/UnusedMethodArgument
38
+
39
+ def query_variables(payload)
40
+ props = get_common_db_properties
41
+ props[:SQL] = payload[:sql]
42
+ props
43
+ end
44
+
45
+ def check_prepared_stmt(statement, payload)
46
+ if StackifyRubyAPM.agent.config.prefix_enabled
47
+ check_prepared_stmt_by_placeholder(payload[:sql].include?('?'), statement, payload)
48
+ end
49
+ end
40
50
  end
41
51
  end
42
52
  end
@@ -14,15 +14,21 @@ module StackifyRubyAPM
14
14
  def log_message_task(level, msg, call_trace)
15
15
  return log_message_task_without_apm(level, msg, call_trace) unless StackifyRubyAPM.current_transaction
16
16
 
17
- trans_id = StackifyRubyAPM.current_transaction.id
18
- log_uuid = SecureRandom.uuid
17
+ begin
18
+ trans_id = StackifyRubyAPM.current_transaction.id
19
+ log_uuid = SecureRandom.uuid
19
20
 
20
- # build span context
21
- ctx = Span::Context.new(
22
- CATEGORY: 'Stackify',
23
- SUBCATEGORY: 'Log',
24
- ID: log_uuid # matching the MsgObject id
25
- )
21
+ # build span context
22
+ ctx = Span::Context.new(
23
+ CATEGORY: 'Stackify',
24
+ SUBCATEGORY: 'Log',
25
+ ID: log_uuid # matching the MsgObject id
26
+ )
27
+ rescue Exception => e
28
+ StackifyRubyAPM.agent.error "[StackifyLoggerSpy] Error: creating span context."
29
+ StackifyRubyAPM.agent.error "[StackifyLoggerSpy] #{e.inspect}"
30
+ return log_message_task_without_apm(level, msg, call_trace)
31
+ end
26
32
 
27
33
  # create log span
28
34
  StackifyRubyAPM.span(msg, 'stackify.log', context: ctx) do
@@ -34,15 +40,21 @@ module StackifyRubyAPM
34
40
  def log_exception_task(level, ex)
35
41
  return log_exception_task_without_apm(level, ex) unless StackifyRubyAPM.current_transaction
36
42
 
37
- trans_id = StackifyRubyAPM.agent.current_transaction.id
38
- log_uuid = SecureRandom.uuid
43
+ begin
44
+ trans_id = StackifyRubyAPM.agent.current_transaction.id
45
+ log_uuid = SecureRandom.uuid
39
46
 
40
- # build span context
41
- ctx = Span::Context.new(
42
- CATEGORY: 'Stackify',
43
- SUBCATEGORY: 'Log',
44
- ID: log_uuid # matching the MsgObject id
45
- )
47
+ # build span context
48
+ ctx = Span::Context.new(
49
+ CATEGORY: 'Stackify',
50
+ SUBCATEGORY: 'Log',
51
+ ID: log_uuid # matching the MsgObject id
52
+ )
53
+ rescue Exception => e
54
+ StackifyRubyAPM.agent.error "[StackifyLoggerSpy] Error: creating span context."
55
+ StackifyRubyAPM.agent.error "[StackifyLoggerSpy] #{e.inspect}"
56
+ return log_exception_task_without_apm(level, ex)
57
+ end
46
58
 
47
59
  # create log span
48
60
  StackifyRubyAPM.span(ex.message, 'stackify.log', context: ctx) do
@@ -0,0 +1,39 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Monkey patch for the sucker_punch class for running async tasks.
4
+ #
5
+
6
+ module StackifyRubyAPM
7
+ # @api private
8
+ module Spies
9
+ # @api private
10
+ class SuckerPunchSpy
11
+ def install
12
+ SuckerPunch::Job::ClassMethods.class_eval do
13
+ alias_method '__run_perform_without_elastic_apm', '__run_perform'
14
+
15
+ def __run_perform(*args)
16
+ ret = nil
17
+ begin
18
+ name = "#{to_s}.perform"
19
+ ctx = StackifyRubyAPM::Context.new
20
+ ctx.category = 'SuckerPunch::Job'
21
+ transaction = StackifyRubyAPM.transaction name, 'TASK', context: ctx
22
+ ret = __run_perform_without_elastic_apm(*args)
23
+ rescue StackifyRubyAPM::InternalError
24
+ raise # Don't report StackifyRubyAPM errors
25
+ rescue StandardError => e
26
+ StackifyRubyAPM.report e
27
+ raise e
28
+ ensure
29
+ transaction.submit()
30
+ end
31
+ ret
32
+ end
33
+ end
34
+ end
35
+ end
36
+
37
+ register 'SuckerPunch', 'sucker_punch', SuckerPunchSpy.new
38
+ end
39
+ end
@@ -0,0 +1,65 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Monkey patch for the Yell::Logger class for logging log messages.
4
+ #
5
+ module StackifyRubyAPM
6
+ # @api private
7
+ module Spies
8
+ # @api private
9
+ class YellSpy
10
+ SEVERITIES = ['DEBUG', 'INFO', 'WARN', 'ERROR', 'FATAL', 'UNKNOWN'].freeze
11
+
12
+ def install
13
+ Yell::Logger.module_eval do
14
+ alias_method 'add_without_apm', 'add'
15
+
16
+ # Log messages
17
+ def add(options, *messages, &block)
18
+ return add_without_apm(options, *messages, &block) unless StackifyRubyAPM.current_transaction
19
+
20
+ begin
21
+ name = 'yell;'
22
+ type = 'ext.yell'
23
+ log_message = []
24
+ exception = []
25
+
26
+ messages.each { |msg|
27
+ case msg
28
+ when ::String
29
+ log_message.push(msg)
30
+ when ::Exception
31
+ log_message.push(msg.message)
32
+ exception.push("(#{ msg.class })\n#{ msg.backtrace.join("\n") if msg.backtrace }")
33
+ else
34
+ log_message.push(msg.inspect)
35
+ end
36
+ }
37
+
38
+ ctx = Span::Context.new(
39
+ CATEGORY: 'Log',
40
+ SUBCATEGORY: 'Yell',
41
+ LEVEL: SEVERITIES[options.severity],
42
+ MESSAGE: log_message.to_s,
43
+ PREFIX: 'TRUE'
44
+ )
45
+
46
+ if exception.length > 0
47
+ ctx.EXCEPTION = exception.to_s
48
+ end
49
+ rescue Exception => e
50
+ StackifyRubyAPM.agent.error "[YellSpy] Error: creating span context."
51
+ StackifyRubyAPM.agent.error "[YellSpy] #{e.inspect}"
52
+ return add_without_apm(options, *messages, &block)
53
+ end
54
+
55
+ StackifyRubyAPM.span name, type, context: ctx do
56
+ add_without_apm(options, *messages, &block)
57
+ end
58
+ end
59
+ end
60
+ end
61
+ end
62
+
63
+ register 'Yell', 'yell', YellSpy.new
64
+ end
65
+ end
@@ -8,15 +8,6 @@ module StackifyRubyAPM
8
8
  target.to_i * 1_000_000 + target.usec
9
9
  end
10
10
 
11
- #
12
- # This method will check if there is any rake task is running.
13
- # If rake task is detected we set instrument=false and don't load the spies.
14
- #
15
- def self.apm_disabled_in_rake
16
- cmd_rake = ($PROGRAM_NAME =~ /rake$/)
17
- StackifyRubyAPM.agent.config.instrument = false if cmd_rake
18
- end
19
-
20
11
  def self.host_os
21
12
  host_os = RbConfig::CONFIG['host_os']
22
13
  case host_os
@@ -34,6 +25,16 @@ module StackifyRubyAPM
34
25
  "UNKNOWN #{host_os}"
35
26
  end
36
27
  end
28
+
29
+ # Push the element to existing array of object with incremented index(key/value pair)
30
+ # We get the prepared statement values ['J.K. Rowling', 'Harry Potter', ...] and restructure it.
31
+ # Example structured: [{'1': 'J.K. Rowling'},{'2': 'Harry Potter'}, ..., {n: 'other data'}]
32
+ def self.pushToAryIndex(ary, idx, val)
33
+ obj = {}
34
+ i = idx + 1
35
+ obj[i] = val.to_s
36
+ ary.push(obj)
37
+ end
37
38
  end
38
39
  end
39
40
  require 'stackify_apm/util/inspector'
@@ -2,5 +2,5 @@
2
2
 
3
3
  # Sets the version of the APM
4
4
  module StackifyRubyAPM
5
- VERSION = '1.10.2'.freeze
5
+ VERSION = '1.13.2'.freeze
6
6
  end
@@ -54,6 +54,7 @@ Gem::Specification.new do |spec|
54
54
  spec.add_development_dependency 'timecop'
55
55
  spec.add_development_dependency 'to_bool'
56
56
  spec.add_development_dependency 'webmock'
57
+ spec.add_development_dependency 'delayed_job'
57
58
 
58
59
  spec.add_dependency('concurrent-ruby', '~> 1.0')
59
60
  spec.add_dependency('delegate_matcher', '~> 0.4')
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: stackify-ruby-apm
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.10.2
4
+ version: 1.13.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Stackify
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2020-05-18 00:00:00.000000000 Z
11
+ date: 2020-09-01 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rails
@@ -332,6 +332,20 @@ dependencies:
332
332
  - - ">="
333
333
  - !ruby/object:Gem::Version
334
334
  version: '0'
335
+ - !ruby/object:Gem::Dependency
336
+ name: delayed_job
337
+ requirement: !ruby/object:Gem::Requirement
338
+ requirements:
339
+ - - ">="
340
+ - !ruby/object:Gem::Version
341
+ version: '0'
342
+ type: :development
343
+ prerelease: false
344
+ version_requirements: !ruby/object:Gem::Requirement
345
+ requirements:
346
+ - - ">="
347
+ - !ruby/object:Gem::Version
348
+ version: '0'
335
349
  - !ruby/object:Gem::Dependency
336
350
  name: concurrent-ruby
337
351
  requirement: !ruby/object:Gem::Requirement
@@ -419,7 +433,9 @@ files:
419
433
  - lib/stackify_apm/agent.rb
420
434
  - lib/stackify_apm/config.rb
421
435
  - lib/stackify_apm/context.rb
436
+ - lib/stackify_apm/context/prefix.rb
422
437
  - lib/stackify_apm/context/request.rb
438
+ - lib/stackify_apm/context/request/headers.rb
423
439
  - lib/stackify_apm/context/request/socket.rb
424
440
  - lib/stackify_apm/context/request/url.rb
425
441
  - lib/stackify_apm/context/response.rb
@@ -457,9 +473,15 @@ files:
457
473
  - lib/stackify_apm/spies/curb/easy.rb
458
474
  - lib/stackify_apm/spies/curb/multi.rb
459
475
  - lib/stackify_apm/spies/custom_instrumenter.rb
476
+ - lib/stackify_apm/spies/delayed_job.rb
477
+ - lib/stackify_apm/spies/dynamo_db.rb
478
+ - lib/stackify_apm/spies/faraday.rb
460
479
  - lib/stackify_apm/spies/httparty.rb
461
480
  - lib/stackify_apm/spies/httpclient.rb
462
481
  - lib/stackify_apm/spies/httprb.rb
482
+ - lib/stackify_apm/spies/log4r.rb
483
+ - lib/stackify_apm/spies/logger.rb
484
+ - lib/stackify_apm/spies/logging.rb
463
485
  - lib/stackify_apm/spies/mongo.rb
464
486
  - lib/stackify_apm/spies/net_http.rb
465
487
  - lib/stackify_apm/spies/redis.rb
@@ -470,7 +492,9 @@ files:
470
492
  - lib/stackify_apm/spies/sinatra_activerecord/postgresql_adapter.rb
471
493
  - lib/stackify_apm/spies/sinatra_activerecord/sqlite_adapter.rb
472
494
  - lib/stackify_apm/spies/stackify_logger.rb
495
+ - lib/stackify_apm/spies/sucker_punch.rb
473
496
  - lib/stackify_apm/spies/tilt.rb
497
+ - lib/stackify_apm/spies/yell.rb
474
498
  - lib/stackify_apm/stacktrace.rb
475
499
  - lib/stackify_apm/stacktrace/frame.rb
476
500
  - lib/stackify_apm/stacktrace_builder.rb