influxdb-rails 1.0.0.beta1 → 1.0.1.beta1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (87) hide show
  1. checksums.yaml +4 -4
  2. data/.github/dependabot.yml +11 -0
  3. data/.gitignore +2 -0
  4. data/.rspec +1 -0
  5. data/.rubocop.yml +7 -1
  6. data/.travis.yml +9 -10
  7. data/CHANGELOG.md +48 -11
  8. data/Gemfile +6 -0
  9. data/README.md +278 -100
  10. data/Rakefile +17 -18
  11. data/gemfiles/Gemfile.rails-5.0.x +2 -0
  12. data/gemfiles/Gemfile.rails-6.0.x +10 -0
  13. data/influxdb-rails.gemspec +20 -10
  14. data/lib/influxdb-rails.rb +35 -118
  15. data/lib/influxdb/rails/configuration.rb +99 -179
  16. data/lib/influxdb/rails/context.rb +26 -0
  17. data/lib/influxdb/rails/helpers/rspec_matchers.rb +48 -0
  18. data/lib/influxdb/rails/metric.rb +39 -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 +32 -0
  23. data/lib/influxdb/rails/middleware/request_subscriber.rb +44 -0
  24. data/lib/influxdb/rails/middleware/sql_subscriber.rb +37 -0
  25. data/lib/influxdb/rails/middleware/subscriber.rb +68 -0
  26. data/lib/influxdb/rails/railtie.rb +28 -25
  27. data/lib/influxdb/rails/sql/normalizer.rb +27 -0
  28. data/lib/influxdb/rails/sql/query.rb +32 -0
  29. data/lib/influxdb/rails/tags.rb +33 -0
  30. data/lib/influxdb/rails/test_client.rb +13 -0
  31. data/lib/influxdb/rails/values.rb +24 -0
  32. data/lib/influxdb/rails/version.rb +1 -1
  33. data/lib/rails/generators/influxdb/influxdb_generator.rb +1 -1
  34. data/lib/rails/generators/influxdb/templates/initializer.rb +39 -9
  35. data/sample-dashboard/Dockerfile +24 -0
  36. data/sample-dashboard/README.md +74 -0
  37. data/sample-dashboard/Rakefile +9 -0
  38. data/sample-dashboard/Ruby On Rails Performance (per Action).json +1576 -0
  39. data/sample-dashboard/Ruby On Rails Performance (per Request).json +1053 -0
  40. data/sample-dashboard/Ruby On Rails Performance.json +2041 -0
  41. data/sample-dashboard/docker-compose.yml +34 -0
  42. data/sample-dashboard/provisioning/grafana-dashboards.yml +12 -0
  43. data/sample-dashboard/provisioning/grafana-datasource.yml +10 -0
  44. data/sample-dashboard/provisioning/performance-action.json +1576 -0
  45. data/sample-dashboard/provisioning/performance-request.json +1053 -0
  46. data/sample-dashboard/provisioning/performance.json +2041 -0
  47. data/spec/requests/action_controller_metrics_spec.rb +83 -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_job_perform_start_metrics_spec.rb +68 -0
  54. data/spec/requests/active_record_instantiation_metrics_spec.rb +65 -0
  55. data/spec/requests/active_record_sql_metrics_spec.rb +103 -0
  56. data/spec/requests/block_inistrumentation_spec.rb +64 -0
  57. data/spec/requests/context_spec.rb +27 -0
  58. data/spec/requests/logger_spec.rb +10 -0
  59. data/spec/spec_helper.rb +12 -4
  60. data/spec/support/broken_client.rb +11 -0
  61. data/spec/support/rails5/app.rb +44 -5
  62. data/spec/support/rails6/app.rb +70 -0
  63. data/spec/support/views/metrics/_item.html.erb +1 -0
  64. data/spec/support/views/metrics/index.html.erb +5 -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 +64 -65
  68. data/spec/unit/sql/normalizer_spec.rb +15 -0
  69. data/spec/unit/sql/query_spec.rb +29 -0
  70. metadata +167 -44
  71. data/gemfiles/Gemfile.rails-4.2.x +0 -7
  72. data/lib/influxdb/rails/air_traffic_controller.rb +0 -41
  73. data/lib/influxdb/rails/backtrace.rb +0 -44
  74. data/lib/influxdb/rails/exception_presenter.rb +0 -94
  75. data/lib/influxdb/rails/instrumentation.rb +0 -34
  76. data/lib/influxdb/rails/logger.rb +0 -16
  77. data/lib/influxdb/rails/middleware/hijack_render_exception.rb +0 -16
  78. data/lib/influxdb/rails/middleware/hijack_rescue_action_everywhere.rb +0 -31
  79. data/lib/influxdb/rails/rack.rb +0 -24
  80. data/spec/controllers/widgets_controller_spec.rb +0 -15
  81. data/spec/integration/exceptions_spec.rb +0 -37
  82. data/spec/integration/integration_helper.rb +0 -1
  83. data/spec/integration/metrics_spec.rb +0 -21
  84. data/spec/support/rails4/app.rb +0 -30
  85. data/spec/unit/backtrace_spec.rb +0 -85
  86. data/spec/unit/exception_presenter_spec.rb +0 -23
  87. data/spec/unit/influxdb_rails_spec.rb +0 -164
