influxdb-rails 1.0.0.beta3 → 1.0.1.beta3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (94) hide show
  1. checksums.yaml +4 -4
  2. data/.github/dependabot.yml +11 -0
  3. data/.github/workflows/rubocop.yml +18 -0
  4. data/.github/workflows/spec.yml +31 -0
  5. data/.gitignore +1 -0
  6. data/.rubocop.yml +40 -7
  7. data/CHANGELOG.md +42 -12
  8. data/README.md +277 -164
  9. data/Rakefile +0 -6
  10. data/gemfiles/Gemfile.rails-6.0.x +9 -0
  11. data/gemfiles/Gemfile.rails-6.1.x +9 -0
  12. data/influxdb-rails.gemspec +18 -9
  13. data/lib/influxdb-rails.rb +31 -81
  14. data/lib/influxdb/rails/configuration.rb +99 -194
  15. data/lib/influxdb/rails/context.rb +12 -28
  16. data/lib/influxdb/rails/helpers/rspec_matchers.rb +48 -0
  17. data/lib/influxdb/rails/metric.rb +39 -0
  18. data/lib/influxdb/rails/middleware/action_mailer_subscriber.rb +22 -0
  19. data/lib/influxdb/rails/middleware/active_job_subscriber.rb +67 -0
  20. data/lib/influxdb/rails/middleware/active_record_subscriber.rb +26 -0
  21. data/lib/influxdb/rails/middleware/block_instrumentation_subscriber.rb +24 -0
  22. data/lib/influxdb/rails/middleware/render_subscriber.rb +16 -10
  23. data/lib/influxdb/rails/middleware/request_subscriber.rb +23 -30
  24. data/lib/influxdb/rails/middleware/sql_subscriber.rb +19 -15
  25. data/lib/influxdb/rails/middleware/subscriber.rb +44 -20
  26. data/lib/influxdb/rails/railtie.rb +29 -35
  27. data/lib/influxdb/rails/sql/normalizer.rb +3 -3
  28. data/lib/influxdb/rails/tags.rb +33 -0
  29. data/lib/influxdb/rails/test_client.rb +13 -0
  30. data/lib/influxdb/rails/values.rb +24 -0
  31. data/lib/influxdb/rails/version.rb +1 -1
  32. data/lib/rails/generators/influxdb/influxdb_generator.rb +1 -1
  33. data/lib/rails/generators/influxdb/templates/initializer.rb +43 -9
  34. data/sample-dashboard/Dockerfile +24 -0
  35. data/sample-dashboard/README.md +74 -0
  36. data/sample-dashboard/Rakefile +9 -0
  37. data/sample-dashboard/Ruby On Rails Performance (per Action).json +1576 -0
  38. data/sample-dashboard/Ruby On Rails Performance (per Request).json +1053 -0
  39. data/sample-dashboard/Ruby On Rails Performance.json +2041 -0
  40. data/sample-dashboard/docker-compose.yml +34 -0
  41. data/sample-dashboard/provisioning/grafana-dashboards.yml +12 -0
  42. data/sample-dashboard/provisioning/grafana-datasource.yml +10 -0
  43. data/sample-dashboard/provisioning/performance-action.json +1576 -0
  44. data/sample-dashboard/provisioning/performance-request.json +1053 -0
  45. data/sample-dashboard/provisioning/performance.json +2041 -0
  46. data/spec/requests/action_controller_metrics_spec.rb +83 -0
  47. data/spec/requests/action_mailer_deliver_metrics_spec.rb +49 -0
  48. data/spec/requests/action_view_collection_metrics_spec.rb +66 -0
  49. data/spec/requests/action_view_partial_metrics_spec.rb +62 -0
  50. data/spec/requests/action_view_template_metrics_spec.rb +62 -0
  51. data/spec/requests/active_job_enqueue_metrics_spec.rb +65 -0
  52. data/spec/requests/active_job_perform_metrics_spec.rb +68 -0
  53. data/spec/requests/active_record_instantiation_metrics_spec.rb +65 -0
  54. data/spec/requests/active_record_sql_metrics_spec.rb +103 -0
  55. data/spec/requests/block_inistrumentation_spec.rb +64 -0
  56. data/spec/requests/context_spec.rb +27 -0
  57. data/spec/requests/logger_spec.rb +10 -0
  58. data/spec/spec_helper.rb +14 -4
  59. data/spec/support/broken_client.rb +11 -0
  60. data/spec/support/rails5/app.rb +51 -12
  61. data/spec/support/rails6/app.rb +83 -0
  62. data/spec/support/views/layouts/mailer.txt.erb +1 -0
  63. data/spec/support/views/{widgets → metrics}/_item.html.erb +0 -0
  64. data/spec/support/views/{widgets → metrics}/index.html.erb +0 -0
  65. data/spec/support/views/metrics/show.html.erb +4 -0
  66. data/spec/unit/block_instrumentation_spec.rb +18 -0
  67. data/spec/unit/configuration_spec.rb +47 -65
  68. metadata +141 -61
  69. data/.travis.yml +0 -37
  70. data/gemfiles/Gemfile.rails-4.2.x +0 -7
  71. data/gemfiles/Gemfile.rails-5.0.x +0 -7
  72. data/gemfiles/Gemfile.rails-5.1.x +0 -7
  73. data/lib/influxdb/rails/air_traffic_controller.rb +0 -41
  74. data/lib/influxdb/rails/backtrace.rb +0 -44
  75. data/lib/influxdb/rails/exception_presenter.rb +0 -94
  76. data/lib/influxdb/rails/instrumentation.rb +0 -34
  77. data/lib/influxdb/rails/logger.rb +0 -16
  78. data/lib/influxdb/rails/middleware/hijack_render_exception.rb +0 -16
  79. data/lib/influxdb/rails/middleware/hijack_rescue_action_everywhere.rb +0 -31
  80. data/lib/influxdb/rails/middleware/simple_subscriber.rb +0 -46
  81. data/lib/influxdb/rails/rack.rb +0 -24
  82. data/spec/controllers/widgets_controller_spec.rb +0 -15
  83. data/spec/integration/exceptions_spec.rb +0 -37
  84. data/spec/integration/integration_helper.rb +0 -1
  85. data/spec/integration/metrics_spec.rb +0 -28
  86. data/spec/shared_examples/tags.rb +0 -42
  87. data/spec/support/rails4/app.rb +0 -44
  88. data/spec/unit/backtrace_spec.rb +0 -85
  89. data/spec/unit/context_spec.rb +0 -40
  90. data/spec/unit/exception_presenter_spec.rb +0 -23
  91. data/spec/unit/influxdb_rails_spec.rb +0 -78
  92. data/spec/unit/middleware/render_subscriber_spec.rb +0 -92
  93. data/spec/unit/middleware/request_subscriber_spec.rb +0 -91
  94. data/spec/unit/middleware/sql_subscriber_spec.rb +0 -81
