influxdb-rails 1.0.0 → 1.0.1.beta1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (62) hide show
  1. checksums.yaml +4 -4
  2. data/.github/dependabot.yml +11 -0
  3. data/.gitignore +1 -0
  4. data/.rubocop.yml +1 -1
  5. data/.travis.yml +4 -7
  6. data/CHANGELOG.md +17 -0
  7. data/README.md +47 -5
  8. data/Rakefile +0 -6
  9. data/gemfiles/Gemfile.rails-5.0.x +2 -0
  10. data/gemfiles/Gemfile.rails-6.0.x +10 -0
  11. data/influxdb-rails.gemspec +5 -3
  12. data/lib/influxdb-rails.rb +11 -0
  13. data/lib/influxdb/rails/configuration.rb +8 -12
  14. data/lib/influxdb/rails/context.rb +6 -40
  15. data/lib/influxdb/rails/helpers/rspec_matchers.rb +48 -0
  16. data/lib/influxdb/rails/metric.rb +39 -0
  17. data/lib/influxdb/rails/middleware/active_job_subscriber.rb +67 -0
  18. data/lib/influxdb/rails/middleware/active_record_subscriber.rb +26 -0
  19. data/lib/influxdb/rails/middleware/block_instrumentation_subscriber.rb +24 -0
  20. data/lib/influxdb/rails/middleware/render_subscriber.rb +15 -16
  21. data/lib/influxdb/rails/middleware/request_subscriber.rb +16 -21
  22. data/lib/influxdb/rails/middleware/sql_subscriber.rb +18 -18
  23. data/lib/influxdb/rails/middleware/subscriber.rb +40 -27
  24. data/lib/influxdb/rails/railtie.rb +15 -18
  25. data/lib/influxdb/rails/tags.rb +33 -0
  26. data/lib/influxdb/rails/test_client.rb +13 -0
  27. data/lib/influxdb/rails/values.rb +24 -0
  28. data/lib/influxdb/rails/version.rb +1 -1
  29. data/sample-dashboard/README.md +1 -1
  30. data/spec/requests/action_controller_metrics_spec.rb +83 -0
  31. data/spec/requests/action_view_collection_metrics_spec.rb +66 -0
  32. data/spec/requests/action_view_partial_metrics_spec.rb +62 -0
  33. data/spec/requests/action_view_template_metrics_spec.rb +62 -0
  34. data/spec/requests/active_job_enqueue_metrics_spec.rb +65 -0
  35. data/spec/requests/active_job_perform_metrics_spec.rb +68 -0
  36. data/spec/requests/active_job_perform_start_metrics_spec.rb +68 -0
  37. data/spec/requests/active_record_instantiation_metrics_spec.rb +65 -0
  38. data/spec/requests/active_record_sql_metrics_spec.rb +103 -0
  39. data/spec/requests/block_inistrumentation_spec.rb +64 -0
  40. data/spec/requests/context_spec.rb +27 -0
  41. data/spec/requests/logger_spec.rb +10 -0
  42. data/spec/spec_helper.rb +10 -4
  43. data/spec/support/broken_client.rb +11 -0
  44. data/spec/support/rails5/app.rb +32 -10
  45. data/spec/support/rails6/app.rb +70 -0
  46. data/spec/support/views/{widgets → metrics}/_item.html.erb +0 -0
  47. data/spec/support/views/{widgets → metrics}/index.html.erb +0 -0
  48. data/spec/support/views/metrics/show.html.erb +4 -0
  49. data/spec/unit/block_instrumentation_spec.rb +18 -0
  50. metadata +87 -37
  51. data/gemfiles/Gemfile.rails-4.2.x +0 -7
  52. data/lib/influxdb/rails/instrumentation.rb +0 -34
  53. data/lib/influxdb/rails/middleware/simple_subscriber.rb +0 -33
  54. data/spec/controllers/widgets_controller_spec.rb +0 -15
  55. data/spec/integration/integration_helper.rb +0 -1
  56. data/spec/integration/metrics_spec.rb +0 -27
  57. data/spec/shared_examples/data.rb +0 -61
  58. data/spec/support/rails4/app.rb +0 -48
  59. data/spec/unit/context_spec.rb +0 -40
  60. data/spec/unit/middleware/render_subscriber_spec.rb +0 -96
  61. data/spec/unit/middleware/request_subscriber_spec.rb +0 -103
  62. data/spec/unit/middleware/sql_subscriber_spec.rb +0 -108
