influx_reporter 1.0.0

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 (103) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +7 -0
  3. data/.rspec +2 -0
  4. data/.rubocop.yml +51 -0
  5. data/.travis.yml +42 -0
  6. data/.yardopts +3 -0
  7. data/Dockerfile +9 -0
  8. data/Gemfile +7 -0
  9. data/HISTORY.md +1 -0
  10. data/LICENSE +14 -0
  11. data/README.md +189 -0
  12. data/Rakefile +27 -0
  13. data/gemfiles/Gemfile.base +29 -0
  14. data/gemfiles/Gemfile.rails-3.2.x +4 -0
  15. data/gemfiles/Gemfile.rails-4.0.x +4 -0
  16. data/gemfiles/Gemfile.rails-4.1.x +4 -0
  17. data/gemfiles/Gemfile.rails-4.2.x +5 -0
  18. data/gemfiles/Gemfile.rails-5.0.x +5 -0
  19. data/gemfiles/Gemfile.rails-HEAD +7 -0
  20. data/influx_reporter.gemspec +26 -0
  21. data/lib/influx_reporter.rb +142 -0
  22. data/lib/influx_reporter/client.rb +306 -0
  23. data/lib/influx_reporter/configuration.rb +88 -0
  24. data/lib/influx_reporter/data_builders.rb +18 -0
  25. data/lib/influx_reporter/data_builders/error.rb +52 -0
  26. data/lib/influx_reporter/data_builders/transactions.rb +120 -0
  27. data/lib/influx_reporter/error.rb +7 -0
  28. data/lib/influx_reporter/error_message.rb +85 -0
  29. data/lib/influx_reporter/error_message/exception.rb +14 -0
  30. data/lib/influx_reporter/error_message/http.rb +73 -0
  31. data/lib/influx_reporter/error_message/stacktrace.rb +76 -0
  32. data/lib/influx_reporter/error_message/user.rb +25 -0
  33. data/lib/influx_reporter/filter.rb +66 -0
  34. data/lib/influx_reporter/http_client.rb +140 -0
  35. data/lib/influx_reporter/influx_db_client.rb +74 -0
  36. data/lib/influx_reporter/injections.rb +89 -0
  37. data/lib/influx_reporter/injections/json.rb +21 -0
  38. data/lib/influx_reporter/injections/net_http.rb +50 -0
  39. data/lib/influx_reporter/injections/redis.rb +25 -0
  40. data/lib/influx_reporter/injections/sequel.rb +37 -0
  41. data/lib/influx_reporter/injections/sinatra.rb +59 -0
  42. data/lib/influx_reporter/integration/delayed_job.rb +30 -0
  43. data/lib/influx_reporter/integration/rails/inject_exceptions_catcher.rb +25 -0
  44. data/lib/influx_reporter/integration/railtie.rb +56 -0
  45. data/lib/influx_reporter/integration/resque.rb +18 -0
  46. data/lib/influx_reporter/integration/sidekiq.rb +130 -0
  47. data/lib/influx_reporter/line_cache.rb +21 -0
  48. data/lib/influx_reporter/logging.rb +39 -0
  49. data/lib/influx_reporter/middleware.rb +63 -0
  50. data/lib/influx_reporter/normalizers.rb +65 -0
  51. data/lib/influx_reporter/normalizers/action_controller.rb +34 -0
  52. data/lib/influx_reporter/normalizers/action_view.rb +72 -0
  53. data/lib/influx_reporter/normalizers/active_record.rb +45 -0
  54. data/lib/influx_reporter/sql_summarizer.rb +31 -0
  55. data/lib/influx_reporter/subscriber.rb +80 -0
  56. data/lib/influx_reporter/tasks.rb +28 -0
  57. data/lib/influx_reporter/trace.rb +48 -0
  58. data/lib/influx_reporter/trace_helpers.rb +31 -0
  59. data/lib/influx_reporter/transaction.rb +114 -0
  60. data/lib/influx_reporter/util.rb +18 -0
  61. data/lib/influx_reporter/util/constantize.rb +56 -0
  62. data/lib/influx_reporter/util/inspector.rb +72 -0
  63. data/lib/influx_reporter/util/timestamp.rb +11 -0
  64. data/lib/influx_reporter/version.rb +5 -0
  65. data/lib/influx_reporter/worker.rb +56 -0
  66. data/spec/influx_reporter/client_spec.rb +264 -0
  67. data/spec/influx_reporter/configuration_spec.rb +42 -0
  68. data/spec/influx_reporter/data_builders/error_spec.rb +40 -0
  69. data/spec/influx_reporter/data_builders/transactions_spec.rb +48 -0
  70. data/spec/influx_reporter/error_message/exception_spec.rb +22 -0
  71. data/spec/influx_reporter/error_message/http_spec.rb +55 -0
  72. data/spec/influx_reporter/error_message/stacktrace_spec.rb +56 -0
  73. data/spec/influx_reporter/error_message/user_spec.rb +26 -0
  74. data/spec/influx_reporter/error_message_spec.rb +102 -0
  75. data/spec/influx_reporter/filter_spec.rb +33 -0
  76. data/spec/influx_reporter/injections/net_http_spec.rb +35 -0
  77. data/spec/influx_reporter/injections/sequel_spec.rb +33 -0
  78. data/spec/influx_reporter/injections/sinatra_spec.rb +13 -0
  79. data/spec/influx_reporter/injections_spec.rb +50 -0
  80. data/spec/influx_reporter/integration/delayed_job_spec.rb +37 -0
  81. data/spec/influx_reporter/integration/json_spec.rb +41 -0
  82. data/spec/influx_reporter/integration/rails_spec.rb +92 -0
  83. data/spec/influx_reporter/integration/redis_spec.rb +20 -0
  84. data/spec/influx_reporter/integration/resque_spec.rb +42 -0
  85. data/spec/influx_reporter/integration/sidekiq_spec.rb +40 -0
  86. data/spec/influx_reporter/integration/sinatra_spec.rb +99 -0
  87. data/spec/influx_reporter/line_cache_spec.rb +38 -0
  88. data/spec/influx_reporter/logging_spec.rb +49 -0
  89. data/spec/influx_reporter/middleware_spec.rb +32 -0
  90. data/spec/influx_reporter/normalizers/action_controller_spec.rb +37 -0
  91. data/spec/influx_reporter/normalizers/action_view_spec.rb +78 -0
  92. data/spec/influx_reporter/normalizers/active_record_spec.rb +70 -0
  93. data/spec/influx_reporter/normalizers_spec.rb +16 -0
  94. data/spec/influx_reporter/sql_summarizer_spec.rb +35 -0
  95. data/spec/influx_reporter/subscriber_spec.rb +83 -0
  96. data/spec/influx_reporter/trace_spec.rb +43 -0
  97. data/spec/influx_reporter/transaction_spec.rb +98 -0
  98. data/spec/influx_reporter/util/inspector_spec.rb +41 -0
  99. data/spec/influx_reporter/util_spec.rb +20 -0
  100. data/spec/influx_reporter/worker_spec.rb +54 -0
  101. data/spec/influx_reporter_spec.rb +50 -0
  102. data/spec/spec_helper.rb +86 -0
  103. metadata +188 -0
