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
@@ -0,0 +1,65 @@
1
+ require "#{File.dirname(__FILE__)}/../spec_helper"
2
+
3
+ RSpec.describe "ActiveRecord instantiation metrics", type: :request do
4
+ let(:tags_middleware) do
5
+ lambda do |tags|
6
+ tags.merge(tags_middleware: :tags_middleware)
7
+ end
8
+ end
9
+ let(:metric) { Metric.create!(name: "name") }
10
+ before do
11
+ allow_any_instance_of(InfluxDB::Rails::Configuration).to receive(:ignored_environments).and_return(%w[development])
12
+ allow_any_instance_of(ActionDispatch::Request).to receive(:request_id).and_return(:request_id)
13
+ allow_any_instance_of(InfluxDB::Rails::Configuration).to receive(:application_name).and_return(:app_name)
14
+ allow_any_instance_of(InfluxDB::Rails::Configuration).to receive(:tags_middleware).and_return(tags_middleware)
15
+ end
16
+
17
+ it "writes metric" do
18
+ get metric_path(metric)
19
+
20
+ expect_metric(
21
+ tags: a_hash_including(
22
+ location: "MetricsController#show",
23
+ hook: "instantiation",
24
+ class_name: "Metric",
25
+ additional_tag: :value,
26
+ server: Socket.gethostname,
27
+ app_name: :app_name,
28
+ tags_middleware: :tags_middleware
29
+ ),
30
+ values: a_hash_including(
31
+ additional_value: :value,
32
+ request_id: :request_id,
33
+ value: be_between(1, 500),
34
+ record_count: 1
35
+ )
36
+ )
37
+ end
38
+
39
+ it "includes correct timestamps" do
40
+ travel_to Time.zone.local(2018, 1, 1, 9, 0, 0)
41
+
42
+ get metric_path(metric)
43
+
44
+ expect_metric(
45
+ tags: a_hash_including(
46
+ location: "MetricsController#show",
47
+ hook: "instantiation"
48
+ ),
49
+ timestamp: 1_514_797_200
50
+ )
51
+ end
52
+
53
+ it "does not write metric when hook is ignored" do
54
+ allow_any_instance_of(InfluxDB::Rails::Configuration).to receive(:ignored_hooks).and_return(["instantiation.active_record"])
55
+
56
+ get metric_path(metric)
57
+
58
+ expect_no_metric(
59
+ tags: a_hash_including(
60
+ location: "MetricsController#show",
61
+ hook: "instantiation"
62
+ )
63
+ )
64
+ end
65
+ end
@@ -0,0 +1,103 @@
1
+ require "#{File.dirname(__FILE__)}/../spec_helper"
2
+
3
+ RSpec.describe "ActiveRecord SQL metrics", type: :request do
4
+ let(:tags_middleware) do
5
+ lambda do |tags|
6
+ tags.merge(tags_middleware: :tags_middleware)
7
+ end
8
+ end
9
+ before do
10
+ allow_any_instance_of(ActionDispatch::Request).to receive(:request_id).and_return(:request_id)
11
+ allow_any_instance_of(InfluxDB::Rails::Configuration).to receive(:application_name).and_return(:app_name)
12
+ allow_any_instance_of(InfluxDB::Rails::Configuration).to receive(:tags_middleware).and_return(tags_middleware)
13
+ end
14
+
15
+ it "writes metric" do
16
+ skip("https://github.com/rails/rails/issues/30586") unless payload_names_fixed_in_rails?
17
+
18
+ get "/metrics"
19
+
20
+ expect_metric(
21
+ tags: a_hash_including(
22
+ location: "MetricsController#index",
23
+ hook: "sql",
24
+ name: "Metric Create",
25
+ class_name: "Metric",
26
+ operation: "INSERT",
27
+ additional_tag: :value,
28
+ server: Socket.gethostname,
29
+ app_name: :app_name,
30
+ tags_middleware: :tags_middleware
31
+ ),
32
+ values: a_hash_including(
33
+ additional_value: :value,
34
+ request_id: :request_id,
35
+ value: be_between(1, 500),
36
+ sql: "INSERT INTO \"metrics\" (\"name\", \"created_at\", \"updated_at\") VALUES (xxx)"
37
+ )
38
+ )
39
+ end
40
+
41
+ it "writes metric" do
42
+ skip("https://github.com/rails/rails/issues/30586") if payload_names_fixed_in_rails?
43
+
44
+ get "/metrics"
45
+
46
+ expect_metric(
47
+ tags: a_hash_including(
48
+ location: "MetricsController#index",
49
+ hook: "sql",
50
+ name: "SQL",
51
+ class_name: "SQL",
52
+ operation: "INSERT",
53
+ additional_tag: :value,
54
+ server: Socket.gethostname,
55
+ app_name: :app_name,
56
+ tags_middleware: :tags_middleware
57
+ ),
58
+ values: a_hash_including(
59
+ additional_value: :value,
60
+ request_id: :request_id,
61
+ value: be_between(1, 500),
62
+ sql: "INSERT INTO \"metrics\" (\"name\", \"created_at\", \"updated_at\") VALUES (xxx)"
63
+ )
64
+ )
65
+ end
66
+
67
+ it "includes correct timestamps" do
68
+ travel_to Time.zone.local(2018, 1, 1, 9, 0, 0)
69
+
70
+ get "/metrics"
71
+
72
+ expect_metric(
73
+ tags: a_hash_including(
74
+ location: "MetricsController#index",
75
+ hook: "sql"
76
+ ),
77
+ timestamp: 1_514_797_200
78
+ )
79
+ end
80
+
81
+ it "does not write metric when hook is ignored" do
82
+ allow_any_instance_of(InfluxDB::Rails::Configuration).to receive(:ignored_hooks).and_return(["sql.active_record"])
83
+
84
+ get "/metrics"
85
+
86
+ expect_no_metric(
87
+ tags: a_hash_including(
88
+ location: "MetricsController#index",
89
+ hook: "sql"
90
+ )
91
+ )
92
+ end
93
+
94
+ def payload_names_fixed_in_rails?
95
+ Rails::VERSION::MAJOR > 5 ||
96
+ rails_after_5_1?
97
+ end
98
+
99
+ def rails_after_5_1?
100
+ Rails::VERSION::MAJOR == 5 &&
101
+ Rails::VERSION::MINOR > 1
102
+ end
103
+ end
@@ -0,0 +1,64 @@
1
+ require "#{File.dirname(__FILE__)}/../spec_helper"
2
+
3
+ RSpec.describe "BlockInstrumentation metrics", type: :request do
4
+ let(:tags_middleware) do
5
+ lambda do |tags|
6
+ tags.merge(tags_middleware: :tags_middleware)
7
+ end
8
+ end
9
+ before do
10
+ allow_any_instance_of(ActionDispatch::Request).to receive(:request_id).and_return(:request_id)
11
+ allow_any_instance_of(InfluxDB::Rails::Configuration).to receive(:application_name).and_return(:app_name)
12
+ allow_any_instance_of(InfluxDB::Rails::Configuration).to receive(:tags_middleware).and_return(tags_middleware)
13
+ end
14
+
15
+ it "writes metric" do
16
+ get "/metrics"
17
+
18
+ expect_metric(
19
+ tags: a_hash_including(
20
+ location: "MetricsController#index",
21
+ hook: "block_instrumentation",
22
+ additional_tag: :value,
23
+ server: Socket.gethostname,
24
+ app_name: :app_name,
25
+ tags_middleware: :tags_middleware,
26
+ block_tag: :block_tag,
27
+ name: "name"
28
+ ),
29
+ values: a_hash_including(
30
+ additional_value: :value,
31
+ request_id: :request_id,
32
+ block_value: :block_value,
33
+ value: be_between(1, 500)
34
+ )
35
+ )
36
+ end
37
+
38
+ it "includes correct timestamps" do
39
+ travel_to Time.zone.local(2018, 1, 1, 9, 0, 0)
40
+
41
+ get "/metrics"
42
+
43
+ expect_metric(
44
+ tags: a_hash_including(
45
+ location: "MetricsController#index",
46
+ hook: "block_instrumentation"
47
+ ),
48
+ timestamp: 1_514_797_200
49
+ )
50
+ end
51
+
52
+ it "does not write metric when hook is ignored" do
53
+ allow_any_instance_of(InfluxDB::Rails::Configuration).to receive(:ignored_hooks).and_return(["block_instrumentation.influxdb_rails"])
54
+
55
+ get "/metrics"
56
+
57
+ expect_no_metric(
58
+ tags: a_hash_including(
59
+ location: "MetricsController#index",
60
+ hook: "block_instrumentation"
61
+ )
62
+ )
63
+ end
64
+ end
@@ -0,0 +1,27 @@
1
+ require "#{File.dirname(__FILE__)}/../spec_helper"
2
+
3
+ RSpec.describe "Context", type: :request do
4
+ it "resets the context after a request" do
5
+ get "/metrics"
6
+
7
+ expect_metric(
8
+ tags: a_hash_including(
9
+ location: "MetricsController#index",
10
+ hook: "sql"
11
+ )
12
+ )
13
+
14
+ expect(InfluxDB::Rails.current.tags).to be_empty
15
+ expect(InfluxDB::Rails.current.values).to be_empty
16
+ end
17
+
18
+ it "resets the context after a request when exceptioni occurs" do
19
+ setup_broken_client
20
+
21
+ get "/metrics"
22
+
23
+ expect_no_metric(hook: "process_action")
24
+ expect(InfluxDB::Rails.current.tags).to be_empty
25
+ expect(InfluxDB::Rails.current.values).to be_empty
26
+ end
27
+ end
@@ -0,0 +1,10 @@
1
+ require "#{File.dirname(__FILE__)}/../spec_helper"
2
+
3
+ RSpec.describe "Logger", type: :request do
4
+ it "logs exception" do
5
+ setup_broken_client
6
+ expect(Rails.logger).to receive(:error).with(/message/).at_least(:once)
7
+
8
+ get "/metrics"
9
+ end
10
+ end
@@ -1,5 +1,9 @@
1
1
  $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), "..", "lib"))