@@ -1,37 +0,0 @@
1
- sudo: required
2
- dist: trusty
3
- language: ruby
4
- before_install:
5
- - gem update --system --no-doc
6
- - gem install bundler --no-doc
7
- - gem update bundler --no-doc
8
- rvm:
9
- - ruby-head
10
- - "2.6"
11
- - "2.5"
12
- - "2.4"
13
- - "2.3"
14
- gemfile:
15
- - gemfiles/Gemfile.rails-5.2.x
16
- - gemfiles/Gemfile.rails-5.1.x
17
- - gemfiles/Gemfile.rails-5.0.x
18
- - gemfiles/Gemfile.rails-4.2.x
19
- env:
20
- - TEST_TASK=spec
21
- matrix:
22
- allow_failures:
23
- - rvm: ruby-head
24
- include:
25
- - { rvm: "2.6", gemfile: "Gemfile", env: [TEST_TASK=rubocop] }
26
- exclude:
27
- # Rails < 5 not on MRI 2.4+
28
- - { rvm: ruby-head, gemfile: "gemfiles/Gemfile.rails-4.2.x" }
29
- - { rvm: "2.6", gemfile: "gemfiles/Gemfile.rails-4.2.x" }
30
- - { rvm: "2.5", gemfile: "gemfiles/Gemfile.rails-4.2.x" }
31
- - { rvm: "2.4", gemfile: "gemfiles/Gemfile.rails-4.2.x" }
32
- addons:
33
- apt:
34
- packages:
35
- - haveged
36
- - libgmp-dev
37
- script: bundle exec rake $TEST_TASK
@@ -1,7 +0,0 @@
1
- source "https://rubygems.org"
2
-
3
- gem 'actionpack', '~> 4.2.0'
4
- gem 'activesupport', '~> 4.2.0'
5
- gem 'activemodel', '~> 4.2.0'
6
-
7
- gemspec :path => '../'
@@ -1,7 +0,0 @@
1
- source "https://rubygems.org"
2
-
3
- gem 'actionpack', '~> 5.0.0'
4
- gem 'activesupport', '~> 5.0.0'
5
- gem 'activemodel', '~> 5.0.0'
6
-
7
- gemspec :path => '../'
@@ -1,7 +0,0 @@
1
- source "https://rubygems.org"
2
-
3
- gem 'actionpack', '~> 5.1.0'
4
- gem 'activesupport', '~> 5.1.0'
5
- gem 'activemodel', '~> 5.1.0'
6
-
7
- gemspec :path => '../'
@@ -1,41 +0,0 @@
1
- module InfluxDB
2
- module Rails
3
- module AirTrafficController # :nodoc:
4
- def influxdb_request_data # rubocop:disable Metrics/MethodLength
5
- {
6
- params: influxdb_filtered_params,
7
- session_data: influxdb_session_data,
8
- controller: params[:controller],
9
- action: params[:action],
10
- request_url: influxdb_request_url,
11
- user_agent: request.env["HTTP_USER_AGENT"],
12
- remote_ip: request.remote_ip,
13
- referer: request.referer,
14
- current_user: (current_user rescue nil),
15
- }
16
- end
17
-
18
- private
19
-
20
- def influxdb_session_data
21
- session.respond_to?(:to_hash) ? session.to_hash : session.data
22
- end
23
-
24
- def influxdb_request_url
25
- url = "#{request.protocol}#{request.host}"
26
- url << ":#{request.port}" unless [80, 443].include?(request.port)
27
- url << request.fullpath
28
- end
29
-
30
- def influxdb_filtered_params
31
- if respond_to?(:filter_parameters)
32
- filter_parameters(unfiltered_params)
33
- elsif defined?(request.filtered_parameters)
34
- request.filtered_parameters
35
- else
36
- params.to_hash.except(:password, :password_confirmation)
37
- end
38
- end
39
- end
40
- end
41
- end
@@ -1,44 +0,0 @@
1
- module InfluxDB
2
- module Rails
3
- class Backtrace # rubocop:disable Style/Documentation
4
- class Line # rubocop:disable Style/Documentation
5
- FORMAT = /^((?:[a-zA-Z]:)?[^:]+):(\d+)(?::in `([^']+)')?$/.freeze
6
-
7
- attr_reader :file
8
- attr_reader :number
9
- attr_reader :method
10
-
11
- def initialize(line)
12
- _, @file, @number, @method = line.match(FORMAT).to_a
13
- end
14
-
15
- def to_s
16
- "#{file}:#{number} in `#{method}'"
17
- end
18
-
19
- def inspect
20
- "<Line: #{to_s}>" # rubocop:disable Lint/StringConversionInInterpolation
21
- end
22
- end
23
-
24
- attr_reader :lines
25
-
26
- def initialize(backtrace)
27
- @lines = Array(backtrace).each.collect do |line|
28
- InfluxDB::Rails.configuration.backtrace_filters.each do |filter|
29
- line = filter.call(line)
30
- end
31
- Line.new(line)
32
- end
33
- end
34
-
35
- def to_a
36
- lines.map(&:to_s)
37
- end
38
-
39
- def inspect
40
- "<Backtrace: " + lines.collect(&:to_s).join(", ") + ">"
41
- end
42
- end
43
- end
44
- end
@@ -1,94 +0,0 @@
1
- require "base64"
2
- require "socket"
3
- require "json"
4
-
5
- module InfluxDB
6
- module Rails
7
- class ExceptionPresenter # rubocop:disable Style/Documentation
8
- attr_reader :exception
9
- attr_reader :backtrace
10
- attr_reader :params
11
- attr_reader :session_data
12
- attr_reader :current_user
13
- attr_reader :controller
14
- attr_reader :action
15
- attr_reader :request_url
16
- attr_reader :referer
17
- attr_reader :remote_ip
18
- attr_reader :user_agent
19
- attr_reader :custom_data
20
-
21
- def initialize(ex, params = {})
22
- ex = ex.continued_exception if ex.respond_to?(:continued_exception)
23
- ex = ex.original_exception if ex.respond_to?(:original_exception)
24
-
25
- @exception = ex.is_a?(String) ? Exception.new(ex) : ex
26
- @backtrace = InfluxDB::Rails::Backtrace.new(@exception.backtrace)
27
- @dimensions = {}
28
- configure_from_params(params)
29
-
30
- @environment_variables = ENV.to_hash || {}
31
- end
32
-
33
- def context # rubocop:disable Metrics/MethodLength
34
- c = {
35
- application_name: InfluxDB::Rails.configuration.application_name,
36
- application_root: InfluxDB::Rails.configuration.application_root,
37
- framework: InfluxDB::Rails.configuration.framework,
38
- framework_version: InfluxDB::Rails.configuration.framework_version,
39
- language: "Ruby",
40
- language_version: "#{RUBY_VERSION}-p#{RUBY_PATCHLEVEL}",
41
- custom_data: @custom_data,
42
- }
43
-
44
- InfluxDB::Rails.configuration.add_custom_exception_data(self)
45
- c
46
- end
47
-
48
- def dimensions
49
- {
50
- class: @exception.class.to_s,
51
- method: "#{@controller}##{@action}",
52
- filename: File.basename(@backtrace.lines.first.try(:file)),
53
- server: Socket.gethostname,
54
- status: "open",
55
- }.merge(@dimensions)
56
- end
57
-
58
- def values
59
- {
60
- exception_message: @exception.message,
61
- exception_backtrace: JSON.generate(@backtrace.to_a),
62
- }
63
- end
64
-
65
- def request_data
66
- {
67
- params: @params,
68
- session_data: @session_data,
69
- controller: @controller,
70
- action: @action,
71
- request_url: @request_url,
72
- referer: @referer,
73
- remote_ip: @remote_ip,
74
- user_agent: @user_agent,
75
- }
76
- end
77
-
78
- private
79
-
80
- def configure_from_params(params)
81
- @params = params[:params]
82
- @session_data = params[:session_data] || {}
83
- @current_user = params[:current_user]
84
- @controller = params[:controller]
85
- @action = params[:action]
86
- @request_url = params[:request_url]
87
- @user_agent = params[:user_agent]
88
- @referer = params[:referer]
89
- @remote_ip = params[:remote_ip]
90
- @custom_data = params[:custom_data] || {}
91
- end
92
- end
93
- end
94
- end
@@ -1,34 +0,0 @@
1
- module InfluxDB
2
- module Rails
3
- module Instrumentation # rubocop:disable Style/Documentation
4
- def benchmark_for_instrumentation # rubocop:disable Metrics/MethodLength
5
- start = Time.now
6
- yield
7
-
8
- c = InfluxDB::Rails.configuration
9
- return if c.ignore_current_environment?
10
-
11
- InfluxDB::Rails.client.write_point \
12
- c.series_name_for_instrumentation,
13
- values: {
14
- value: ((Time.now - start) * 1000).ceil,
15
- },
16
- tags: configuration.tags_middleware.call(
17
- method: "#{controller_name}##{action_name}",
18
- server: Socket.gethostname
19
- )
20
- end
21
-
22
- def self.included(base)
23
- base.extend(ClassMethods)
24
- end
25
-
26
- module ClassMethods # rubocop:disable Style/Documentation
27
- def instrument(methods = [])
28
- methods = [methods] unless methods.is_a?(Array)
29
- around_filter :benchmark_for_instrumentation, only: methods
30
- end
31
- end
32
- end
33
- end
34
- end
@@ -1,16 +0,0 @@
1
- module InfluxDB
2
- module Rails
3
- module Logger # rubocop:disable Style/Documentation
4
- PREFIX = "[InfluxDB::Rails] ".freeze
5
-
6
- private
7
-
8
- def log(level, message)
9
- c = InfluxDB::Rails.configuration
10
- return if level != :error && !c.debug?
11
-
12
- c.logger&.send(level, PREFIX + message)
13
- end
14
- end
15
- end
16
- end
@@ -1,16 +0,0 @@
1
- module InfluxDB
2
- module Rails
3
- module Middleware
4
- module HijackRenderException # rubocop:disable Style/Documentation
5
- def render_exception(env, ex)
6
- controller = env["action_controller.instance"] || env.controller_instance
7
- request_data = controller.try(:influxdb_request_data) || {}
8
- unless InfluxDB::Rails.configuration.ignore_user_agent?(request_data[:user_agent])
9
- InfluxDB::Rails.report_exception_unless_ignorable(ex, request_data)
10
- end
11
- super
12
- end
13
- end
14
- end
15
- end
16
- end
@@ -1,31 +0,0 @@
1
- module InfluxDB
2
- module Rails
3
- module Middleware
4
- module HijackRescueActionEverywhere # rubocop:disable Style/Documentation
5
- def self.included(base)
6
- base.send(:alias_method_chain, :rescue_action_in_public, :influxdb)
7
- base.send(:alias_method_chain, :rescue_action_locally, :influxdb)
8
- end
9
-
10
- private
11
-
12
- def rescue_action_in_public_with_influxdb(ex)
13
- handle_exception(ex)
14
- rescue_action_in_public_without_influxdb(ex)
15
- end
16
-
17
- def rescue_action_locally_with_influxdb(ex)
18
- handle_exception(ex)
19
- rescue_action_locally_without_influxdb(ex)
20
- end
21
-
22
- def handle_exception(ex)
23
- request_data = influxdb_request_data || {}
24
- return if InfluxDB::Rails.configuration.ignore_user_agent?(request_data[:user_agent])
25
-
26
- InfluxDB::Rails.report_exception_unless_ignorable(ex, request_data)
27
- end
28
- end
29
- end
30
- end
31
- end
@@ -1,46 +0,0 @@
1
- require "influxdb/rails/middleware/subscriber"
2
-
3
- module InfluxDB
4
- module Rails
5
- module Middleware
6
- # Subscriber acts as base class for different *Subscriber classes,
7
- # which are intended as ActiveSupport::Notifications.subscribe
8
- # consumers.
9
- class SimpleSubscriber < Subscriber
10
- attr_reader :series_name
11
-
12
- def initialize(configuration, series_name)
13
- super(configuration)
14
- @series_name = series_name
15
- end
16
-
17
- def call(_name, started, finished, _unique_id, payload)
18
- return unless enabled?
19
-
20
- begin
21
- InfluxDB::Rails.client.write_point series_name,
22
- values: values(started, finished, payload),
23
- tags: tags(payload),
24
- timestamp: timestamp(finished.utc)
25
- rescue StandardError => e
26
- log :error, "[InfluxDB::Rails] Unable to write points: #{e.message}"
27
- end
28
- end
29
-
30
- private
31
-
32
- def values(started, finished, _payload)
33
- { value: ((finished - started) * 1000).ceil }
34
- end
35
-
36
- def timestamp(finished)
37
- InfluxDB.convert_timestamp(finished.utc, configuration.time_precision)
38
- end
39
-
40
- def enabled?
41
- super && series_name.present?
42
- end
43
- end
44
- end
45
- end
46
- end
@@ -1,24 +0,0 @@
1
- module InfluxDB
2
- module Rails
3
- class Rack # rubocop:disable Style/Documentation
4
- def initialize(app)
5
- @app = app
6
- end
7
-
8
- def call(env)
9
- dup._call(env)
10
- end
11
-
12
- def _call(env)
13
- begin
14
- response = @app.call(env)
15
- rescue StandardError => e
16
- InfluxDB::Rails.transmit_unless_ignorable(e, env)
17
- raise(e)
18
- end
19
-
20
- response
21
- end
22
- end
23
- end
24
- end
@@ -1,15 +0,0 @@
1
- require "spec_helper"
2
-
3
- RSpec.describe WidgetsController, type: :controller do
4
- describe "#new" do
5
- it "should raise an exception" do
6
- expect { get :new }.to raise_error(ZeroDivisionError)
7
- end
8
- end
9
-
10
- describe "#index" do
11
- it "should not raise an exception" do
12
- expect { get :index }.to_not raise_error
13
- end
14
- end
15
- end
@@ -1,37 +0,0 @@
1
- require File.expand_path(File.dirname(__FILE__) + "/integration_helper")
2
-
3
- RSpec.describe "exception handling", type: :request do
4
- before do
5
- InfluxDB::Rails.configure do |config|
6
- config.ignored_environments = %w[development]
7
- config.instrumentation_enabled = false
8
- end
9
- end
10
-
11
- describe "in an action that raises an exception" do
12
- it "should add an exception to the queue" do
13
- expect(InfluxDB::Rails.client).to receive(:write_point)
14
- get "/widgets/new"
15
- end
16
- end
17
-
18
- describe "in an action that does not raise an exception" do
19
- it "should not add anything to the queue" do
20
- expect(InfluxDB::Rails.client).not_to receive(:write_point)
21
- get "/widgets"
22
- end
23
- end
24
-
25
- describe "for an ignored user agent" do
26
- it "should not make an HTTP call to the API" do
27
- expect(InfluxDB::Rails.client).not_to receive(:write_point)
28
-
29
- # note: GoogleBot is ignored by default
30
- if Rails::VERSION::MAJOR >= 5
31
- get "/widgets/new", headers: { "HTTP_USER_AGENT" => "GoogleBot/2.1" }
32
- else
33
- get "/widgets/new", {}, "HTTP_USER_AGENT" => "GoogleBot/2.1"
34
- end
35
- end
36
- end
37
- end