@@ -0,0 +1,68 @@
1
+ require File.dirname(__FILE__) + "/../spec_helper"
2
+
3
+ RSpec.describe "ActiveJob start 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(InfluxDB::Rails::Configuration).to receive(:ignored_environments).and_return(%w[development])
11
+ allow_any_instance_of(ActionDispatch::Request).to receive(:request_id).and_return(:request_id)
12
+ allow_any_instance_of(InfluxDB::Rails::Configuration).to receive(:application_name).and_return(:app_name)
13
+ allow_any_instance_of(InfluxDB::Rails::Configuration).to receive(:tags_middleware).and_return(tags_middleware)
14
+ end
15
+
16
+ it "writes metric" do
17
+ perform_enqueued_jobs do
18
+ get "/metrics"
19
+ end
20
+
21
+ expect_metric(
22
+ tags: a_hash_including(
23
+ location: "MetricsController#index",
24
+ hook: "perform_start",
25
+ state: "running",
26
+ job: "MetricJob",
27
+ queue: "default",
28
+ server: Socket.gethostname,
29
+ app_name: :app_name,
30
+ tags_middleware: :tags_middleware
31
+ ),
32
+ values: a_hash_including(
33
+ value: 1
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
+ perform_enqueued_jobs do
42
+ get "/metrics"
43
+ end
44
+
45
+ expect_metric(
46
+ tags: a_hash_including(
47
+ location: "MetricsController#index",
48
+ hook: "perform_start"
49
+ ),
50
+ timestamp: 1_514_797_200
51
+ )
52
+ end
53
+
54
+ it "does not write metric when hook is ignored" do
55
+ allow_any_instance_of(InfluxDB::Rails::Configuration).to receive(:ignored_hooks).and_return(["perform_start.active_job"])
56
+
57
+ perform_enqueued_jobs do
58
+ get "/metrics"
59
+ end
60
+
61
+ expect_no_metric(
62
+ tags: a_hash_including(
63
+ location: "MetricsController#index",
64
+ hook: "perform_start"
65
+ )
66
+ )
67
+ end
68
+ end
@@ -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, 30),
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, 30),
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, 30),
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, 30)
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"
@@ -25,9 +29,11 @@ RSpec.configure do |config|
25
29
  # use expect syntax
26
30
  config.disable_monkey_patching!
27
31
 
28
- # reset configuration for each spec
29
- config.before :each do
30
- InfluxDB::Rails.instance_variable_set :@configuration, nil
31
- InfluxDB::Rails.configure
32
+ config.after(:each) do
33
+ travel_back
32
34
  end
35
+
36
+ config.include ActiveSupport::Testing::TimeHelpers
37
+ config.include ActiveJob::TestHelper
38
+ config.include InfluxDB::Rails::BrokenClient
33
39
  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,6 @@
1
1
  require "action_controller/railtie"
2
- require "active_record"
2
+ require "active_record/railtie"
3
+ require "active_job"
3
4
 
4
5
  app = Class.new(Rails::Application)
5
6
  app.config.secret_key_base = "1234567890abcdef1234567890abcdef"
@@ -9,38 +10,59 @@ app.config.active_support.deprecation = :log
9
10
  app.config.eager_load = false
10
11
  app.config.root = __dir__
11
12
  Rails.backtrace_cleaner.remove_silencers!
13
+ ActiveJob::Base.logger = Rails.logger
12
14
  app.initialize!
13
15
 
14
16
  app.routes.draw do
15
- resources :widgets
17
+ resources :metrics, only: %i[index show]
18
+ resources :exceptions, only: :index
16
19
  end
17
20
 
18
21
  InfluxDB::Rails.configure do |config|
19
22
  end
20
23
 
21
- ActiveRecord::Base.establish_connection(adapter: "sqlite3", database: ":memory:")
24
+ ENV["DATABASE_URL"] = "sqlite3::memory:"
22
25
  ActiveRecord::Schema.define do
23
- create_table :widgets, force: true do |t|
24
- t.string :title
26
+ create_table :metrics, force: true do |t|
27
+ t.string :name
25
28
 
26
29
  t.timestamps
27
30
  end
28
31
  end
29
32
 
30
- class Widget < ActiveRecord::Base; end
33
+ class MetricJob < ActiveJob::Base
34
+ queue_as :default
35
+
36
+ def perform
37
+ # Do something later
38
+ end
39
+ end
40
+
41
+ class Metric < ActiveRecord::Base; end
31
42
  class ApplicationController < ActionController::Base; end
32
- class WidgetsController < ApplicationController
43
+ class MetricsController < ApplicationController
33
44
  prepend_view_path File.join(__dir__, "..", "views")
34
45
 
35
46
  before_action do
36
- InfluxDB::Rails.current.values = { key: :value }
47
+ InfluxDB::Rails.current.values = { additional_value: :value }
48
+ InfluxDB::Rails.current.tags = { additional_tag: :value }
37
49
  end
38
50
 
39
51
  def index
40
- Widget.create!(title: "test")
52
+ InfluxDB::Rails.instrument "name", tags: { block_tag: :block_tag }, values: { block_value: :block_value } do
53
+ 1 + 1
54
+ end
55
+ MetricJob.perform_later
56
+ Metric.create!(name: "name")
41
57
  end
42
58
 
43
- def new
59
+ def show
60
+ @metric = Metric.find_by(name: "name")
61
+ end
62
+ end
63
+
64
+ class ExceptionsController < ApplicationController
65
+ def index
44
66
  1 / 0
45
67
  end
46
68
  end