2
2
  $LOAD_PATH.unshift(File.dirname(__FILE__))
3
+ require "active_support"
4
+ require_relative "../lib/influxdb/rails/helpers/rspec_matchers"
5
+ require File.expand_path("#{File.dirname(__FILE__)}/support/broken_client")
6
+
3
7
  ENV["RAILS_ENV"] ||= "test"
4
8
 
5
9
  require "rails"
@@ -19,13 +23,19 @@ puts "Loading Rails v#{Rails.version}..."
19
23
  require "support/rails#{Rails::VERSION::MAJOR}/app"
20
24
  require "rspec/rails"
21
25
 
26
+ require "pry"
27
+
22
28
  RSpec.configure do |config|
23
29
  # use expect syntax
24
30
  config.disable_monkey_patching!
25
31
 
26
- # reset configuration for each spec
27
- config.before :each do
28
- InfluxDB::Rails.instance_variable_set :@configuration, nil
29
- InfluxDB::Rails.configure(&:load_rails_defaults)
32
+ config.after(:each) do
33
+ travel_back
30
34
  end
35
+
36
+ config.include ActiveSupport::Testing::TimeHelpers
37
+ config.include ActiveSupport::Testing::Assertions
38
+ config.include ActiveJob::TestHelper
39
+
40
+ config.include InfluxDB::Rails::BrokenClient
31
41
  end