@@ -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,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_instrumentationn # 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: {
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,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
@@ -1 +0,0 @@
1
- require File.dirname(__FILE__) + "/../spec_helper"
@@ -1,21 +0,0 @@
1
- require File.expand_path(File.dirname(__FILE__) + "/integration_helper")
2
-
3
- RSpec.describe "collecting metrics through ActiveSupport::Notifications", type: :request do
4
- before do
5
- InfluxDB::Rails.configure do |config|
6
- config.ignored_environments = %w[development]
7
- end
8
- end
9
-
10
- describe "in a normal request" do
11
- it "should attempt to handle ActionController metrics" do
12
- expect(InfluxDB::Rails).to receive(:handle_action_controller_metrics).once
13
- get "/widgets"
14
- end
15
-
16
- it "should result in attempts to write metrics via the client" do
17
- expect(InfluxDB::Rails.client).to receive(:write_point).exactly(3).times
18
- get "/widgets"
19
- end
20
- end
21
- end
@@ -1,30 +0,0 @@
1
- require "action_controller/railtie"
2
-
3
- app = Class.new(Rails::Application)
4
- app.config.secret_token = "1234567890abcdef1234567890abcdef"
5
- app.config.session_store :cookie_store, key: "_myapp_session"
6
- app.config.active_support.deprecation = :log
7
- app.config.eager_load = false
8
- app.config.root = File.dirname(__FILE__)
9
- Rails.backtrace_cleaner.remove_silencers!
10
- app.initialize!
11
-
12
- app.routes.draw do
13
- resources :widgets
14
- end
15
-
16
- InfluxDB::Rails.configure do |config|
17
- end
18
-
19
- class ApplicationController < ActionController::Base; end
20
- class WidgetsController < ApplicationController
21
- def index
22
- render nothing: true
23
- end
24
-
25
- def new
26
- 1 / 0
27
- end
28
- end
29
-
30
- Object.const_set(:ApplicationHelper, Module.new)
@@ -1,85 +0,0 @@
1
- require "spec_helper"
2
-
3
- RSpec.describe InfluxDB::Rails::Backtrace do
4
- before do
5
- @raw_backtrace = [
6
- "/var/www/current/app/models/foo.rb:10:in `bar'",
7
- "/var/www/current/app/models/foo.rb:19:in `baz'",
8
- "/var/www/current/app/models/foo.rb:32:in `<main>'"
9
- ]
10
-
11
- @backtrace = InfluxDB::Rails::Backtrace.new(@raw_backtrace)
12
- end
13
-
14
- it "should accept an exception into the initializer" do
15
- expect(@backtrace.lines).not_to be_empty
16
- expect(@backtrace.lines.count).to eq(3)
17
- end
18
-
19
- it "should correctly parse lines into their elements" do
20
- line = @backtrace.lines.first
21
-
22
- expect(line.file).to eq("/var/www/current/app/models/foo.rb")
23
- expect(line.number).to eq("10")
24
- expect(line.method).to eq("bar")
25
- end
26
-
27
- describe "#to_a" do
28
- it "should return an array of lines" do
29
- expect(@backtrace.to_a.is_a?(Array)).to be_truthy
30
- end
31
- end
32
-
33
- context "nil backtrace" do
34
- before do
35
- @raw_backtrace = nil
36
- @backtrace = InfluxDB::Rails::Backtrace.new(@raw_backtrace)
37
- end
38
-
39
- it "should accept an exception into the initializer" do
40
- expect(@backtrace.lines).to be_empty
41
- expect(@backtrace.lines.count).to eq(0)
42
- end
43
-
44
- describe "#to_a" do
45
- it "should return an array of lines" do
46
- expect(@backtrace.to_a.is_a?(Array)).to be_truthy
47
- end
48
- end
49
- end
50
-
51
- describe "backtrace filters" do
52
- before do
53
- InfluxDB::Rails.configure do |config|
54
- config.application_root = "/var/www/current"
55
- end
56
- end
57
-
58
- it "should apply a single default backtrace filter correctly" do
59
- filtered_backtrace = InfluxDB::Rails::Backtrace.new(@raw_backtrace)
60
-
61
- line = filtered_backtrace.lines.first
62
- expect(line.file).to eq("[APP_ROOT]/app/models/foo.rb")
63
- end
64
-
65
- it "should all default backtrace filters correctly" do
66
- extended_backtrace = @raw_backtrace.dup
67
- extended_backtrace << "#{Gem.path.first}/lib/foo_gem.rb:1:in `blah'"
68
-
69
- filtered_backtrace = InfluxDB::Rails::Backtrace.new(extended_backtrace)
70
- expect(filtered_backtrace.lines.first.file).to eq("[APP_ROOT]/app/models/foo.rb")
71
- expect(filtered_backtrace.lines.last.file).to eq("[GEM_ROOT]/lib/foo_gem.rb")
72
- end
73
-
74
- it "should allow the addition of custom backtrace filters" do
75
- InfluxDB::Rails.configure do |config|
76
- config.backtrace_filters << ->(line) { line.gsub(/foo/, "F00") }
77
- end
78
-
79
- filtered_backtrace = InfluxDB::Rails::Backtrace.new(@raw_backtrace)
80
-
81
- line = filtered_backtrace.lines.first
82
- expect(line.file).to eq("[APP_ROOT]/app/models/F00.rb")
83
- end
84
- end
85
- end