experimental-influxdb-rails 1.0.0.beta5

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 (60) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +10 -0
  3. data/.rspec +3 -0
  4. data/.rubocop.yml +78 -0
  5. data/.travis.yml +37 -0
  6. data/CHANGELOG.md +133 -0
  7. data/Gemfile +9 -0
  8. data/LICENSE.txt +22 -0
  9. data/README.md +292 -0
  10. data/Rakefile +34 -0
  11. data/config.ru +7 -0
  12. data/experimental-influxdb-rails.gemspec +35 -0
  13. data/gemfiles/Gemfile.rails-4.2.x +7 -0
  14. data/gemfiles/Gemfile.rails-5.0.x +7 -0
  15. data/gemfiles/Gemfile.rails-5.1.x +7 -0
  16. data/gemfiles/Gemfile.rails-5.2.x +7 -0
  17. data/lib/experimental-influxdb-rails.rb +123 -0
  18. data/lib/influxdb/rails/air_traffic_controller.rb +41 -0
  19. data/lib/influxdb/rails/backtrace.rb +44 -0
  20. data/lib/influxdb/rails/configuration.rb +211 -0
  21. data/lib/influxdb/rails/context.rb +51 -0
  22. data/lib/influxdb/rails/exception_presenter.rb +94 -0
  23. data/lib/influxdb/rails/instrumentation.rb +34 -0
  24. data/lib/influxdb/rails/logger.rb +16 -0
  25. data/lib/influxdb/rails/middleware/hijack_render_exception.rb +16 -0
  26. data/lib/influxdb/rails/middleware/hijack_rescue_action_everywhere.rb +31 -0
  27. data/lib/influxdb/rails/middleware/render_subscriber.rb +26 -0
  28. data/lib/influxdb/rails/middleware/request_subscriber.rb +59 -0
  29. data/lib/influxdb/rails/middleware/simple_subscriber.rb +49 -0
  30. data/lib/influxdb/rails/middleware/sql_subscriber.rb +38 -0
  31. data/lib/influxdb/rails/middleware/subscriber.rb +48 -0
  32. data/lib/influxdb/rails/rack.rb +24 -0
  33. data/lib/influxdb/rails/railtie.rb +51 -0
  34. data/lib/influxdb/rails/sql/normalizer.rb +27 -0
  35. data/lib/influxdb/rails/sql/query.rb +32 -0
  36. data/lib/influxdb/rails/version.rb +5 -0
  37. data/lib/rails/generators/influxdb/influxdb_generator.rb +15 -0
  38. data/lib/rails/generators/influxdb/templates/initializer.rb +11 -0
  39. data/spec/controllers/widgets_controller_spec.rb +15 -0
  40. data/spec/integration/exceptions_spec.rb +37 -0
  41. data/spec/integration/integration_helper.rb +1 -0
  42. data/spec/integration/metrics_spec.rb +28 -0
  43. data/spec/shared_examples/data.rb +67 -0
  44. data/spec/shared_examples/tags.rb +45 -0
  45. data/spec/spec_helper.rb +31 -0
  46. data/spec/support/rails4/app.rb +44 -0
  47. data/spec/support/rails5/app.rb +44 -0
  48. data/spec/support/views/widgets/_item.html.erb +1 -0
  49. data/spec/support/views/widgets/index.html.erb +5 -0
  50. data/spec/unit/backtrace_spec.rb +85 -0
  51. data/spec/unit/configuration_spec.rb +125 -0
  52. data/spec/unit/context_spec.rb +40 -0
  53. data/spec/unit/exception_presenter_spec.rb +23 -0
  54. data/spec/unit/influxdb_rails_spec.rb +78 -0
  55. data/spec/unit/middleware/render_subscriber_spec.rb +92 -0
  56. data/spec/unit/middleware/request_subscriber_spec.rb +94 -0
  57. data/spec/unit/middleware/sql_subscriber_spec.rb +95 -0
  58. data/spec/unit/sql/normalizer_spec.rb +15 -0
  59. data/spec/unit/sql/query_spec.rb +29 -0
  60. metadata +300 -0