@@ -0,0 +1,11 @@
1
+ module InfluxDB
2
+ module Rails
3
+ module BrokenClient
4
+ def setup_broken_client
5
+ client = double
6
+ allow(client).to receive(:write_point).and_raise("message")
7
+ allow(InfluxDB::Rails).to receive(:client).and_return(client)
8
+ end
9
+ end
10
+ end
11
+ end
@@ -1,5 +1,7 @@
1
1
  require "action_controller/railtie"
2
- require "active_record"
2
+ require "active_record/railtie"
3
+ require "active_job"
4
+ require "action_mailer"
3
5
 
4
6
  app = Class.new(Rails::Application)
5
7
  app.config.secret_key_base = "1234567890abcdef1234567890abcdef"
@@ -9,34 +11,71 @@ app.config.active_support.deprecation = :log
9
11
  app.config.eager_load = false
10
12
  app.config.root = __dir__
11
13
  Rails.backtrace_cleaner.remove_silencers!
14
+ ActiveJob::Base.logger = Rails.logger
15
+ ActionMailer::Base.delivery_method = :test
12
16
  app.initialize!
13
17
 
14
18
  app.routes.draw do
15
- resources :widgets
19
+ resources :metrics, only: %i[index show]
20
+ resources :exceptions, only: :index
16
21
  end
17
22
 
18
- InfluxDB::Rails.configure do |config|
19
- end
20
-
21
- ActiveRecord::Base.establish_connection(adapter: "sqlite3", database: ":memory:")
23
+ ENV["DATABASE_URL"] = "sqlite3::memory:"
22
24
  ActiveRecord::Schema.define do
23
- create_table :widgets, force: true do |t|
24
- t.string :title
25
+ create_table :metrics, force: true do |t|
26
+ t.string :name
25
27
 
26
28
  t.timestamps
27
29
  end
28
30
  end
29
31
 