@@ -0,0 +1,21 @@
1
+ # frozen_string_literal: true
2
+
3
+ module InfluxReporter
4
+ module Injections
5
+ module JSON
6
+ class Injector
7
+ def install
8
+ ::JSON.class_eval do
9
+ include TraceHelpers
10
+
11
+ trace_class_method :parse, 'JSON#parse', 'json.parse'
12
+ trace_class_method :parse!, 'JSON#parse!', 'json.parse'
13
+ trace_class_method :generate, 'JSON#generate', 'json.generate'
14
+ end
15
+ end
16
+ end
17
+ end
18
+
19
+ register 'JSON', 'json', JSON::Injector.new
20
+ end
21
+ end
@@ -0,0 +1,50 @@
1
+ # frozen_string_literal: true
2
+
3
+ module InfluxReporter
4
+ module Injections
5
+ module NetHTTP
6
+ class Injector
7
+ def install
8
+ Net::HTTP.class_eval do
9
+ alias_method :request_without_opb, :request
10
+
11
+ def request(req, body = nil, &block)
12
+ unless InfluxReporter.started?
13
+ return request_without_opb req, body, &block
14
+ end
15
+
16
+ host, port = req['host']&.split(':')
17
+ method = req.method
18
+ path = req.path
19
+ scheme = use_ssl? ? 'https' : 'http'
20
+
21
+ # inside a session
22
+ host ||= address
23
+ port ||= use_ssl? ? 443 : 80
24
+
25
+ extra = {
26
+ tags: {
27
+ scheme: scheme,
28
+ port: port,
29
+ method: method
30
+ },
31
+ values: {
32
+ path: path
33
+ }
34
+ }
35
+
36
+ signature = host
37
+ kind = 'ext.net_http'
38
+
39
+ InfluxReporter.trace signature, kind, extra do
40
+ request_without_opb(req, body, &block)
41
+ end
42
+ end
43
+ end
44
+ end
45
+ end
46
+ end
47
+
48
+ register 'Net::HTTP', 'net/http', NetHTTP::Injector.new
49
+ end
50
+ end
@@ -0,0 +1,25 @@
1
+ # frozen_string_literal: true
2
+
3
+ module InfluxReporter
4
+ module Injections
5
+ module Redis
6
+ class Injector
7
+ def install
8
+ ::Redis::Client.class_eval do
9
+ alias_method :call_without_influx_reporter, :call
10
+
11
+ def call(command, &block)
12
+ signature = command[0]
13
+
14
+ InfluxReporter.trace signature.to_s, 'cache.redis' do
15
+ call_without_influx_reporter(command, &block)
16
+ end
17
+ end
18
+ end
19
+ end
20
+ end
21
+ end
22
+
23
+ register 'Redis', 'redis', Redis::Injector.new
24
+ end
25
+ end
@@ -0,0 +1,37 @@
1
+ # frozen_string_literal: true
2
+
3
+ module InfluxReporter
4
+ module Injections
5
+ module Sequel
6
+ class Injector
7
+ KIND = 'db.sequel.sql'
8
+
9
+ def self.sql_parser
10
+ @sql_parser ||= SqlSummarizer.new(nil)
11
+ end
12
+
13
+ def install
14
+ require 'sequel/database/logging'
15
+
16
+ log_method = ::Sequel::Database.method_defined?(:log_connection_yield) ?
17
+ 'log_connection_yield' : 'log_yield'
18
+
19
+ ::Sequel::Database.class_eval <<-end_eval
20
+ alias #{log_method}_without_opb #{log_method}
21
+
22
+ def #{log_method} sql, *args, &block
23
+ #{log_method}_without_opb(sql, *args) do
24
+ sig = InfluxReporter::Injections::Sequel::Injector.sql_parser.signature_for(sql)
25
+ InfluxReporter.trace(sig, KIND, sql: sql) do
26
+ block.call
27
+ end
28
+ end
29
+ end
30
+ end_eval
31
+ end
32
+ end
33
+ end
34
+
35
+ register 'Sequel', 'sequel', Sequel::Injector.new
36
+ end
37
+ end
@@ -0,0 +1,59 @@
1
+ # frozen_string_literal: true
2
+
3
+ module InfluxReporter
4
+ module Injections
5
+ module Sinatra
6
+ class Injector
7
+ def install
8
+ ::Sinatra::Base.class_eval do
9
+ alias_method :dispatch_without_opb!, :dispatch!
10
+ alias_method :compile_template_with_opb, :compile_template
11
+
12
+ def dispatch!(*args, &block)
13
+ dispatch_without_opb!(*args, &block).tap do
14
+ transaction = InfluxReporter.transaction(nil)
15
+ if (route = env['sinatra.route']) && transaction
16
+ transaction.endpoint = route
17
+ end
18
+ end
19
+ end
20
+
21
+ def compile_template(engine, data, opts, *args, &block)
22
+ opts[:__influx_reporter_template_sig] = case data
23
+ when Symbol
24
+ data.to_s
25
+ else
26
+ "Inline #{engine}"
27
+ end
28
+
29
+ compile_template_with_opb(engine, data, opts, *args, &block)
30
+ end
31
+ end
32
+ end
33
+ end
34
+ end
35
+
36
+ module Tilt
37
+ class Injector
38
+ KIND = 'template.view'
39
+
40
+ def install
41
+ ::Tilt::Template.class_eval do
42
+ alias_method :render_without_opb, :render
43
+
44
+ def render(*args, &block)
45
+ sig = options[:__influx_reporter_template_sig] || 'Unknown template'
46
+
47
+ InfluxReporter.trace sig, KIND do
48
+ render_without_opb(*args, &block)
49
+ end
50
+ end
51
+ end
52
+ end
53
+ end
54
+ end
55
+
56
+ register 'Sinatra::Base', 'sinatra/base', Sinatra::Injector.new
57
+ register 'Tilt::Template', 'tilt/template', Tilt::Injector.new
58
+ end
59
+ end
@@ -0,0 +1,30 @@
1
+ # frozen_string_literal: true
2
+
3
+ begin
4
+ require 'active_support'
5
+ require 'delayed_job'
6
+ rescue LoadError
7
+ end
8
+
9
+ if defined?(Delayed)
10
+ module Delayed
11
+ module Plugins
12
+ class InfluxReporter < Delayed::Plugin
13
+ callbacks do |lifecycle|
14
+ lifecycle.around(:invoke_job) do |job, *args, &block|
15
+ begin
16
+ block.call(job, *args)
17
+ rescue ::InfluxReporter::Error
18
+ raise # don't report InfluxReporter errors
19
+ rescue Exception => exception
20
+ ::InfluxReporter.report exception
21
+ raise
22
+ end
23
+ end
24
+ end
25
+ end
26
+ end
27
+ end
28
+
29
+ Delayed::Worker.plugins << Delayed::Plugins::InfluxReporter
30
+ end
@@ -0,0 +1,25 @@
1
+ # frozen_string_literal: true
2
+
3
+ module InfluxReporter
4
+ module Integration
5
+ module Rails
6
+ module InjectExceptionsCatcher
7
+ def self.included(cls)
8
+ cls.send(:alias_method, :render_exception_without_influx_reporter, :render_exception)
9
+ cls.send(:alias_method, :render_exception, :render_exception_with_influx_reporter)
10
+ end
11
+
12
+ def render_exception_with_influx_reporter(env, exception)
13
+ begin
14
+ InfluxReporter.report(exception, tags: { rack_env: env }) if InfluxReporter.started?
15
+ rescue
16
+ ::Rails.logger.error "** [InfluxReporter] Error capturing or sending exception #{$ERROR_INFO}"
17
+ ::Rails.logger.debug $ERROR_INFO.backtrace.join("\n")
18
+ end
19
+
20
+ render_exception_without_influx_reporter(env, exception)
21
+ end
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,56 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'influx_reporter'
4
+ require 'rails'
5
+
6
+ module InfluxReporter
7
+ class Railtie < Rails::Railtie
8
+ config.influx_reporter = ActiveSupport::OrderedOptions.new
9
+ # bootstrap options with the defaults
10
+ Configuration::DEFAULTS.each { |k, v| config.influx_reporter[k] = v }
11
+
12
+ initializer 'influx_reporter.configure' do |app|
13
+ config = Configuration.new app.config.influx_reporter do |conf|
14
+ conf.logger = Rails.logger
15
+ conf.view_paths = app.config.paths['app/views'].existent
16
+ conf.tags[:environment] = Rails.env
17
+ end
18
+
19
+ if config.enabled_environments.include?(Rails.env)
20
+ if InfluxReporter.start!(config)
21
+ app.config.middleware.insert 0, Middleware
22
+ Rails.logger.info '** [InfluxReporter] Client running'
23
+ else
24
+ # :nocov:
25
+ Rails.logger.info '** [InfluxReporter] Failed to start'
26
+ # :nocov:
27
+ end
28
+ else
29
+ # :nocov:
30
+ Rails.logger.info "** [InfluxReporter] Disabled in #{Rails.env} environment"
31
+ # :nocov:
32
+ end
33
+ end
34
+
35
+ config.after_initialize do
36
+ # :nocov:
37
+ require 'influx_reporter/integration/rails/inject_exceptions_catcher'
38
+ if defined?(ActionDispatch::DebugExceptions)
39
+ ActionDispatch::DebugExceptions.send(
40
+ :include, InfluxReporter::Integration::Rails::InjectExceptionsCatcher
41
+ )
42
+ elsif defined?(::ActionDispatch::ShowExceptions)
43
+ ::ActionDispatch::ShowExceptions.send(
44
+ :include, InfluxReporter::Integration::Rails::InjectExceptionsCatcher
45
+ )
46
+ end
47
+ # :nocov:
48
+ end
49
+
50
+ rake_tasks do
51
+ # :nocov:
52
+ require 'influx_reporter/tasks'
53
+ # :nocov:
54
+ end
55
+ end
56
+ end
@@ -0,0 +1,18 @@
1
+ # frozen_string_literal: true
2
+
3
+ begin
4
+ require 'resque'
5
+ rescue LoadError
6
+ end
7
+
8
+ if defined? Resque
9
+ module InfluxReporter
10
+ module Integration
11
+ class Resque < Resque::Failure::Base
12
+ def save
13
+ InfluxReporter.report exception
14
+ end
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,130 @@
1
+ # frozen_string_literal: true
2
+
3
+ begin
4
+ require 'sidekiq'
5
+ rescue LoadError
6
+ end
7
+
8
+ if defined? Sidekiq
9
+ module InfluxReporter
10
+ module Integration
11
+ class SidekiqException
12
+
13
+ def call(worker, item, queue)
14
+ InfluxReporter.set_context tags: { sidekiq_queue: queue }
15
+ yield
16
+ rescue Exception => exception
17
+ if [Interrupt, SystemExit, SignalException].include? exception.class
18
+ raise exception
19
+ end
20
+
21
+ InfluxReporter.report exception
22
+
23
+ raise
24
+ end
25
+ end
26
+
27
+ class Sidekiq
28
+ KIND = 'worker.sidekiq'.freeze
29
+ PART_KIND = 'worker.sidekiq.part'
30
+ PERFORM_TRACE = 'perform'.freeze
31
+ PERFORM_KIND = 'app.worker.perform'.freeze
32
+
33
+
34
+ def call(worker, item, queue)
35
+ performance_trace(worker, item, queue) do
36
+ yield
37
+ end
38
+ end
39
+
40
+ private
41
+
42
+ def performance_trace(worker, item, queue)
43
+ return yield unless worker.class.performance_trace?
44
+
45
+ transaction = InfluxReporter.transaction get_worker_name(worker, item), KIND
46
+ transaction.extra_tags do |extra|
47
+ extra[:sidekiq_queue] = queue
48
+ end
49
+ response_code = 500
50
+ trace = transaction&.trace PERFORM_TRACE, PERFORM_KIND
51
+
52
+ begin
53
+ yield
54
+ response_code = 200
55
+ ensure
56
+ InfluxReporter::Client.inst.current_transaction = nil
57
+ trace&.done
58
+ transaction&.submit(response_code)
59
+ end
60
+ InfluxReporter.flush_transactions_if_needed
61
+ end
62
+
63
+ def get_worker_name(worker, item)
64
+ item['wrapped'.freeze] || worker.class.to_s
65
+ end
66
+ end
67
+ end
68
+ end
69
+
70
+ module Sidekiq::Worker
71
+ def with_performance_trace
72
+ unless InfluxReporter::Client.inst
73
+ return yield
74
+ end
75
+ caller = caller_locations(1,1)[0].label
76
+ parent_transaction = InfluxReporter::Client.inst.current_transaction
77
+ InfluxReporter::Client.inst.current_transaction = nil
78
+ transaction = InfluxReporter::Client.inst.transaction "#{self.class}##{caller}", InfluxReporter::Integration::Sidekiq::PART_KIND
79
+ InfluxReporter::Client.inst.current_transaction = transaction
80
+ begin
81
+ result = yield
82
+ ensure
83
+ transaction.submit if transaction
84
+ InfluxReporter::Client.inst.current_transaction = parent_transaction
85
+ end
86
+ InfluxReporter.flush_transactions_if_needed
87
+ result
88
+ end
89
+
90
+ def without_performance_trace
91
+ unless InfluxReporter::Client.inst
92
+ return yield
93
+ end
94
+ parent_transaction = InfluxReporter::Client.inst&.current_transaction
95
+ InfluxReporter::Client.inst.current_transaction = nil
96
+ begin
97
+ result = yield
98
+ ensure
99
+ InfluxReporter::Client.inst.current_transaction = parent_transaction
100
+ end
101
+ result
102
+ end
103
+
104
+ module ClassMethods
105
+ def skip_performance_trace!
106
+ @skip_performance_trace = true
107
+ end
108
+
109
+ def performance_trace?
110
+ !@skip_performance_trace
111
+ end
112
+ end
113
+ end
114
+
115
+ Sidekiq.configure_server do |config|
116
+ if Sidekiq::VERSION.to_i < 3
117
+ config.server_middleware do |chain|
118
+ chain.add InfluxReporter::Integration::SidekiqException
119
+ chain.add InfluxReporter::Integration::Sidekiq
120
+ end
121
+ else
122
+ config.error_handlers << lambda do |exception, *|
123
+ InfluxReporter.report exception
124
+ end
125
+ config.server_middleware do |chain|
126
+ chain.add InfluxReporter::Integration::Sidekiq
127
+ end
128
+ end
129
+ end
130
+ end