@@ -0,0 +1,44 @@
1
+ require "action_controller/railtie"
2
+ require "active_record"
3
+
4
+ app = Class.new(Rails::Application)
5
+ app.config.secret_key_base = "1234567890abcdef1234567890abcdef"
6
+ app.config.secret_token = "1234567890abcdef1234567890abcdef"
7
+ app.config.session_store :cookie_store, key: "_myapp_session"
8
+ app.config.active_support.deprecation = :log
9
+ app.config.eager_load = false
10
+ app.config.root = __dir__
11
+ Rails.backtrace_cleaner.remove_silencers!
12
+ app.initialize!
13
+
14
+ app.routes.draw do
15
+ resources :widgets
16
+ end
17
+
18
+ InfluxDB::Rails.configure do |config|
19
+ end
20
+
21
+ ActiveRecord::Base.establish_connection(adapter: "sqlite3", database: ":memory:")
22
+ ActiveRecord::Schema.define do
23
+ create_table :widgets, force: true do |t|
24
+ t.string :title
25
+
26
+ t.timestamps
27
+ end
28
+ end
29
+
30
+ class Widget < ActiveRecord::Base; end
31
+ class ApplicationController < ActionController::Base; end
32
+ class WidgetsController < ApplicationController
33
+ prepend_view_path File.join(__dir__, "..", "views")
34
+
35
+ def index
36
+ Widget.create!(title: "test")
37
+ end
38
+
39
+ def new
40
+ 1 / 0
41
+ end
42
+ end
43
+
44
+ Object.const_set(:ApplicationHelper, Module.new)
@@ -0,0 +1 @@
1
+ <div>item</div
@@ -0,0 +1,5 @@
1
+ <h1>Index page</h1>
2
+ <div>
3
+ <%= render partial: 'item' %>
4
+ <%= render partial: 'item', collection: [1,2,3] %>
5
+ </div>
@@ -0,0 +1,85 @@
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
@@ -0,0 +1,125 @@
1
+ require "spec_helper"
2
+
3
+ RSpec.describe InfluxDB::Rails::Configuration do
4
+ before do
5
+ @configuration = InfluxDB::Rails::Configuration.new
6
+ end
7
+
8
+ describe "#ignore_user_agent?" do
9
+ it "should be true for user agents that have been set as ignorable" do
10
+ @configuration.ignored_user_agents = %w[Googlebot]
11
+ expect(@configuration.ignore_user_agent?("Googlebot/2.1")).to be_truthy
12
+ end
13
+
14
+ it "should be false for user agents that have not been set as ignorable" do
15
+ @configuration.ignored_user_agents = %w[Googlebot]
16
+ expect(@configuration.ignore_user_agent?("Mozilla/5.0")).to be_falsey
17
+ end
18
+
19
+ it "should be false if the ignored user agents list is empty" do
20
+ @configuration.ignored_user_agents = []
21
+ expect(@configuration.ignore_user_agent?("Googlebot/2.1")).to be_falsey
22
+ end
23
+
24
+ it "should be false if the ignored user agents list is inadvertently set to nil" do
25
+ @configuration.ignored_user_agents = nil
26
+ expect(@configuration.ignore_user_agent?("Googlebot/2.1")).to be_falsey
27
+ end
28
+ end
29
+
30
+ describe "#retry" do
31
+ it "defaults to nil" do
32
+ expect(InfluxDB::Rails.configuration.retry).to be_nil
33
+ end
34
+
35
+ it "can be updated" do
36
+ InfluxDB::Rails.configure do |config|
37
+ config.retry = 5
38
+ end
39
+ expect(InfluxDB::Rails.configuration.retry).to eql(5)
40
+ end
41
+ end
42
+
43
+ describe "#open_timeout" do
44
+ it "defaults to 5" do
45
+ expect(InfluxDB::Rails.configuration.open_timeout).to eql(5)
46
+ end
47
+
48
+ it "can be updated" do
49
+ InfluxDB::Rails.configure do |config|
50
+ config.open_timeout = 5
51
+ end
52
+ expect(InfluxDB::Rails.configuration.open_timeout).to eql(5)
53
+ end
54
+ end
55
+
56
+ describe "#read_timeout" do
57
+ it "defaults to 300" do
58
+ expect(InfluxDB::Rails.configuration.read_timeout).to eql(300)
59
+ end
60
+
61
+ it "can be updated" do
62
+ InfluxDB::Rails.configure do |config|
63
+ config.read_timeout = 5
64
+ end
65
+ expect(InfluxDB::Rails.configuration.read_timeout).to eql(5)
66
+ end
67
+ end
68
+
69
+ describe "#max_delay" do
70
+ it "defaults to 30" do
71
+ expect(InfluxDB::Rails.configuration.max_delay).to eql(30)
72
+ end
73
+
74
+ it "can be updated" do
75
+ InfluxDB::Rails.configure do |config|
76
+ config.max_delay = 5
77
+ end
78
+ expect(InfluxDB::Rails.configuration.max_delay).to eql(5)
79
+ end
80
+ end
81
+
82
+ describe "#time_precision" do
83
+ it "defaults to seconds" do
84
+ expect(InfluxDB::Rails.configuration.time_precision).to eql("s")
85
+ end
86
+
87
+ it "can be updated" do
88
+ InfluxDB::Rails.configure do |config|
89
+ config.time_precision = "ms"
90
+ end
91
+ expect(InfluxDB::Rails.configuration.time_precision).to eql("ms")
92
+ end
93
+ end
94
+
95
+ describe "#rails_app_name" do
96
+ it "defaults to nil" do
97
+ expect(InfluxDB::Rails.configuration.rails_app_name).to be(nil)
98
+ end
99
+
100
+ it "can be set to own name" do
101
+ InfluxDB::Rails.configure do |config|
102
+ config.rails_app_name = "my-app"
103
+ end
104
+
105
+ expect(InfluxDB::Rails.configuration.rails_app_name).to eq("my-app")
106
+ end
107
+ end
108
+
109
+ describe "#tags_middleware" do
110
+ let(:middleware) { InfluxDB::Rails.configuration.tags_middleware }
111
+ let(:tags_example) { { a: 1, b: 2 } }
112
+
113
+ it "by default returns unmodified tags" do
114
+ expect(middleware.call(tags_example)).to eq tags_example
115
+ end
116
+
117
+ it "can be updated" do
118
+ InfluxDB::Rails.configure do |config|
119
+ config.tags_middleware = ->(tags) { tags.merge(c: 3) }
120
+ end
121
+
122
+ expect(middleware.call(tags_example)).to eq(tags_example.merge(c: 3))
123
+ end
124
+ end
125
+ end
@@ -0,0 +1,40 @@
1
+ require "spec_helper"
2
+
3
+ RSpec.describe InfluxDB::Rails::Context do
4
+ subject { described_class.new }
5
+
6
+ describe "#controller" do
7
+ it "does set and get" do
8
+ subject.controller = "Controller"
9
+ expect(subject.controller).to eq("Controller")
10
+ end
11
+ end
12
+
13
+ describe "#action" do
14
+ it "does get and set" do
15
+ subject.action = "action"
16
+ expect(subject.action).to eq("action")
17
+ end
18
+ end
19
+
20
+ describe "#location" do
21
+ before do
22
+ subject.controller = "Controller"
23
+ subject.action = "action"
24
+ end
25
+
26
+ it { expect(subject.location).to eq("Controller#action") }
27
+ end
28
+
29
+ describe "#reset" do
30
+ before do
31
+ subject.controller = "Controller"
32
+ subject.action = "action"
33
+ end
34
+
35
+ it "does reset the location" do
36
+ subject.reset
37
+ expect(subject.location).to be_empty
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,23 @@
1
+ require "spec_helper"
2
+
3
+ RSpec.describe InfluxDB::Rails::ExceptionPresenter do
4
+ before do
5
+ begin
6
+ 1 / 0
7
+ rescue ZeroDivisionError => e
8
+ @exception = e
9
+ end
10
+ end
11
+
12
+ describe ".new" do
13
+ it "should create a new ExceptionPresenter" do
14
+ exception_presenter = InfluxDB::Rails::ExceptionPresenter.new(@exception)
15
+ expect(exception_presenter).to be_a(InfluxDB::Rails::ExceptionPresenter)
16
+ end
17
+
18
+ it "should accept an exception as a parameter" do
19
+ exception_presenter = InfluxDB::Rails::ExceptionPresenter.new(@exception)
20
+ expect(exception_presenter).not_to be_nil
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,78 @@
1
+ require "spec_helper"
2
+
3
+ RSpec.describe InfluxDB::Rails do
4
+ before do
5
+ InfluxDB::Rails.configure do |config|
6
+ config.application_name = "my-rails-app"
7
+ config.ignored_environments = []
8
+ config.time_precision = "ms"
9
+ end
10
+ end
11
+
12
+ describe ".current_timestamp" do
13
+ let(:timestamp) { 1_513_009_229_111 }
14
+
15
+ it "should return the current timestamp in the configured precision" do
16
+ expect(Process).to receive(:clock_gettime)
17
+ .with(Process::CLOCK_REALTIME, :millisecond)
18
+ .and_return(timestamp)
19
+
20
+ expect(InfluxDB::Rails.current_timestamp).to eq(timestamp)
21
+ end
22
+ end
23
+
24
+ describe ".ignorable_exception?" do
25
+ it "should be true for exception types specified in the configuration" do
26
+ class DummyException < RuntimeError; end
27
+ exception = DummyException.new
28
+
29
+ InfluxDB::Rails.configure do |config|
30
+ config.ignored_exceptions << "DummyException"
31
+ end
32
+
33
+ expect(InfluxDB::Rails.ignorable_exception?(exception)).to be_truthy
34
+ end
35
+
36
+ it "should be true for exception types specified in the configuration" do
37
+ exception = ActionController::RoutingError.new("foo")
38
+ expect(InfluxDB::Rails.ignorable_exception?(exception)).to be_truthy
39
+ end
40
+
41
+ it "should be false for valid exceptions" do
42
+ exception = ZeroDivisionError.new
43
+ expect(InfluxDB::Rails.ignorable_exception?(exception)).to be_falsey
44
+ end
45
+ end
46
+
47
+ describe "rescue" do
48
+ it "should transmit an exception when passed" do
49
+ expect(InfluxDB::Rails.client).to receive(:write_point)
50
+
51
+ InfluxDB::Rails.rescue do
52
+ raise ArgumentError, "wrong"
53
+ end
54
+ end
55
+
56
+ it "should also raise the exception when in an ignored environment" do
57
+ InfluxDB::Rails.configure do |config|
58
+ config.ignored_environments = %w[development test]
59
+ end
60
+
61
+ expect do
62
+ InfluxDB::Rails.rescue do
63
+ raise ArgumentError, "wrong"
64
+ end
65
+ end.to raise_error(ArgumentError)
66
+ end
67
+ end
68
+
69
+ describe "rescue_and_reraise" do
70
+ it "should transmit an exception when passed" do
71
+ expect(InfluxDB::Rails.client).to receive(:write_point)
72
+
73
+ expect do
74
+ InfluxDB::Rails.rescue_and_reraise { raise ArgumentError, "wrong" }
75
+ end.to raise_error(ArgumentError)
76
+ end
77
+ end
78
+ end
@@ -0,0 +1,92 @@
1
+ require "spec_helper"
2
+ require "shared_examples/data"
3
+
4
+ RSpec.describe InfluxDB::Rails::Middleware::RenderSubscriber do
5
+ let(:config) { InfluxDB::Rails::Configuration.new }
6
+ let(:logger) { double(:logger) }
7
+
8
+ before do
9
+ allow(config).to receive(:application_name).and_return("my-rails-app")
10
+ allow(config).to receive(:ignored_environments).and_return([])
11
+ allow(config).to receive(:time_precision).and_return("ms")
12
+ end
13
+
14
+ describe ".call" do
15
+ let(:start) { Time.at(1_517_567_368) }
16
+ let(:finish) { Time.at(1_517_567_370) }
17
+ let(:series_name) { "series_name" }
18
+ let(:payload) { { identifier: "index.html", count: 43, cache_hits: 42 } }
19
+ let(:data) do
20
+ {
21
+ values: {
22
+ value: 2000,
23
+ count: 43,
24
+ cache_hits: 42
25
+ },
26
+ tags: {
27
+ filename: "index.html",
28
+ location: "Foo#bar",
29
+ },
30
+ timestamp: 1_517_567_370_000
31
+ }
32
+ end
33
+
34
+ subject { described_class.new(config, series_name) }
35
+
36
+ before do
37
+ InfluxDB::Rails.current.controller = "Foo"
38
+ InfluxDB::Rails.current.action = "bar"
39
+ end
40
+
41
+ after do
42
+ InfluxDB::Rails.current.reset
43
+ end
44
+
45
+ context "successfully" do
46
+ it "writes to InfluxDB" do
47
+ expect_any_instance_of(InfluxDB::Client).to receive(:write_point).with(
48
+ series_name, data
49
+ )
50
+ subject.call("name", start, finish, "id", payload)
51
+ end
52
+
53
+ it_behaves_like "with additional data", ["series_name"]
54
+
55
+ context "with an empty value" do
56
+ before do
57
+ payload[:count] = nil
58
+ data[:values].delete(:count)
59
+ end
60
+
61
+ it "does not write empty value" do
62
+ expect_any_instance_of(InfluxDB::Client).to receive(:write_point).with(
63
+ series_name, data
64
+ )
65
+ subject.call("name", start, finish, "id", payload)
66
+ end
67
+ end
68
+
69
+ context "disabled" do
70
+ subject { described_class.new(config, nil) }
71
+
72
+ it "does not write a data point" do
73
+ expect_any_instance_of(InfluxDB::Client).not_to receive(:write_point)
74
+ subject.call("name", start, finish, "id", payload)
75
+ end
76
+ end
77
+ end
78
+
79
+ context "unsuccessfully" do
80
+ before do
81
+ allow(config).to receive(:logger).and_return(logger)
82
+ InfluxDB::Rails.configuration = config
83
+ end
84
+
85
+ it "does log exceptions" do
86
+ allow_any_instance_of(InfluxDB::Client).to receive(:write_point).and_raise("boom")
87
+ expect(logger).to receive(:error).with(/boom/)
88
+ subject.call("name", start, finish, "id", payload)
89
+ end
90
+ end
91
+ end
92
+ end