30
- class Widget < ActiveRecord::Base; end
32
+ class MetricJob < ActiveJob::Base
33
+ queue_as :default
34
+
35
+ def perform
36
+ # Do something later
37
+ end
38
+ end
39
+
40
+ class MetricMailer < ActionMailer::Base
41
+ default from: "from@example.com"
42
+ layout "mailer"
43
+
44
+ def welcome_mail
45
+ mail(to: "eisendieter@werder.de", subject: "Welcome to metrics!") do |format|
46
+ format.text { render plain: "Hello Dieter!" }
47
+ end
48
+ end
49
+ end
50
+
51
+ class Metric < ActiveRecord::Base; end
52
+
31
53
  class ApplicationController < ActionController::Base; end
32
- class WidgetsController < ApplicationController
54
+
55
+ class MetricsController < ApplicationController
33
56
  prepend_view_path File.join(__dir__, "..", "views")
34
57
 
58
+ before_action do
59
+ InfluxDB::Rails.current.values = { additional_value: :value }
60
+ InfluxDB::Rails.current.tags = { additional_tag: :value }
61
+ end
62
+
35
63
  def index
36
- Widget.create!(title: "test")
64
+ InfluxDB::Rails.instrument "name", tags: { block_tag: :block_tag }, values: { block_value: :block_value } do
65
+ 1 + 1
66
+ end
67
+ MetricJob.perform_later
68
+ MetricMailer.with(user: "eisendieter").welcome_mail.deliver_now
69
+ Metric.create!(name: "name")
37
70
  end
38
71
 
39
- def new
72
+ def show
73
+ @metric = Metric.find_by(name: "name")
74
+ end
75
+ end
76
+
77
+ class ExceptionsController < ApplicationController
78
+ def index
40
79
  1 / 0
41
80
  end
42
81
  end
@@ -0,0 +1,83 @@
1
+ require "action_controller/railtie"
2
+ require "active_record/railtie"
3
+ require "active_job"
4
+ require "action_mailer"
5
+
6
+ app = Class.new(Rails::Application)
7
+ app.config.secret_key_base = "1234567890abcdef1234567890abcdef"
8
+ app.config.secret_token = "1234567890abcdef1234567890abcdef"
9
+ app.config.session_store :cookie_store, key: "_myapp_session"
10
+ app.config.active_support.deprecation = :log
11
+ app.config.eager_load = false
12
+ app.config.root = __dir__
13
+ Rails.backtrace_cleaner.remove_silencers!
14
+ ActiveJob::Base.logger = Rails.logger
15
+ ActionMailer::Base.delivery_method = :test
16
+ app.initialize!
17
+
18
+ app.routes.draw do
19
+ resources :metrics, only: %i[index show]
20
+ resources :exceptions, only: :index
21
+ end
22
+
23
+ ENV["DATABASE_URL"] = "sqlite3::memory:"
24
+ ActiveRecord::Schema.define do
25
+ create_table :metrics, force: true do |t|
26
+ t.string :name
27
+
28
+ t.timestamps
29
+ end
30
+ end
31
+
32
+ class MetricJob < ActiveJob::Base
33
+ queue_as :default
34
+
35
+ def perform
36
+ # Do something later
37
+ end
38
+ end
39
+
40
+ class MetricMailer < ActionMailer::Base
41
+ default from: "from@example.com"
42
+ layout "mailer"
43
+
44
+ def welcome_mail
45
+ mail(to: "eisendieter@werder.de", subject: "Welcome to metrics!") do |format|
46
+ format.text { render plain: "Hello Dieter!" }
47
+ end
48
+ end
49
+ end
50
+
51
+ class Metric < ActiveRecord::Base; end
52
+
53
+ class ApplicationController < ActionController::Base; end
54
+
55
+ class MetricsController < ApplicationController
56
+ prepend_view_path File.join(__dir__, "..", "views")
57
+
58
+ before_action do
59
+ InfluxDB::Rails.current.values = { additional_value: :value }
60
+ InfluxDB::Rails.current.tags = { additional_tag: :value }
61
+ end
62
+
63
+ def index
64
+ InfluxDB::Rails.instrument "name", tags: { block_tag: :block_tag }, values: { block_value: :block_value } do
65
+ 1 + 1
66
+ end
67
+ MetricJob.perform_later
68
+ MetricMailer.with(user: "eisendieter").welcome_mail.deliver_now
69
+ Metric.create!(name: "name")
70
+ end
71
+
72
+ def show
73
+ @metric = Metric.find_by(name: "name")
74
+ end
75
+ end
76
+
77
+ class ExceptionsController < ApplicationController
78
+ def index
79
+ 1 / 0
80
+ end
81
+ end
82
+
83
+ Object.const_set(:ApplicationHelper, Module.new)